From 33bad77043d3ec4b91bc302af69da8c7ba9dd204 Mon Sep 17 00:00:00 2001 From: Jim Eckerlein Date: Fri, 17 Jun 2022 18:38:41 +0200 Subject: Draco: update to version 1.5.2 Differential Revision: https://developer.blender.org/D15233 --- extern/draco/README.blender | 4 +- .../attributes/attribute_octahedron_transform.cc | 95 ++++-- .../attributes/attribute_octahedron_transform.h | 31 +- .../attributes/attribute_quantization_transform.cc | 113 ++++++-- .../attributes/attribute_quantization_transform.h | 38 ++- .../src/draco/attributes/attribute_transform.cc | 25 +- .../src/draco/attributes/attribute_transform.h | 36 ++- .../src/draco/attributes/geometry_attribute.cc | 12 +- .../src/draco/attributes/geometry_attribute.h | 42 +++ .../draco/src/draco/attributes/point_attribute.cc | 43 +++ .../draco/src/draco/attributes/point_attribute.h | 6 + .../compression/attributes/attributes_decoder.cc | 22 +- .../compression/attributes/attributes_encoder.cc | 16 +- .../attributes/kd_tree_attributes_decoder.cc | 19 +- .../attributes/kd_tree_attributes_encoder.cc | 15 +- .../attributes/kd_tree_attributes_encoder.h | 6 +- .../attributes/normal_compression_utils.h | 133 +++++---- .../mesh_prediction_scheme_data.h | 4 +- ...iction_scheme_geometric_normal_predictor_area.h | 9 +- .../mesh_prediction_scheme_parallelogram_shared.h | 9 +- ...ediction_scheme_tex_coords_portable_predictor.h | 7 + .../prediction_scheme_encoder_factory.cc | 33 ++- .../prediction_scheme_encoder_factory.h | 4 + .../prediction_scheme_encoder_interface.h | 6 +- .../prediction_scheme_wrap_decoding_transform.h | 18 +- .../prediction_scheme_wrap_transform_base.h | 2 +- .../sequential_attribute_encoders_controller.cc | 4 +- .../sequential_integer_attribute_decoder.cc | 15 +- .../sequential_integer_attribute_encoder.cc | 3 + .../sequential_normal_attribute_decoder.cc | 44 +-- .../sequential_normal_attribute_decoder.h | 3 +- .../sequential_normal_attribute_encoder.cc | 13 +- .../sequential_quantization_attribute_decoder.cc | 64 +--- .../sequential_quantization_attribute_decoder.h | 8 +- .../sequential_quantization_attribute_encoder.cc | 19 +- .../draco/compression/config/compression_shared.h | 3 + .../src/draco/compression/config/draco_options.h | 6 +- extern/draco/draco/src/draco/compression/decode.cc | 5 +- .../draco/src/draco/compression/encode_base.h | 8 +- .../draco/src/draco/compression/entropy/ans.h | 7 +- .../draco/compression/entropy/rans_symbol_coding.h | 9 +- .../compression/entropy/rans_symbol_encoder.h | 4 +- .../draco/compression/entropy/symbol_decoding.cc | 2 +- .../draco/src/draco/compression/expert_encode.cc | 2 +- .../draco/src/draco/compression/expert_encode.h | 6 +- .../mesh/mesh_edgebreaker_decoder_impl.cc | 31 +- .../compression/mesh/mesh_edgebreaker_encoder.cc | 1 - .../mesh/mesh_edgebreaker_encoder_impl.cc | 2 +- .../mesh/mesh_edgebreaker_encoder_impl.h | 1 - .../compression/mesh/mesh_edgebreaker_shared.h | 2 - .../mesh_edgebreaker_traversal_valence_decoder.h | 7 +- .../compression/mesh/mesh_sequential_decoder.cc | 7 +- .../compression/mesh/mesh_sequential_encoder.cc | 4 - .../compression/mesh/mesh_sequential_encoder.h | 1 - .../mesh_attribute_indices_encoding_observer.h | 2 +- .../mesh/traverser/mesh_traversal_sequencer.h | 2 +- .../dynamic_integer_points_kd_tree_decoder.h | 5 +- .../dynamic_integer_points_kd_tree_encoder.h | 5 +- .../algorithms/float_points_tree_decoder.cc | 27 +- .../algorithms/float_points_tree_encoder.h | 4 +- .../algorithms/integer_points_kd_tree_decoder.h | 3 +- .../algorithms/integer_points_kd_tree_encoder.h | 3 +- .../point_cloud/algorithms/quantize_points_3.h | 2 +- .../compression/point_cloud/point_cloud_decoder.cc | 10 + .../compression/point_cloud/point_cloud_encoder.cc | 14 +- extern/draco/draco/src/draco/core/bounding_box.cc | 13 +- extern/draco/draco/src/draco/core/bounding_box.h | 42 ++- extern/draco/draco/src/draco/core/cycle_timer.cc | 14 +- extern/draco/draco/src/draco/core/cycle_timer.h | 7 +- extern/draco/draco/src/draco/core/data_buffer.cc | 2 +- extern/draco/draco/src/draco/core/decoder_buffer.h | 12 +- .../draco/src/draco/core/draco_index_type_vector.h | 3 +- extern/draco/draco/src/draco/core/draco_version.h | 2 +- extern/draco/draco/src/draco/core/macros.h | 27 +- extern/draco/draco/src/draco/core/options.h | 2 - extern/draco/draco/src/draco/core/status.h | 4 + .../draco/draco/src/draco/core/varint_decoding.h | 1 + extern/draco/draco/src/draco/core/vector_d.h | 14 +- extern/draco/draco/src/draco/draco_features.h | 2 - extern/draco/draco/src/draco/mesh/corner_table.cc | 7 +- extern/draco/draco/src/draco/mesh/mesh.h | 4 + .../src/draco/mesh/mesh_attribute_corner_table.h | 6 + extern/draco/draco/src/draco/mesh/mesh_cleanup.cc | 321 ++++++++++++--------- extern/draco/draco/src/draco/mesh/mesh_cleanup.h | 27 +- .../draco/src/draco/mesh/mesh_misc_functions.h | 1 - .../draco/draco/src/draco/mesh/mesh_stripifier.h | 8 +- .../src/draco/mesh/triangle_soup_mesh_builder.cc | 2 - .../draco/src/draco/metadata/geometry_metadata.cc | 15 +- .../draco/src/draco/metadata/geometry_metadata.h | 2 + extern/draco/draco/src/draco/metadata/metadata.cc | 8 + extern/draco/draco/src/draco/metadata/metadata.h | 1 + .../draco/src/draco/metadata/metadata_decoder.cc | 10 +- .../draco/src/draco/point_cloud/point_cloud.cc | 16 +- extern/draco/patches/blender.patch | 30 ++ extern/draco/src/common.cpp | 28 +- extern/draco/src/common.h | 2 +- extern/draco/src/decoder.cpp | 74 ++--- extern/draco/src/decoder.h | 36 ++- extern/draco/src/encoder.cpp | 97 ++++--- extern/draco/src/encoder.h | 33 ++- 100 files changed, 1305 insertions(+), 674 deletions(-) create mode 100644 extern/draco/patches/blender.patch (limited to 'extern/draco') diff --git a/extern/draco/README.blender b/extern/draco/README.blender index b9c3bbb967d..a879ded978b 100644 --- a/extern/draco/README.blender +++ b/extern/draco/README.blender @@ -1,5 +1,5 @@ Project: Draco URL: https://google.github.io/draco/ License: Apache 2.0 -Upstream version: 1.3.6 -Local modifications: None +Upstream version: 1.5.2 +Local modifications: Apply patches/blender.patch diff --git a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc index 283a21251f4..51c3bb6c872 100644 --- a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc +++ b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.cc @@ -38,6 +38,46 @@ void AttributeOctahedronTransform::CopyToAttributeTransformData( out_data->AppendParameterValue(quantization_bits_); } +bool AttributeOctahedronTransform::TransformAttribute( + const PointAttribute &attribute, const std::vector &point_ids, + PointAttribute *target_attribute) { + return GeneratePortableAttribute(attribute, point_ids, + target_attribute->size(), target_attribute); +} + +bool AttributeOctahedronTransform::InverseTransformAttribute( + const PointAttribute &attribute, PointAttribute *target_attribute) { + if (target_attribute->data_type() != DT_FLOAT32) { + return false; + } + + const int num_points = target_attribute->size(); + const int num_components = target_attribute->num_components(); + if (num_components != 3) { + return false; + } + constexpr int kEntrySize = sizeof(float) * 3; + float att_val[3]; + const int32_t *source_attribute_data = reinterpret_cast( + attribute.GetAddress(AttributeValueIndex(0))); + uint8_t *target_address = + target_attribute->GetAddress(AttributeValueIndex(0)); + OctahedronToolBox octahedron_tool_box; + if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_)) { + return false; + } + for (uint32_t i = 0; i < num_points; ++i) { + const int32_t s = *source_attribute_data++; + const int32_t t = *source_attribute_data++; + octahedron_tool_box.QuantizedOctahedralCoordsToUnitVector(s, t, att_val); + + // Store the decoded floating point values into the attribute buffer. + std::memcpy(target_address, att_val, kEntrySize); + target_address += kEntrySize; + } + return true; +} + void AttributeOctahedronTransform::SetParameters(int quantization_bits) { quantization_bits_ = quantization_bits; } @@ -51,38 +91,55 @@ bool AttributeOctahedronTransform::EncodeParameters( return false; } -std::unique_ptr -AttributeOctahedronTransform::GeneratePortableAttribute( +bool AttributeOctahedronTransform::DecodeParameters( + const PointAttribute &attribute, DecoderBuffer *decoder_buffer) { + uint8_t quantization_bits; + if (!decoder_buffer->Decode(&quantization_bits)) { + return false; + } + quantization_bits_ = quantization_bits; + return true; +} + +bool AttributeOctahedronTransform::GeneratePortableAttribute( const PointAttribute &attribute, const std::vector &point_ids, - int num_points) const { + int num_points, PointAttribute *target_attribute) const { DRACO_DCHECK(is_initialized()); - // Allocate portable attribute. - const int num_entries = static_cast(point_ids.size()); - std::unique_ptr portable_attribute = - InitPortableAttribute(num_entries, 2, num_points, attribute, true); - // Quantize all values in the order given by point_ids into portable // attribute. int32_t *const portable_attribute_data = reinterpret_cast( - portable_attribute->GetAddress(AttributeValueIndex(0))); + target_attribute->GetAddress(AttributeValueIndex(0))); float att_val[3]; int32_t dst_index = 0; OctahedronToolBox converter; if (!converter.SetQuantizationBits(quantization_bits_)) { - return nullptr; + return false; } - for (uint32_t i = 0; i < point_ids.size(); ++i) { - const AttributeValueIndex att_val_id = attribute.mapped_index(point_ids[i]); - attribute.GetValue(att_val_id, att_val); - // Encode the vector into a s and t octahedral coordinates. - int32_t s, t; - converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t); - portable_attribute_data[dst_index++] = s; - portable_attribute_data[dst_index++] = t; + if (!point_ids.empty()) { + for (uint32_t i = 0; i < point_ids.size(); ++i) { + const AttributeValueIndex att_val_id = + attribute.mapped_index(point_ids[i]); + attribute.GetValue(att_val_id, att_val); + // Encode the vector into a s and t octahedral coordinates. + int32_t s, t; + converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t); + portable_attribute_data[dst_index++] = s; + portable_attribute_data[dst_index++] = t; + } + } else { + for (PointIndex i(0); i < num_points; ++i) { + const AttributeValueIndex att_val_id = attribute.mapped_index(i); + attribute.GetValue(att_val_id, att_val); + // Encode the vector into a s and t octahedral coordinates. + int32_t s, t; + converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t); + portable_attribute_data[dst_index++] = s; + portable_attribute_data[dst_index++] = t; + } } - return portable_attribute; + return true; } } // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h index 6e4e74284f0..21a1725bb52 100644 --- a/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h +++ b/extern/draco/draco/src/draco/attributes/attribute_octahedron_transform.h @@ -37,19 +37,40 @@ class AttributeOctahedronTransform : public AttributeTransform { void CopyToAttributeTransformData( AttributeTransformData *out_data) const override; + bool TransformAttribute(const PointAttribute &attribute, + const std::vector &point_ids, + PointAttribute *target_attribute) override; + + bool InverseTransformAttribute(const PointAttribute &attribute, + PointAttribute *target_attribute) override; + // Set number of quantization bits. void SetParameters(int quantization_bits); // Encode relevant parameters into buffer. - bool EncodeParameters(EncoderBuffer *encoder_buffer) const; + bool EncodeParameters(EncoderBuffer *encoder_buffer) const override; + + bool DecodeParameters(const PointAttribute &attribute, + DecoderBuffer *decoder_buffer) override; bool is_initialized() const { return quantization_bits_ != -1; } int32_t quantization_bits() const { return quantization_bits_; } - // Create portable attribute. - std::unique_ptr GeneratePortableAttribute( - const PointAttribute &attribute, const std::vector &point_ids, - int num_points) const; + protected: + DataType GetTransformedDataType( + const PointAttribute &attribute) const override { + return DT_UINT32; + } + int GetTransformedNumComponents( + const PointAttribute &attribute) const override { + return 2; + } + + // Perform the actual transformation. + bool GeneratePortableAttribute(const PointAttribute &attribute, + const std::vector &point_ids, + int num_points, + PointAttribute *target_attribute) const; private: int32_t quantization_bits_; diff --git a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc index daa634ed03f..a7f93a488d7 100644 --- a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc +++ b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.cc @@ -1,4 +1,3 @@ - // Copyright 2017 The Draco Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -51,13 +50,74 @@ void AttributeQuantizationTransform::CopyToAttributeTransformData( out_data->AppendParameterValue(range_); } -void AttributeQuantizationTransform::SetParameters(int quantization_bits, +bool AttributeQuantizationTransform::TransformAttribute( + const PointAttribute &attribute, const std::vector &point_ids, + PointAttribute *target_attribute) { + if (point_ids.empty()) { + GeneratePortableAttribute(attribute, target_attribute->size(), + target_attribute); + } else { + GeneratePortableAttribute(attribute, point_ids, target_attribute->size(), + target_attribute); + } + return true; +} + +bool AttributeQuantizationTransform::InverseTransformAttribute( + const PointAttribute &attribute, PointAttribute *target_attribute) { + if (target_attribute->data_type() != DT_FLOAT32) { + return false; + } + + // Convert all quantized values back to floats. + const int32_t max_quantized_value = + (1u << static_cast(quantization_bits_)) - 1; + const int num_components = target_attribute->num_components(); + const int entry_size = sizeof(float) * num_components; + const std::unique_ptr att_val(new float[num_components]); + int quant_val_id = 0; + int out_byte_pos = 0; + Dequantizer dequantizer; + if (!dequantizer.Init(range_, max_quantized_value)) { + return false; + } + const int32_t *const source_attribute_data = + reinterpret_cast( + attribute.GetAddress(AttributeValueIndex(0))); + + const int num_values = target_attribute->size(); + + for (uint32_t i = 0; i < num_values; ++i) { + for (int c = 0; c < num_components; ++c) { + float value = + dequantizer.DequantizeFloat(source_attribute_data[quant_val_id++]); + value = value + min_values_[c]; + att_val[c] = value; + } + // Store the floating point value into the attribute buffer. + target_attribute->buffer()->Write(out_byte_pos, att_val.get(), entry_size); + out_byte_pos += entry_size; + } + return true; +} + +bool AttributeQuantizationTransform::IsQuantizationValid( + int quantization_bits) { + // Currently we allow only up to 30 bit quantization. + return quantization_bits >= 1 && quantization_bits <= 30; +} + +bool AttributeQuantizationTransform::SetParameters(int quantization_bits, const float *min_values, int num_components, float range) { + if (!IsQuantizationValid(quantization_bits)) { + return false; + } quantization_bits_ = quantization_bits; min_values_.assign(min_values, min_values + num_components); range_ = range; + return true; } bool AttributeQuantizationTransform::ComputeParameters( @@ -65,6 +125,9 @@ bool AttributeQuantizationTransform::ComputeParameters( if (quantization_bits_ != -1) { return false; // already initialized. } + if (!IsQuantizationValid(quantization_bits)) { + return false; + } quantization_bits_ = quantization_bits; const int num_components = attribute.num_components(); @@ -121,20 +184,37 @@ bool AttributeQuantizationTransform::EncodeParameters( return false; } -std::unique_ptr -AttributeQuantizationTransform::GeneratePortableAttribute( - const PointAttribute &attribute, int num_points) const { +bool AttributeQuantizationTransform::DecodeParameters( + const PointAttribute &attribute, DecoderBuffer *decoder_buffer) { + min_values_.resize(attribute.num_components()); + if (!decoder_buffer->Decode(&min_values_[0], + sizeof(float) * min_values_.size())) { + return false; + } + if (!decoder_buffer->Decode(&range_)) { + return false; + } + uint8_t quantization_bits; + if (!decoder_buffer->Decode(&quantization_bits)) { + return false; + } + if (!IsQuantizationValid(quantization_bits)) { + return false; + } + quantization_bits_ = quantization_bits; + return true; +} + +void AttributeQuantizationTransform::GeneratePortableAttribute( + const PointAttribute &attribute, int num_points, + PointAttribute *target_attribute) const { DRACO_DCHECK(is_initialized()); - // Allocate portable attribute. - const int num_entries = num_points; const int num_components = attribute.num_components(); - std::unique_ptr portable_attribute = - InitPortableAttribute(num_entries, num_components, 0, attribute, true); // Quantize all values using the order given by point_ids. int32_t *const portable_attribute_data = reinterpret_cast( - portable_attribute->GetAddress(AttributeValueIndex(0))); + target_attribute->GetAddress(AttributeValueIndex(0))); const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1; Quantizer quantizer; quantizer.Init(range(), max_quantized_value); @@ -149,24 +229,18 @@ AttributeQuantizationTransform::GeneratePortableAttribute( portable_attribute_data[dst_index++] = q_val; } } - return portable_attribute; } -std::unique_ptr -AttributeQuantizationTransform::GeneratePortableAttribute( +void AttributeQuantizationTransform::GeneratePortableAttribute( const PointAttribute &attribute, const std::vector &point_ids, - int num_points) const { + int num_points, PointAttribute *target_attribute) const { DRACO_DCHECK(is_initialized()); - // Allocate portable attribute. - const int num_entries = static_cast(point_ids.size()); const int num_components = attribute.num_components(); - std::unique_ptr portable_attribute = InitPortableAttribute( - num_entries, num_components, num_points, attribute, true); // Quantize all values using the order given by point_ids. int32_t *const portable_attribute_data = reinterpret_cast( - portable_attribute->GetAddress(AttributeValueIndex(0))); + target_attribute->GetAddress(AttributeValueIndex(0))); const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1; Quantizer quantizer; quantizer.Init(range(), max_quantized_value); @@ -181,7 +255,6 @@ AttributeQuantizationTransform::GeneratePortableAttribute( portable_attribute_data[dst_index++] = q_val; } } - return portable_attribute; } } // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h index 934856f2db7..f1122b680ab 100644 --- a/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h +++ b/extern/draco/draco/src/draco/attributes/attribute_quantization_transform.h @@ -37,14 +37,24 @@ class AttributeQuantizationTransform : public AttributeTransform { void CopyToAttributeTransformData( AttributeTransformData *out_data) const override; - void SetParameters(int quantization_bits, const float *min_values, + bool TransformAttribute(const PointAttribute &attribute, + const std::vector &point_ids, + PointAttribute *target_attribute) override; + + bool InverseTransformAttribute(const PointAttribute &attribute, + PointAttribute *target_attribute) override; + + bool SetParameters(int quantization_bits, const float *min_values, int num_components, float range); bool ComputeParameters(const PointAttribute &attribute, const int quantization_bits); // Encode relevant parameters into buffer. - bool EncodeParameters(EncoderBuffer *encoder_buffer) const; + bool EncodeParameters(EncoderBuffer *encoder_buffer) const override; + + bool DecodeParameters(const PointAttribute &attribute, + DecoderBuffer *decoder_buffer) override; int32_t quantization_bits() const { return quantization_bits_; } float min_value(int axis) const { return min_values_[axis]; } @@ -52,16 +62,30 @@ class AttributeQuantizationTransform : public AttributeTransform { float range() const { return range_; } bool is_initialized() const { return quantization_bits_ != -1; } + protected: // Create portable attribute using 1:1 mapping between points in the input and // output attribute. - std::unique_ptr GeneratePortableAttribute( - const PointAttribute &attribute, int num_points) const; + void GeneratePortableAttribute(const PointAttribute &attribute, + int num_points, + PointAttribute *target_attribute) const; // Create portable attribute using custom mapping between input and output // points. - std::unique_ptr GeneratePortableAttribute( - const PointAttribute &attribute, const std::vector &point_ids, - int num_points) const; + void GeneratePortableAttribute(const PointAttribute &attribute, + const std::vector &point_ids, + int num_points, + PointAttribute *target_attribute) const; + + DataType GetTransformedDataType( + const PointAttribute &attribute) const override { + return DT_UINT32; + } + int GetTransformedNumComponents( + const PointAttribute &attribute) const override { + return attribute.num_components(); + } + + static bool IsQuantizationValid(int quantization_bits); private: int32_t quantization_bits_; diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform.cc b/extern/draco/draco/src/draco/attributes/attribute_transform.cc index 55af630ac07..fb2ed18297a 100644 --- a/extern/draco/draco/src/draco/attributes/attribute_transform.cc +++ b/extern/draco/draco/src/draco/attributes/attribute_transform.cc @@ -24,21 +24,18 @@ bool AttributeTransform::TransferToAttribute(PointAttribute *attribute) const { return true; } -std::unique_ptr AttributeTransform::InitPortableAttribute( - int num_entries, int num_components, int num_points, - const PointAttribute &attribute, bool is_unsigned) const { - const DataType dt = is_unsigned ? DT_UINT32 : DT_INT32; - GeometryAttribute va; - va.Init(attribute.attribute_type(), nullptr, num_components, dt, false, +std::unique_ptr AttributeTransform::InitTransformedAttribute( + const PointAttribute &src_attribute, int num_entries) { + const int num_components = GetTransformedNumComponents(src_attribute); + const DataType dt = GetTransformedDataType(src_attribute); + GeometryAttribute ga; + ga.Init(src_attribute.attribute_type(), nullptr, num_components, dt, false, num_components * DataTypeLength(dt), 0); - std::unique_ptr portable_attribute(new PointAttribute(va)); - portable_attribute->Reset(num_entries); - if (num_points) { - portable_attribute->SetExplicitMapping(num_points); - } else { - portable_attribute->SetIdentityMapping(); - } - return portable_attribute; + std::unique_ptr transformed_attribute(new PointAttribute(ga)); + transformed_attribute->Reset(num_entries); + transformed_attribute->SetIdentityMapping(); + transformed_attribute->set_unique_id(src_attribute.unique_id()); + return transformed_attribute; } } // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/attribute_transform.h b/extern/draco/draco/src/draco/attributes/attribute_transform.h index d746fbf6eea..62aad60db91 100644 --- a/extern/draco/draco/src/draco/attributes/attribute_transform.h +++ b/extern/draco/draco/src/draco/attributes/attribute_transform.h @@ -17,6 +17,8 @@ #include "draco/attributes/attribute_transform_data.h" #include "draco/attributes/point_attribute.h" +#include "draco/core/decoder_buffer.h" +#include "draco/core/encoder_buffer.h" namespace draco { @@ -35,10 +37,38 @@ class AttributeTransform { AttributeTransformData *out_data) const = 0; bool TransferToAttribute(PointAttribute *attribute) const; + // Applies the transform to |attribute| and stores the result in + // |target_attribute|. |point_ids| is an optional vector that can be used to + // remap values during the transform. + virtual bool TransformAttribute(const PointAttribute &attribute, + const std::vector &point_ids, + PointAttribute *target_attribute) = 0; + + // Applies an inverse transform to |attribute| and stores the result in + // |target_attribute|. In this case, |attribute| is an attribute that was + // already transformed (e.g. quantized) and |target_attribute| is the + // attribute before the transformation. + virtual bool InverseTransformAttribute(const PointAttribute &attribute, + PointAttribute *target_attribute) = 0; + + // Encodes all data needed by the transformation into the |encoder_buffer|. + virtual bool EncodeParameters(EncoderBuffer *encoder_buffer) const = 0; + + // Decodes all data needed to transform |attribute| back to the original + // format. + virtual bool DecodeParameters(const PointAttribute &attribute, + DecoderBuffer *decoder_buffer) = 0; + + // Initializes a transformed attribute that can be used as target in the + // TransformAttribute() function call. + virtual std::unique_ptr InitTransformedAttribute( + const PointAttribute &src_attribute, int num_entries); + protected: - std::unique_ptr InitPortableAttribute( - int num_entries, int num_components, int num_points, - const PointAttribute &attribute, bool is_unsigned) const; + virtual DataType GetTransformedDataType( + const PointAttribute &attribute) const = 0; + virtual int GetTransformedNumComponents( + const PointAttribute &attribute) const = 0; }; } // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/geometry_attribute.cc b/extern/draco/draco/src/draco/attributes/geometry_attribute.cc index f7ed6a86915..b624784261d 100644 --- a/extern/draco/draco/src/draco/attributes/geometry_attribute.cc +++ b/extern/draco/draco/src/draco/attributes/geometry_attribute.cc @@ -43,10 +43,6 @@ void GeometryAttribute::Init(GeometryAttribute::Type attribute_type, } bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) { - if (buffer_ == nullptr || src_att.buffer_ == nullptr) { - return false; - } - buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size()); num_components_ = src_att.num_components_; data_type_ = src_att.data_type_; normalized_ = src_att.normalized_; @@ -55,6 +51,14 @@ bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) { attribute_type_ = src_att.attribute_type_; buffer_descriptor_ = src_att.buffer_descriptor_; unique_id_ = src_att.unique_id_; + if (src_att.buffer_ == nullptr) { + buffer_ = nullptr; + } else { + if (buffer_ == nullptr) { + return false; + } + buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size()); + } return true; } diff --git a/extern/draco/draco/src/draco/attributes/geometry_attribute.h b/extern/draco/draco/src/draco/attributes/geometry_attribute.h index b94ba8e22dd..c5faccc1b83 100644 --- a/extern/draco/draco/src/draco/attributes/geometry_attribute.h +++ b/extern/draco/draco/src/draco/attributes/geometry_attribute.h @@ -21,6 +21,7 @@ #include "draco/attributes/geometry_indices.h" #include "draco/core/data_buffer.h" #include "draco/core/hash_utils.h" +#include "draco/draco_features.h" namespace draco { @@ -51,6 +52,16 @@ class GeometryAttribute { // predefined use case. Such attributes are often used for a shader specific // data. GENERIC, +#ifdef DRACO_TRANSCODER_SUPPORTED + // TODO(ostava): Adding a new attribute would be bit-stream change for GLTF. + // Older decoders wouldn't know what to do with this attribute type. This + // should be open-sourced only when we are ready to increase our bit-stream + // version. + TANGENT, + MATERIAL, + JOINTS, + WEIGHTS, +#endif // Total number of different attribute types. // Always keep behind all named attributes. NAMED_ATTRIBUTES_COUNT, @@ -111,6 +122,9 @@ class GeometryAttribute { const int64_t byte_pos = GetBytePos(att_index); return buffer_->data() + byte_pos; } + inline bool IsAddressValid(const uint8_t *address) const { + return ((buffer_->data() + buffer_->data_size()) > address); + } // Fills out_data with the raw value of the requested attribute entry. // out_data must be at least byte_stride_ long. @@ -263,7 +277,35 @@ class GeometryAttribute { // Convert all components available in both the original and output formats. for (int i = 0; i < std::min(num_components_, out_num_components); ++i) { + if (!IsAddressValid(src_address)) { + return false; + } const T in_value = *reinterpret_cast(src_address); + + // Make sure the in_value fits within the range of values that OutT + // is able to represent. Perform the check only for integral types. + if (std::is_integral::value && std::is_integral::value) { +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4804) +#endif +#if defined(__GNUC__) && !defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wbool-compare" +#endif + static constexpr OutT kOutMin = + std::is_signed::value ? std::numeric_limits::lowest() : 0; + if (in_value < kOutMin || in_value > std::numeric_limits::max()) { + return false; + } +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif +#ifdef _MSC_VER +# pragma warning(pop) +#endif + } + out_value[i] = static_cast(in_value); // When converting integer to floating point, normalize the value if // necessary. diff --git a/extern/draco/draco/src/draco/attributes/point_attribute.cc b/extern/draco/draco/src/draco/attributes/point_attribute.cc index b28f860c15d..e54ab54278f 100644 --- a/extern/draco/draco/src/draco/attributes/point_attribute.cc +++ b/extern/draco/draco/src/draco/attributes/point_attribute.cc @@ -222,4 +222,47 @@ AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues( } #endif +#ifdef DRACO_TRANSCODER_SUPPORTED +void PointAttribute::RemoveUnusedValues() { + if (is_mapping_identity()) { + return; // For identity mapping, all values are always used. + } + // For explicit mapping we need to check if any point is mapped to a value. + // If not we can delete the value. + IndexTypeVector is_value_used(size(), false); + int num_used_values = 0; + for (PointIndex pi(0); pi < indices_map_.size(); ++pi) { + const AttributeValueIndex avi = indices_map_[pi]; + if (!is_value_used[avi]) { + is_value_used[avi] = true; + num_used_values++; + } + } + if (num_used_values == size()) { + return; // All values are used. + } + + // Remap the values and update the point to value mapping. + IndexTypeVector + old_to_new_value_map(size(), kInvalidAttributeValueIndex); + AttributeValueIndex new_avi(0); + for (AttributeValueIndex avi(0); avi < size(); ++avi) { + if (!is_value_used[avi]) { + continue; + } + if (avi != new_avi) { + SetAttributeValue(new_avi, GetAddress(avi)); + } + old_to_new_value_map[avi] = new_avi++; + } + + // Remap all points to the new attribute values. + for (PointIndex pi(0); pi < indices_map_.size(); ++pi) { + indices_map_[pi] = old_to_new_value_map[indices_map_[pi]]; + } + + num_unique_entries_ = num_used_values; +} +#endif + } // namespace draco diff --git a/extern/draco/draco/src/draco/attributes/point_attribute.h b/extern/draco/draco/src/draco/attributes/point_attribute.h index ee36620313e..d55c50c8a57 100644 --- a/extern/draco/draco/src/draco/attributes/point_attribute.h +++ b/extern/draco/draco/src/draco/attributes/point_attribute.h @@ -133,6 +133,12 @@ class PointAttribute : public GeometryAttribute { return attribute_transform_data_.get(); } +#ifdef DRACO_TRANSCODER_SUPPORTED + // Removes unused values from the attribute. Value is unused when no point + // is mapped to the value. Only applicable when the mapping is not identity. + void RemoveUnusedValues(); +#endif + private: #ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED template diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc index ce5b8b9c756..007dd2f4303 100644 --- a/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/attributes_decoder.cc @@ -43,9 +43,18 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) { return false; } } + + // Check that decoded number of attributes is valid. if (num_attributes == 0) { return false; } + if (num_attributes > 5 * in_buffer->remaining_size()) { + // The decoded number of attributes is unreasonably high, because at least + // five bytes of attribute descriptor data per attribute are expected. + return false; + } + + // Decode attribute descriptor data. point_attribute_ids_.resize(num_attributes); PointCloud *pc = point_cloud_; for (uint32_t i = 0; i < num_attributes; ++i) { @@ -69,9 +78,14 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) { if (data_type == DT_INVALID || data_type >= DT_TYPES_COUNT) { return false; } - const DataType draco_dt = static_cast(data_type); - // Add the attribute to the point cloud + // Check decoded attribute descriptor data. + if (num_components == 0) { + return false; + } + + // Add the attribute to the point cloud. + const DataType draco_dt = static_cast(data_type); GeometryAttribute ga; ga.Init(static_cast(att_type), nullptr, num_components, draco_dt, normalized > 0, @@ -90,7 +104,9 @@ bool AttributesDecoder::DecodeAttributesDecoderData(DecoderBuffer *in_buffer) { } else #endif { - DecodeVarint(&unique_id, in_buffer); + if (!DecodeVarint(&unique_id, in_buffer)) { + return false; + } ga.set_unique_id(unique_id); } const int att_id = pc->AddAttribute( diff --git a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc index 797c62f30aa..480e3ff3436 100644 --- a/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/attributes_encoder.cc @@ -15,14 +15,16 @@ #include "draco/compression/attributes/attributes_encoder.h" #include "draco/core/varint_encoding.h" +#include "draco/draco_features.h" namespace draco { AttributesEncoder::AttributesEncoder() : point_cloud_encoder_(nullptr), point_cloud_(nullptr) {} -AttributesEncoder::AttributesEncoder(int att_id) : AttributesEncoder() { - AddAttributeId(att_id); +AttributesEncoder::AttributesEncoder(int point_attrib_id) + : AttributesEncoder() { + AddAttributeId(point_attrib_id); } bool AttributesEncoder::Init(PointCloudEncoder *encoder, const PointCloud *pc) { @@ -37,7 +39,15 @@ bool AttributesEncoder::EncodeAttributesEncoderData(EncoderBuffer *out_buffer) { for (uint32_t i = 0; i < num_attributes(); ++i) { const int32_t att_id = point_attribute_ids_[i]; const PointAttribute *const pa = point_cloud_->attribute(att_id); - out_buffer->Encode(static_cast(pa->attribute_type())); + GeometryAttribute::Type type = pa->attribute_type(); +#ifdef DRACO_TRANSCODER_SUPPORTED + // Attribute types TANGENT, MATERIAL, JOINTS, and WEIGHTS are not supported + // in the official bitstream. They will be encoded as GENERIC. + if (type > GeometryAttribute::GENERIC) { + type = GeometryAttribute::GENERIC; + } +#endif + out_buffer->Encode(static_cast(type)); out_buffer->Encode(static_cast(pa->data_type())); out_buffer->Encode(static_cast(pa->num_components())); out_buffer->Encode(static_cast(pa->normalized())); diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc index 99469f94590..c7c96d77007 100644 --- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_decoder.cc @@ -72,7 +72,7 @@ class PointAttributeVectorOutputIterator { Self &operator*() { return *this; } // Still needed in some cases. - // TODO(hemmer): remove. + // TODO(b/199760123): Remove. // hardcoded to 3 based on legacy usage. const Self &operator=(const VectorD &val) { DRACO_DCHECK_EQ(attributes_.size(), 1); // Expect only ONE attribute. @@ -278,8 +278,10 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms( return false; } AttributeQuantizationTransform transform; - transform.SetParameters(quantization_bits, min_value.data(), - num_components, max_value_dif); + if (!transform.SetParameters(quantization_bits, min_value.data(), + num_components, max_value_dif)) { + return false; + } const int num_transforms = static_cast(attribute_quantization_transforms_.size()); if (!transform.TransferToAttribute( @@ -293,7 +295,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms( // Decode transform data for signed integer attributes. for (int i = 0; i < min_signed_values_.size(); ++i) { int32_t val; - DecodeVarint(&val, in_buffer); + if (!DecodeVarint(&val, in_buffer)) { + return false; + } min_signed_values_[i] = val; } return true; @@ -353,8 +357,9 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms( return false; } if (6 < compression_level) { - LOGE("KdTreeAttributesDecoder: compression level %i not supported.\n", - compression_level); + DRACO_LOGE( + "KdTreeAttributesDecoder: compression level %i not supported.\n", + compression_level); return false; } @@ -371,7 +376,7 @@ bool KdTreeAttributesDecoder::DecodeDataNeededByPortableTransforms( GetDecoder()->point_cloud()->attribute(att_id); attr->Reset(num_points); attr->SetIdentityMapping(); - }; + } PointAttributeVectorOutputIterator out_it(atts); diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc index 0f9c31565e5..b70deb9e01f 100644 --- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.cc @@ -71,16 +71,21 @@ bool KdTreeAttributesEncoder::TransformAttributesToPortableFormat() { att->num_components(), range); } else { // Compute quantization settings from the attribute values. - attribute_quantization_transform.ComputeParameters(*att, - quantization_bits); + if (!attribute_quantization_transform.ComputeParameters( + *att, quantization_bits)) { + return false; + } } attribute_quantization_transforms_.push_back( attribute_quantization_transform); // Store the quantized attribute in an array that will be used when we do // the actual encoding of the data. - quantized_portable_attributes_.push_back( - attribute_quantization_transform.GeneratePortableAttribute( - *att, static_cast(num_points))); + auto portable_att = + attribute_quantization_transform.InitTransformedAttribute(*att, + num_points); + attribute_quantization_transform.TransformAttribute(*att, {}, + portable_att.get()); + quantized_portable_attributes_.push_back(std::move(portable_att)); } else if (att->data_type() == DT_INT32 || att->data_type() == DT_INT16 || att->data_type() == DT_INT8) { // For signed types, find the minimum value for each component. These diff --git a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h index 8b4c4e2faab..80748e0bf5d 100644 --- a/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h +++ b/extern/draco/draco/src/draco/compression/attributes/kd_tree_attributes_encoder.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_ -#define DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_ +#ifndef DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_ #include "draco/attributes/attribute_quantization_transform.h" #include "draco/compression/attributes/attributes_encoder.h" @@ -48,4 +48,4 @@ class KdTreeAttributesEncoder : public AttributesEncoder { } // namespace draco -#endif // DRACO_COMPRESSION_ATTRIBUTES_POINT_CLOUD_KD_TREE_ATTRIBUTES_ENCODER_H_ +#endif // DRACO_COMPRESSION_ATTRIBUTES_KD_TREE_ATTRIBUTES_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h index 32e27c711e3..be5ee5b09e3 100644 --- a/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h +++ b/extern/draco/draco/src/draco/compression/attributes/normal_compression_utils.h @@ -53,6 +53,7 @@ class OctahedronToolBox { : quantization_bits_(-1), max_quantized_value_(-1), max_value_(-1), + dequantization_scale_(1.f), center_value_(-1) {} bool SetQuantizationBits(int32_t q) { @@ -62,6 +63,7 @@ class OctahedronToolBox { quantization_bits_ = q; max_quantized_value_ = (1 << quantization_bits_) - 1; max_value_ = max_quantized_value_ - 1; + dequantization_scale_ = 2.f / max_value_; center_value_ = max_value_ / 2; return true; } @@ -192,64 +194,11 @@ class OctahedronToolBox { } } - // TODO(b/149328891): Change function to not use templates as |T| is only - // float. - template - void OctaherdalCoordsToUnitVector(T in_s, T in_t, T *out_vector) const { - DRACO_DCHECK_GE(in_s, 0); - DRACO_DCHECK_GE(in_t, 0); - DRACO_DCHECK_LE(in_s, 1); - DRACO_DCHECK_LE(in_t, 1); - T s = in_s; - T t = in_t; - T spt = s + t; - T smt = s - t; - T x_sign = 1.0; - if (spt >= 0.5 && spt <= 1.5 && smt >= -0.5 && smt <= 0.5) { - // Right hemisphere. Don't do anything. - } else { - // Left hemisphere. - x_sign = -1.0; - if (spt <= 0.5) { - s = 0.5 - in_t; - t = 0.5 - in_s; - } else if (spt >= 1.5) { - s = 1.5 - in_t; - t = 1.5 - in_s; - } else if (smt <= -0.5) { - s = in_t - 0.5; - t = in_s + 0.5; - } else { - s = in_t + 0.5; - t = in_s - 0.5; - } - spt = s + t; - smt = s - t; - } - const T y = 2.0 * s - 1.0; - const T z = 2.0 * t - 1.0; - const T x = std::min(std::min(2.0 * spt - 1.0, 3.0 - 2.0 * spt), - std::min(2.0 * smt + 1.0, 1.0 - 2.0 * smt)) * - x_sign; - // Normalize the computed vector. - const T normSquared = x * x + y * y + z * z; - if (normSquared < 1e-6) { - out_vector[0] = 0; - out_vector[1] = 0; - out_vector[2] = 0; - } else { - const T d = 1.0 / std::sqrt(normSquared); - out_vector[0] = x * d; - out_vector[1] = y * d; - out_vector[2] = z * d; - } - } - - template - void QuantizedOctaherdalCoordsToUnitVector(int32_t in_s, int32_t in_t, - T *out_vector) const { - T scale = 1.0 / static_cast(max_value_); - OctaherdalCoordsToUnitVector(in_s * scale, in_t * scale, out_vector); + inline void QuantizedOctahedralCoordsToUnitVector(int32_t in_s, int32_t in_t, + float *out_vector) const { + OctahedralCoordsToUnitVector(in_s * dequantization_scale_ - 1.f, + in_t * dequantization_scale_ - 1.f, + out_vector); } // |s| and |t| are expected to be signed values. @@ -333,9 +282,77 @@ class OctahedronToolBox { int32_t center_value() const { return center_value_; } private: + inline void OctahedralCoordsToUnitVector(float in_s_scaled, float in_t_scaled, + float *out_vector) const { + // Background about the encoding: + // A normal is encoded in a normalized space depicted below. The + // encoding correponds to an octahedron that is unwrapped to a 2D plane. + // During encoding, a normal is projected to the surface of the octahedron + // and the projection is then unwrapped to the 2D plane. Decoding is the + // reverse of this process. + // All points in the central diamond are located on triangles on the + // right "hemisphere" of the octahedron while all points outside of the + // diamond are on the left hemisphere (basically, they would have to be + // wrapped along the diagonal edges to form the octahedron). The central + // point corresponds to the right most vertex of the octahedron and all + // corners of the plane correspond to the left most vertex of the + // octahedron. + // + // t + // ^ *-----*-----* + // | | /|\ | + // | / | \ | + // | / | \ | + // | / | \ | + // *-----*---- * + // | \ | / | + // | \ | / | + // | \ | / | + // | \|/ | + // *-----*-----* --> s + + // Note that the input |in_s_scaled| and |in_t_scaled| are already scaled to + // <-1, 1> range. This way, the central point is at coordinate (0, 0). + float y = in_s_scaled; + float z = in_t_scaled; + + // Remaining coordinate can be computed by projecting the (y, z) values onto + // the surface of the octahedron. + const float x = 1.f - std::abs(y) - std::abs(z); + + // |x| is essentially a signed distance from the diagonal edges of the + // diamond shown on the figure above. It is positive for all points in the + // diamond (right hemisphere) and negative for all points outside the + // diamond (left hemisphere). For all points on the left hemisphere we need + // to update their (y, z) coordinates to account for the wrapping along + // the edges of the diamond. + float x_offset = -x; + x_offset = x_offset < 0 ? 0 : x_offset; + + // This will do nothing for the points on the right hemisphere but it will + // mirror the (y, z) location along the nearest diagonal edge of the + // diamond. + y += y < 0 ? x_offset : -x_offset; + z += z < 0 ? x_offset : -x_offset; + + // Normalize the computed vector. + const float norm_squared = x * x + y * y + z * z; + if (norm_squared < 1e-6) { + out_vector[0] = 0; + out_vector[1] = 0; + out_vector[2] = 0; + } else { + const float d = 1.0f / std::sqrt(norm_squared); + out_vector[0] = x * d; + out_vector[1] = y * d; + out_vector[2] = z * d; + } + } + int32_t quantization_bits_; int32_t max_quantized_value_; int32_t max_value_; + float dequantization_scale_; int32_t center_value_; }; } // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h index f712952556a..2960a5e71b4 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_data.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_ -#define DRACO_COMPRESSION_ATTRIBUTES_MESH_PREDICTION_SCHEMES_PREDICTION_SCHEME_DATA_H_ +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_DATA_H_ #include "draco/mesh/corner_table.h" #include "draco/mesh/mesh.h" diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h index bf1a6146111..775eded6b55 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_predictor_area.h @@ -69,7 +69,14 @@ class MeshPredictionSchemeGeometricNormalPredictorArea // Computing cross product. const VectorD cross = CrossProduct(delta_next, delta_prev); - normal = normal + cross; + + // Prevent signed integer overflows by doing math as unsigned. + auto normal_data = reinterpret_cast(normal.data()); + auto cross_data = reinterpret_cast(cross.data()); + normal_data[0] = normal_data[0] + cross_data[0]; + normal_data[1] = normal_data[1] + cross_data[1]; + normal_data[2] = normal_data[2] + cross_data[2]; + cit.Next(); } diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h index 485d457ccf6..fd10fb524b3 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_shared.h @@ -60,8 +60,13 @@ inline bool ComputeParallelogramPrediction( const int v_next_off = vert_next * num_components; const int v_prev_off = vert_prev * num_components; for (int c = 0; c < num_components; ++c) { - out_prediction[c] = (in_data[v_next_off + c] + in_data[v_prev_off + c]) - - in_data[v_opp_off + c]; + const int64_t in_data_next_off = in_data[v_next_off + c]; + const int64_t in_data_prev_off = in_data[v_prev_off + c]; + const int64_t in_data_opp_off = in_data[v_opp_off + c]; + const int64_t result = + (in_data_next_off + in_data_prev_off) - in_data_opp_off; + + out_prediction[c] = static_cast(result); } return true; } diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h index 5d8a5060133..f05e5ddd713 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_portable_predictor.h @@ -156,6 +156,13 @@ bool MeshPredictionSchemeTexCoordsPortablePredictor< const VectorD x_uv = n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv); + const int64_t pn_absmax_element = + std::max(std::max(std::abs(pn[0]), std::abs(pn[1])), std::abs(pn[2])); + if (cn_dot_pn > std::numeric_limits::max() / pn_absmax_element) { + // return false if squared length calculation would overflow. + return false; + } + // Compute squared length of vector CX in position coordinate system: const VectorD x_pos = next_pos + (cn_dot_pn * pn) / pn_norm2_squared; diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc index 428340da013..60429d5c779 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc @@ -18,34 +18,51 @@ namespace draco { PredictionSchemeMethod SelectPredictionMethod( int att_id, const PointCloudEncoder *encoder) { - if (encoder->options()->GetSpeed() >= 10) { + return SelectPredictionMethod(att_id, *encoder->options(), encoder); +} + +PredictionSchemeMethod SelectPredictionMethod( + int att_id, const EncoderOptions &options, + const PointCloudEncoder *encoder) { + if (options.GetSpeed() >= 10) { // Selected fastest, though still doing some compression. return PREDICTION_DIFFERENCE; } if (encoder->GetGeometryType() == TRIANGULAR_MESH) { // Use speed setting to select the best encoding method. const PointAttribute *const att = encoder->point_cloud()->attribute(att_id); - if (att->attribute_type() == GeometryAttribute::TEX_COORD) { - if (encoder->options()->GetSpeed() < 4) { + if (att->attribute_type() == GeometryAttribute::TEX_COORD && + att->num_components() == 2) { + if (options.GetSpeed() < 4) { // Use texture coordinate prediction for speeds 0, 1, 2, 3. return MESH_PREDICTION_TEX_COORDS_PORTABLE; } } if (att->attribute_type() == GeometryAttribute::NORMAL) { #ifdef DRACO_NORMAL_ENCODING_SUPPORTED - if (encoder->options()->GetSpeed() < 4) { + if (options.GetSpeed() < 4) { // Use geometric normal prediction for speeds 0, 1, 2, 3. - return MESH_PREDICTION_GEOMETRIC_NORMAL; + // For this prediction, the position attribute needs to be either + // integer or quantized as well. + const int pos_att_id = encoder->point_cloud()->GetNamedAttributeId( + GeometryAttribute::POSITION); + const PointAttribute *const pos_att = + encoder->point_cloud()->GetNamedAttribute( + GeometryAttribute::POSITION); + if (pos_att && (IsDataTypeIntegral(pos_att->data_type()) || + options.GetAttributeInt(pos_att_id, "quantization_bits", + -1) > 0)) { + return MESH_PREDICTION_GEOMETRIC_NORMAL; + } } #endif return PREDICTION_DIFFERENCE; // default } // Handle other attribute types. - if (encoder->options()->GetSpeed() >= 8) { + if (options.GetSpeed() >= 8) { return PREDICTION_DIFFERENCE; } - if (encoder->options()->GetSpeed() >= 2 || - encoder->point_cloud()->num_points() < 40) { + if (options.GetSpeed() >= 2 || encoder->point_cloud()->num_points() < 40) { // Parallelogram prediction is used for speeds 2 - 7 or when the overhead // of using constrained multi-parallelogram would be too high. return MESH_PREDICTION_PARALLELOGRAM; diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h index 40a7683aa0d..b7e21224fad 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h @@ -38,6 +38,10 @@ namespace draco { PredictionSchemeMethod SelectPredictionMethod(int att_id, const PointCloudEncoder *encoder); +PredictionSchemeMethod SelectPredictionMethod(int att_id, + const EncoderOptions &options, + const PointCloudEncoder *encoder); + // Factory class for creating mesh prediction schemes. template struct MeshPredictionSchemeEncoderFactory { diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h index ab64bce7114..37aa9f76a9c 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_interface.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_ -#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_ +#ifndef DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_ +#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_ #include "draco/compression/attributes/prediction_schemes/prediction_scheme_interface.h" #include "draco/core/encoder_buffer.h" @@ -52,4 +52,4 @@ class PredictionSchemeTypedEncoderInterface } // namespace draco -#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODING_INTERFACE_H_ +#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_INTERFACE_H_ diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h index 0a14d0d9ba4..e100c738a6c 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_decoding_transform.h @@ -36,9 +36,25 @@ class PredictionSchemeWrapDecodingTransform inline void ComputeOriginalValue(const DataTypeT *predicted_vals, const CorrTypeT *corr_vals, DataTypeT *out_original_vals) const { + // For now we assume both |DataTypeT| and |CorrTypeT| are equal. + static_assert(std::is_same::value, + "Predictions and corrections must have the same type."); + + // The only valid implementation right now is for int32_t. + static_assert(std::is_same::value, + "Only int32_t is supported for predicted values."); + predicted_vals = this->ClampPredictedValue(predicted_vals); + + // Perform the wrapping using unsigned coordinates to avoid potential signed + // integer overflows caused by malformed input. + const uint32_t *const uint_predicted_vals = + reinterpret_cast(predicted_vals); + const uint32_t *const uint_corr_vals = + reinterpret_cast(corr_vals); for (int i = 0; i < this->num_components(); ++i) { - out_original_vals[i] = predicted_vals[i] + corr_vals[i]; + out_original_vals[i] = + static_cast(uint_predicted_vals[i] + uint_corr_vals[i]); if (out_original_vals[i] > this->max_value()) { out_original_vals[i] -= this->max_dif(); } else if (out_original_vals[i] < this->min_value()) { diff --git a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h index 26f61fbaf6a..979c63c3d11 100644 --- a/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h +++ b/extern/draco/draco/src/draco/compression/attributes/prediction_schemes/prediction_scheme_wrap_transform_base.h @@ -73,7 +73,7 @@ class PredictionSchemeWrapTransformBase { return &clamped_value_[0]; } - // TODO(hemmer): Consider refactoring to avoid this dummy. + // TODO(b/199760123): Consider refactoring to avoid this dummy. int quantization_bits() const { DRACO_DCHECK(false); return -1; diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc index 521935c1e99..7d5d1eeff26 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc @@ -26,8 +26,8 @@ SequentialAttributeEncodersController::SequentialAttributeEncodersController( : sequencer_(std::move(sequencer)) {} SequentialAttributeEncodersController::SequentialAttributeEncodersController( - std::unique_ptr sequencer, int att_id) - : AttributesEncoder(att_id), sequencer_(std::move(sequencer)) {} + std::unique_ptr sequencer, int point_attrib_id) + : AttributesEncoder(point_attrib_id), sequencer_(std::move(sequencer)) {} bool SequentialAttributeEncodersController::Init(PointCloudEncoder *encoder, const PointCloud *pc) { diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc index d01fb26aad4..17f32fc1612 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_decoder.cc @@ -53,6 +53,11 @@ bool SequentialIntegerAttributeDecoder::DecodeValues( if (!in_buffer->Decode(&prediction_transform_type)) { return false; } + // Check that decoded prediction scheme transform type is valid. + if (prediction_transform_type < PREDICTION_TRANSFORM_NONE || + prediction_transform_type >= NUM_PREDICTION_SCHEME_TRANSFORM_TYPES) { + return false; + } prediction_scheme_ = CreateIntPredictionScheme( static_cast(prediction_scheme_method), static_cast(prediction_transform_type)); @@ -143,8 +148,9 @@ bool SequentialIntegerAttributeDecoder::DecodeIntegerValues( return false; } for (size_t i = 0; i < num_values; ++i) { - if (!in_buffer->Decode(portable_attribute_data + i, num_bytes)) + if (!in_buffer->Decode(portable_attribute_data + i, num_bytes)) { return false; + } } } } @@ -223,12 +229,13 @@ void SequentialIntegerAttributeDecoder::StoreTypedValues(uint32_t num_values) { void SequentialIntegerAttributeDecoder::PreparePortableAttribute( int num_entries, int num_components) { - GeometryAttribute va; - va.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32, + GeometryAttribute ga; + ga.Init(attribute()->attribute_type(), nullptr, num_components, DT_INT32, false, num_components * DataTypeLength(DT_INT32), 0); - std::unique_ptr port_att(new PointAttribute(va)); + std::unique_ptr port_att(new PointAttribute(ga)); port_att->SetIdentityMapping(); port_att->Reset(num_entries); + port_att->set_unique_id(attribute()->unique_id()); SetPortableAttribute(std::move(port_att)); } diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc index 2889e0521a0..e66a0a8a40a 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_integer_attribute_encoder.cc @@ -81,6 +81,9 @@ bool SequentialIntegerAttributeEncoder::TransformAttributeToPortableFormat( value_to_value_map[orig_att->mapped_index(point_ids[i])] = AttributeValueIndex(i); } + if (portable_att->is_mapping_identity()) { + portable_att->SetExplicitMapping(encoder()->point_cloud()->num_points()); + } // Go over all points of the original attribute and update the mapping in // the portable attribute. for (PointIndex i(0); i < encoder()->point_cloud()->num_points(); ++i) { diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc index 017344393dc..de36c1c36f2 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.cc @@ -14,18 +14,17 @@ // #include "draco/compression/attributes/sequential_normal_attribute_decoder.h" -#include "draco/attributes/attribute_octahedron_transform.h" #include "draco/compression/attributes/normal_compression_utils.h" namespace draco { -SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder() - : quantization_bits_(-1) {} +SequentialNormalAttributeDecoder::SequentialNormalAttributeDecoder() {} bool SequentialNormalAttributeDecoder::Init(PointCloudDecoder *decoder, int attribute_id) { - if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id)) + if (!SequentialIntegerAttributeDecoder::Init(decoder, attribute_id)) { return false; + } // Currently, this encoder works only for 3-component normal vectors. if (attribute()->num_components() != 3) { return false; @@ -41,11 +40,13 @@ bool SequentialNormalAttributeDecoder::DecodeIntegerValues( const std::vector &point_ids, DecoderBuffer *in_buffer) { #ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED if (decoder()->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 0)) { - uint8_t quantization_bits; - if (!in_buffer->Decode(&quantization_bits)) { + // Note: in older bitstreams, we do not have a PortableAttribute() decoded + // at this stage so we cannot pass it down to the DecodeParameters() call. + // It still works fine for octahedral transform because it does not need to + // use any data from the attribute. + if (!octahedral_transform_.DecodeParameters(*attribute(), in_buffer)) { return false; } - quantization_bits_ = quantization_bits; } #endif return SequentialIntegerAttributeDecoder::DecodeIntegerValues(point_ids, @@ -56,39 +57,20 @@ bool SequentialNormalAttributeDecoder::DecodeDataNeededByPortableTransform( const std::vector &point_ids, DecoderBuffer *in_buffer) { if (decoder()->bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 0)) { // For newer file version, decode attribute transform data here. - uint8_t quantization_bits; - if (!in_buffer->Decode(&quantization_bits)) { + if (!octahedral_transform_.DecodeParameters(*GetPortableAttribute(), + in_buffer)) { return false; } - quantization_bits_ = quantization_bits; } // Store the decoded transform data in portable attribute. - AttributeOctahedronTransform octahedral_transform; - octahedral_transform.SetParameters(quantization_bits_); - return octahedral_transform.TransferToAttribute(portable_attribute()); + return octahedral_transform_.TransferToAttribute(portable_attribute()); } bool SequentialNormalAttributeDecoder::StoreValues(uint32_t num_points) { // Convert all quantized values back to floats. - const int num_components = attribute()->num_components(); - const int entry_size = sizeof(float) * num_components; - float att_val[3]; - int quant_val_id = 0; - int out_byte_pos = 0; - const int32_t *const portable_attribute_data = GetPortableAttributeData(); - OctahedronToolBox octahedron_tool_box; - if (!octahedron_tool_box.SetQuantizationBits(quantization_bits_)) - return false; - for (uint32_t i = 0; i < num_points; ++i) { - const int32_t s = portable_attribute_data[quant_val_id++]; - const int32_t t = portable_attribute_data[quant_val_id++]; - octahedron_tool_box.QuantizedOctaherdalCoordsToUnitVector(s, t, att_val); - // Store the decoded floating point value into the attribute buffer. - attribute()->buffer()->Write(out_byte_pos, att_val, entry_size); - out_byte_pos += entry_size; - } - return true; + return octahedral_transform_.InverseTransformAttribute( + *GetPortableAttribute(), attribute()); } } // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h index 860eacb4c84..8c2d801b763 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_decoder.h @@ -15,6 +15,7 @@ #ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_ #define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_NORMAL_ATTRIBUTE_DECODER_H_ +#include "draco/attributes/attribute_octahedron_transform.h" #include "draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h" #include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_canonicalized_decoding_transform.h" #include "draco/compression/attributes/prediction_schemes/prediction_scheme_normal_octahedron_decoding_transform.h" @@ -42,7 +43,7 @@ class SequentialNormalAttributeDecoder bool StoreValues(uint32_t num_points) override; private: - int32_t quantization_bits_; + AttributeOctahedronTransform octahedral_transform_; std::unique_ptr> CreateIntPredictionScheme( diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc index 23fa8bb7b39..3c5ef0ebcbc 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_normal_attribute_encoder.cc @@ -20,8 +20,9 @@ namespace draco { bool SequentialNormalAttributeEncoder::Init(PointCloudEncoder *encoder, int attribute_id) { - if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) + if (!SequentialIntegerAttributeEncoder::Init(encoder, attribute_id)) { return false; + } // Currently this encoder works only for 3-component normal vectors. if (attribute()->num_components() != 3) { return false; @@ -44,9 +45,13 @@ bool SequentialNormalAttributeEncoder::EncodeDataNeededByPortableTransform( bool SequentialNormalAttributeEncoder::PrepareValues( const std::vector &point_ids, int num_points) { - SetPortableAttribute( - attribute_octahedron_transform_.GeneratePortableAttribute( - *(attribute()), point_ids, num_points)); + auto portable_att = attribute_octahedron_transform_.InitTransformedAttribute( + *(attribute()), point_ids.size()); + if (!attribute_octahedron_transform_.TransformAttribute( + *(attribute()), point_ids, portable_att.get())) { + return false; + } + SetPortableAttribute(std::move(portable_att)); return true; } diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc index bf925c4a595..3d306e7dae6 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.cc @@ -14,13 +14,12 @@ // #include "draco/compression/attributes/sequential_quantization_attribute_decoder.h" -#include "draco/attributes/attribute_quantization_transform.h" #include "draco/core/quantization_utils.h" namespace draco { -SequentialQuantizationAttributeDecoder::SequentialQuantizationAttributeDecoder() - : quantization_bits_(-1), max_value_dif_(0.f) {} +SequentialQuantizationAttributeDecoder:: + SequentialQuantizationAttributeDecoder() {} bool SequentialQuantizationAttributeDecoder::Init(PointCloudDecoder *decoder, int attribute_id) { @@ -59,62 +58,31 @@ bool SequentialQuantizationAttributeDecoder:: } // Store the decoded transform data in portable attribute; - AttributeQuantizationTransform transform; - transform.SetParameters(quantization_bits_, min_value_.get(), - attribute()->num_components(), max_value_dif_); - return transform.TransferToAttribute(portable_attribute()); + return quantization_transform_.TransferToAttribute(portable_attribute()); } -bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_values) { - return DequantizeValues(num_values); +bool SequentialQuantizationAttributeDecoder::StoreValues(uint32_t num_points) { + return DequantizeValues(num_points); } bool SequentialQuantizationAttributeDecoder::DecodeQuantizedDataInfo() { - const int num_components = attribute()->num_components(); - min_value_ = std::unique_ptr(new float[num_components]); - if (!decoder()->buffer()->Decode(min_value_.get(), - sizeof(float) * num_components)) { - return false; - } - if (!decoder()->buffer()->Decode(&max_value_dif_)) { - return false; + // Get attribute used as source for decoding. + auto att = GetPortableAttribute(); + if (att == nullptr) { + // This should happen only in the backward compatibility mode. It will still + // work fine for this case because the only thing the quantization transform + // cares about is the number of components that is the same for both source + // and target attributes. + att = attribute(); } - uint8_t quantization_bits; - if (!decoder()->buffer()->Decode(&quantization_bits) || - quantization_bits > 31) { - return false; - } - quantization_bits_ = quantization_bits; - return true; + return quantization_transform_.DecodeParameters(*att, decoder()->buffer()); } bool SequentialQuantizationAttributeDecoder::DequantizeValues( uint32_t num_values) { // Convert all quantized values back to floats. - const int32_t max_quantized_value = - (1u << static_cast(quantization_bits_)) - 1; - const int num_components = attribute()->num_components(); - const int entry_size = sizeof(float) * num_components; - const std::unique_ptr att_val(new float[num_components]); - int quant_val_id = 0; - int out_byte_pos = 0; - Dequantizer dequantizer; - if (!dequantizer.Init(max_value_dif_, max_quantized_value)) { - return false; - } - const int32_t *const portable_attribute_data = GetPortableAttributeData(); - for (uint32_t i = 0; i < num_values; ++i) { - for (int c = 0; c < num_components; ++c) { - float value = - dequantizer.DequantizeFloat(portable_attribute_data[quant_val_id++]); - value = value + min_value_[c]; - att_val[c] = value; - } - // Store the floating point value into the attribute buffer. - attribute()->buffer()->Write(out_byte_pos, att_val.get(), entry_size); - out_byte_pos += entry_size; - } - return true; + return quantization_transform_.InverseTransformAttribute( + *GetPortableAttribute(), attribute()); } } // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h index c0b7637a750..ad372dcd8a6 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_decoder.h @@ -15,6 +15,7 @@ #ifndef DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_ #define DRACO_COMPRESSION_ATTRIBUTES_SEQUENTIAL_QUANTIZATION_ATTRIBUTE_DECODER_H_ +#include "draco/attributes/attribute_quantization_transform.h" #include "draco/compression/attributes/sequential_integer_attribute_decoder.h" #include "draco/draco_features.h" @@ -43,12 +44,7 @@ class SequentialQuantizationAttributeDecoder virtual bool DequantizeValues(uint32_t num_values); private: - // Max number of quantization bits used to encode each component of the - // attribute. - int32_t quantization_bits_; - - std::unique_ptr min_value_; - float max_value_dif_; + AttributeQuantizationTransform quantization_transform_; }; } // namespace draco diff --git a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc index cd5b8b141e0..d3666f7a411 100644 --- a/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc +++ b/extern/draco/draco/src/draco/compression/attributes/sequential_quantization_attribute_encoder.cc @@ -50,9 +50,11 @@ bool SequentialQuantizationAttributeEncoder::Init(PointCloudEncoder *encoder, &quantization_origin[0]); const float range = encoder->options()->GetAttributeFloat( attribute_id, "quantization_range", 1.f); - attribute_quantization_transform_.SetParameters( - quantization_bits, quantization_origin.data(), - attribute->num_components(), range); + if (!attribute_quantization_transform_.SetParameters( + quantization_bits, quantization_origin.data(), + attribute->num_components(), range)) { + return false; + } } else { // Compute quantization settings from the attribute values. if (!attribute_quantization_transform_.ComputeParameters( @@ -70,9 +72,14 @@ bool SequentialQuantizationAttributeEncoder:: bool SequentialQuantizationAttributeEncoder::PrepareValues( const std::vector &point_ids, int num_points) { - SetPortableAttribute( - attribute_quantization_transform_.GeneratePortableAttribute( - *(attribute()), point_ids, num_points)); + auto portable_attribute = + attribute_quantization_transform_.InitTransformedAttribute( + *attribute(), point_ids.size()); + if (!attribute_quantization_transform_.TransformAttribute( + *(attribute()), point_ids, portable_attribute.get())) { + return false; + } + SetPortableAttribute(std::move(portable_attribute)); return true; } diff --git a/extern/draco/draco/src/draco/compression/config/compression_shared.h b/extern/draco/draco/src/draco/compression/config/compression_shared.h index 40061d3cd48..c43f303bd15 100644 --- a/extern/draco/draco/src/draco/compression/config/compression_shared.h +++ b/extern/draco/draco/src/draco/compression/config/compression_shared.h @@ -42,6 +42,7 @@ enum EncodedGeometryType { INVALID_GEOMETRY_TYPE = -1, POINT_CLOUD = 0, TRIANGULAR_MESH, + NUM_ENCODED_GEOMETRY_TYPES }; // List of encoding methods for point clouds. @@ -105,6 +106,8 @@ enum PredictionSchemeTransformType { // Specialized transform for normal coordinates using canonicalized inverted // tiles. PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED = 3, + // The number of valid (non-negative) prediction scheme transform types. + NUM_PREDICTION_SCHEME_TRANSFORM_TYPES }; // List of all mesh traversal methods supported by Draco framework. diff --git a/extern/draco/draco/src/draco/compression/config/draco_options.h b/extern/draco/draco/src/draco/compression/config/draco_options.h index 0d1247b2ad1..2bd4a3b6761 100644 --- a/extern/draco/draco/src/draco/compression/config/draco_options.h +++ b/extern/draco/draco/src/draco/compression/config/draco_options.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_ -#define DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_ +#ifndef DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_ +#define DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_ #include #include @@ -246,4 +246,4 @@ void DracoOptions::SetAttributeOptions( } // namespace draco -#endif // DRACO_SRC_DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_ +#endif // DRACO_COMPRESSION_CONFIG_DRACO_OPTIONS_H_ diff --git a/extern/draco/draco/src/draco/compression/decode.cc b/extern/draco/draco/src/draco/compression/decode.cc index ab70ef1ec60..92ae4ff66f9 100644 --- a/extern/draco/draco/src/draco/compression/decode.cc +++ b/extern/draco/draco/src/draco/compression/decode.cc @@ -56,7 +56,10 @@ StatusOr Decoder::GetEncodedGeometryType( DecoderBuffer *in_buffer) { DecoderBuffer temp_buffer(*in_buffer); DracoHeader header; - DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header)) + DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header)); + if (header.encoder_type >= NUM_ENCODED_GEOMETRY_TYPES) { + return Status(Status::DRACO_ERROR, "Unsupported geometry type."); + } return static_cast(header.encoder_type); } diff --git a/extern/draco/draco/src/draco/compression/encode_base.h b/extern/draco/draco/src/draco/compression/encode_base.h index 0c63a972bf4..6211efc221b 100644 --- a/extern/draco/draco/src/draco/compression/encode_base.h +++ b/extern/draco/draco/src/draco/compression/encode_base.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_ -#define DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_ +#ifndef DRACO_COMPRESSION_ENCODE_BASE_H_ +#define DRACO_COMPRESSION_ENCODE_BASE_H_ #include "draco/attributes/geometry_attribute.h" #include "draco/compression/config/compression_shared.h" @@ -98,7 +98,7 @@ class EncoderBase { "Invalid prediction scheme for attribute type."); } } - // TODO(hemmer): Try to enable more prediction schemes for normals. + // TODO(b/199760123): Try to enable more prediction schemes for normals. if (att_type == GeometryAttribute::NORMAL) { if (!(prediction_scheme == PREDICTION_DIFFERENCE || prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) { @@ -128,4 +128,4 @@ void EncoderBase::SetTrackEncodedProperties(bool flag) { } // namespace draco -#endif // DRACO_SRC_DRACO_COMPRESSION_ENCODE_BASE_H_ +#endif // DRACO_COMPRESSION_ENCODE_BASE_H_ diff --git a/extern/draco/draco/src/draco/compression/entropy/ans.h b/extern/draco/draco/src/draco/compression/entropy/ans.h index c765256b96e..313546fee20 100644 --- a/extern/draco/draco/src/draco/compression/entropy/ans.h +++ b/extern/draco/draco/src/draco/compression/entropy/ans.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_CORE_ANS_H_ -#define DRACO_CORE_ANS_H_ +#ifndef DRACO_COMPRESSION_ENTROPY_ANS_H_ +#define DRACO_COMPRESSION_ENTROPY_ANS_H_ // An implementation of Asymmetric Numeral Systems (rANS). // See http://arxiv.org/abs/1311.2540v2 for more information on rANS. // This file is based off libvpx's ans.h. @@ -391,7 +391,6 @@ class RAnsEncoder { ans_.buf[ans_.buf_offset++] = ans_.state % DRACO_ANS_IO_BASE; ans_.state /= DRACO_ANS_IO_BASE; } - // TODO(ostava): The division and multiplication should be optimized. ans_.state = (ans_.state / p) * rans_precision + ans_.state % p + sym->cum_prob; } @@ -524,4 +523,4 @@ class RAnsDecoder { } // namespace draco -#endif // DRACO_CORE_ANS_H_ +#endif // DRACO_COMPRESSION_ENTROPY_ANS_H_ diff --git a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h index 0a68e29fe26..cd4271193bf 100644 --- a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h +++ b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_coding.h @@ -31,11 +31,10 @@ constexpr int ComputeRAnsUnclampedPrecision(int symbols_bit_length) { // our rANS library (which is between 12 to 20 bits). constexpr int ComputeRAnsPrecisionFromUniqueSymbolsBitLength( int symbols_bit_length) { - return ComputeRAnsUnclampedPrecision(symbols_bit_length) < 12 - ? 12 - : ComputeRAnsUnclampedPrecision(symbols_bit_length) > 20 - ? 20 - : ComputeRAnsUnclampedPrecision(symbols_bit_length); + return ComputeRAnsUnclampedPrecision(symbols_bit_length) < 12 ? 12 + : ComputeRAnsUnclampedPrecision(symbols_bit_length) > 20 + ? 20 + : ComputeRAnsUnclampedPrecision(symbols_bit_length); } // Compute approximate frequency table size needed for storing the provided diff --git a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h index 4e07ec87123..4b738b50a9d 100644 --- a/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h +++ b/extern/draco/draco/src/draco/compression/entropy/rans_symbol_encoder.h @@ -125,8 +125,8 @@ bool RAnsSymbolEncoder::Create( for (int i = 0; i < num_symbols; ++i) { sorted_probabilities[i] = i; } - std::sort(sorted_probabilities.begin(), sorted_probabilities.end(), - ProbabilityLess(&probability_table_)); + std::stable_sort(sorted_probabilities.begin(), sorted_probabilities.end(), + ProbabilityLess(&probability_table_)); if (total_rans_prob < rans_precision_) { // This happens rather infrequently, just add the extra needed precision // to the most frequent symbol. diff --git a/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc b/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc index 93d29971c89..79e81181830 100644 --- a/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc +++ b/extern/draco/draco/src/draco/compression/entropy/symbol_decoding.cc @@ -72,7 +72,7 @@ bool DecodeTaggedSymbols(uint32_t num_values, int num_components, int value_id = 0; for (uint32_t i = 0; i < num_values; i += num_components) { // Decode the tag. - const int bit_length = tag_decoder.DecodeSymbol(); + const uint32_t bit_length = tag_decoder.DecodeSymbol(); // Decode the actual value. for (int j = 0; j < num_components; ++j) { uint32_t val; diff --git a/extern/draco/draco/src/draco/compression/expert_encode.cc b/extern/draco/draco/src/draco/compression/expert_encode.cc index 4c70a72a765..f9aec15eb27 100644 --- a/extern/draco/draco/src/draco/compression/expert_encode.cc +++ b/extern/draco/draco/src/draco/compression/expert_encode.cc @@ -67,7 +67,7 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc, kd_tree_possible = false; } if (kd_tree_possible && att->data_type() == DT_FLOAT32 && - options().GetAttributeInt(0, "quantization_bits", -1) <= 0) { + options().GetAttributeInt(i, "quantization_bits", -1) <= 0) { kd_tree_possible = false; // Quantization not enabled. } if (!kd_tree_possible) { diff --git a/extern/draco/draco/src/draco/compression/expert_encode.h b/extern/draco/draco/src/draco/compression/expert_encode.h index a1aa7b8b3a8..ea59393d3d2 100644 --- a/extern/draco/draco/src/draco/compression/expert_encode.h +++ b/extern/draco/draco/src/draco/compression/expert_encode.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_ -#define DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_ +#ifndef DRACO_COMPRESSION_EXPERT_ENCODE_H_ +#define DRACO_COMPRESSION_EXPERT_ENCODE_H_ #include "draco/compression/config/compression_shared.h" #include "draco/compression/config/encoder_options.h" @@ -144,4 +144,4 @@ class ExpertEncoder : public EncoderBase { } // namespace draco -#endif // DRACO_SRC_DRACO_COMPRESSION_EXPERT_ENCODE_H_ +#endif // DRACO_COMPRESSION_EXPERT_ENCODE_H_ diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc index 50d1971c15b..6d22e2f2a32 100644 --- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc +++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_decoder_impl.cc @@ -162,6 +162,10 @@ bool MeshEdgebreakerDecoderImpl::CreateAttributesDecoder( if (!decoder_->buffer()->Decode(&traversal_method_encoded)) { return false; } + // Check that decoded traversal method is valid. + if (traversal_method_encoded >= NUM_TRAVERSAL_METHODS) { + return false; + } traversal_method = static_cast(traversal_method_encoded); } @@ -450,7 +454,7 @@ bool MeshEdgebreakerDecoderImpl::DecodeConnectivity() { #endif // Decode connectivity of non-position attributes. - if (attribute_data_.size() > 0) { + if (!attribute_data_.empty()) { #ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED if (decoder_->bitstream_version() < DRACO_BITSTREAM_VERSION(2, 1)) { for (CornerIndex ci(0); ci < corner_table_->num_corners(); ci += 3) { @@ -577,11 +581,16 @@ int MeshEdgebreakerDecoderImpl::DecodeConnectivity( SetOppositeCorners(corner_b, corner + 2); // Update vertex mapping. - corner_table_->MapCornerToVertex(corner, vertex_x); - corner_table_->MapCornerToVertex( - corner + 1, corner_table_->Vertex(corner_table_->Next(corner_b))); const VertexIndex vert_a_prev = corner_table_->Vertex(corner_table_->Previous(corner_a)); + const VertexIndex vert_b_next = + corner_table_->Vertex(corner_table_->Next(corner_b)); + if (vertex_x == vert_a_prev || vertex_x == vert_b_next) { + // Encoding is invalid, because face vertices are degenerate. + return -1; + } + corner_table_->MapCornerToVertex(corner, vertex_x); + corner_table_->MapCornerToVertex(corner + 1, vert_b_next); corner_table_->MapCornerToVertex(corner + 2, vert_a_prev); corner_table_->SetLeftMostCorner(vert_a_prev, corner + 2); // Mark the vertex |x| as interior. @@ -791,7 +800,7 @@ int MeshEdgebreakerDecoderImpl::DecodeConnectivity( return -1; // Unexpected number of decoded vertices. } // Decode start faces and connect them to the faces from the active stack. - while (active_corner_stack.size() > 0) { + while (!active_corner_stack.empty()) { const CornerIndex corner = active_corner_stack.back(); active_corner_stack.pop_back(); const bool interior_face = @@ -952,9 +961,13 @@ MeshEdgebreakerDecoderImpl::DecodeHoleAndTopologySplitEvents( for (uint32_t i = 0; i < num_topology_splits; ++i) { TopologySplitEventData event_data; uint32_t delta; - DecodeVarint(&delta, decoder_buffer); + if (!DecodeVarint(&delta, decoder_buffer)) { + return -1; + } event_data.source_symbol_id = delta + last_source_symbol_id; - DecodeVarint(&delta, decoder_buffer); + if (!DecodeVarint(&delta, decoder_buffer)) { + return -1; + } if (delta > event_data.source_symbol_id) { return -1; } @@ -1009,7 +1022,9 @@ MeshEdgebreakerDecoderImpl::DecodeHoleAndTopologySplitEvents( for (uint32_t i = 0; i < num_hole_events; ++i) { HoleEventData event_data; uint32_t delta; - DecodeVarint(&delta, decoder_buffer); + if (!DecodeVarint(&delta, decoder_buffer)) { + return -1; + } event_data.symbol_id = delta + last_symbol_id; last_symbol_id = event_data.symbol_id; hole_event_data_.push_back(event_data); diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc index 5aff5d8cc10..a7f381480f1 100644 --- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc +++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc @@ -31,7 +31,6 @@ bool MeshEdgebreakerEncoder::InitializeEncoder() { impl_ = nullptr; // For tiny meshes it's usually better to use the basic edgebreaker as the // overhead of the predictive one may turn out to be too big. - // TODO(b/111065939): Check if this can be improved. const bool is_tiny_mesh = mesh()->num_faces() < 1000; int selected_edgebreaker_method = diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc index 0791dc6705a..4bf6aa92070 100644 --- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc +++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc @@ -408,7 +408,7 @@ Status MeshEdgebreakerEncoderImpl::EncodeConnectivity() { init_face_connectivity_corners.begin(), init_face_connectivity_corners.end()); // Encode connectivity for all non-position attributes. - if (attribute_data_.size() > 0) { + if (!attribute_data_.empty()) { // Use the same order of corner that will be used by the decoder. visited_faces_.assign(mesh_->num_faces(), false); for (CornerIndex ci : processed_connectivity_corners_) { diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h index fb33771637e..979e1d373d8 100644 --- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h +++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h @@ -177,7 +177,6 @@ class MeshEdgebreakerEncoderImpl : public MeshEdgebreakerEncoderImplInterface { uint32_t num_split_symbols_; // Struct holding data used for encoding each non-position attribute. - // TODO(ostava): This should be probably renamed to something better. struct AttributeData { AttributeData() : attribute_index(-1), is_connectivity_used(true) {} int attribute_index; diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h index cb3c29dd669..c650bc35210 100644 --- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h +++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_shared.h @@ -50,8 +50,6 @@ namespace draco { // \ / S \ / / E \ // *-------* *-------* // -// TODO(ostava): Get rid of the topology bit pattern. It's important only for -// encoding but the algorithms should use EdgebreakerSymbol instead. enum EdgebreakerTopologyBitPattern { TOPOLOGY_C = 0x0, // 0 TOPOLOGY_S = 0x1, // 1 0 0 diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h index 621883a5f1f..c00373727df 100644 --- a/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h +++ b/extern/draco/draco/src/draco/compression/mesh/mesh_edgebreaker_traversal_valence_decoder.h @@ -106,7 +106,12 @@ class MeshEdgebreakerTraversalValenceDecoder context_counters_.resize(context_symbols_.size()); for (int i = 0; i < context_symbols_.size(); ++i) { uint32_t num_symbols; - DecodeVarint(&num_symbols, out_buffer); + if (!DecodeVarint(&num_symbols, out_buffer)) { + return false; + } + if (num_symbols > static_cast(corner_table_->num_faces())) { + return false; + } if (num_symbols > 0) { context_symbols_[i].resize(num_symbols); DecodeSymbols(num_symbols, 1, out_buffer, context_symbols_[i].data()); diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc index 53f5e8651b8..fbc7383eef1 100644 --- a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc +++ b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_decoder.cc @@ -53,6 +53,11 @@ bool MeshSequentialDecoder::DecodeConnectivity() { if (faces_64 > 0xffffffff / 3) { return false; } + if (faces_64 > buffer()->remaining_size() / 3) { + // The number of faces is unreasonably high, because face indices do not + // fit in the remaining size of the buffer. + return false; + } if (points_64 > faces_64 * 3) { return false; } @@ -91,7 +96,7 @@ bool MeshSequentialDecoder::DecodeConnectivity() { } mesh()->AddFace(face); } - } else if (mesh()->num_points() < (1 << 21) && + } else if (num_points < (1 << 21) && bitstream_version() >= DRACO_BITSTREAM_VERSION(2, 2)) { // Decode indices as uint32_t. for (uint32_t i = 0; i < num_faces; ++i) { diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc index 02ac7779ea3..fd8b1139253 100644 --- a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc +++ b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.cc @@ -32,8 +32,6 @@ Status MeshSequentialEncoder::EncodeConnectivity() { EncodeVarint(static_cast(mesh()->num_points()), buffer()); // We encode all attributes in the original (possibly duplicated) format. - // TODO(ostava): This may not be optimal if we have only one attribute or if - // all attributes share the same index mapping. if (options()->GetGlobalBool("compress_connectivity", false)) { // 0 = Encode compressed indices. buffer()->Encode(static_cast(0)); @@ -44,8 +42,6 @@ Status MeshSequentialEncoder::EncodeConnectivity() { // 1 = Encode indices directly. buffer()->Encode(static_cast(1)); // Store vertex indices using a smallest data type that fits their range. - // TODO(ostava): This can be potentially improved by using a tighter - // fit that is not bound by a bit-length of any particular data type. if (mesh()->num_points() < 256) { // Serialize indices as uint8_t. for (FaceIndex i(0); i < num_faces; ++i) { diff --git a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h index 672609642b0..6e2b05877ab 100644 --- a/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h +++ b/extern/draco/draco/src/draco/compression/mesh/mesh_sequential_encoder.h @@ -33,7 +33,6 @@ namespace draco { // Class that encodes mesh data using a simple binary representation of mesh's // connectivity and geometry. -// TODO(ostava): Use a better name. class MeshSequentialEncoder : public MeshEncoder { public: MeshSequentialEncoder(); diff --git a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h index e66dd14b238..dd9738ba2d5 100644 --- a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h +++ b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_attribute_indices_encoding_observer.h @@ -25,7 +25,7 @@ namespace draco { // values based on the traversal of the encoded mesh. The class should be used // as the TraversalObserverT member of a Traverser class such as the // DepthFirstTraverser (depth_first_traverser.h). -// TODO(hemmer): rename to AttributeIndicesCodingTraverserObserver +// TODO(b/199760123): Rename to AttributeIndicesCodingTraverserObserver. template class MeshAttributeIndicesEncodingObserver { public: diff --git a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h index ebe1d5f7a9e..e55c93a7969 100644 --- a/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h +++ b/extern/draco/draco/src/draco/compression/mesh/traverser/mesh_traversal_sequencer.h @@ -25,7 +25,7 @@ namespace draco { // Sequencer that generates point sequence in an order given by a deterministic // traversal on the mesh surface. Note that all attributes encoded with this // sequence must share the same connectivity. -// TODO(hemmer): Consider refactoring such that this is an observer. +// TODO(b/199760123): Consider refactoring such that this is an observer. template class MeshTraversalSequencer : public PointsSequencer { public: diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h index 87bc2b7ef3e..fa1b1e203e5 100644 --- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h +++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h @@ -227,7 +227,7 @@ bool DynamicIntegerPointsKdTreeDecoder::DecodeInternal( std::stack status_stack; status_stack.push(init_status); - // TODO(hemmer): use preallocated vector instead of stack. + // TODO(b/199760123): Use preallocated vector instead of stack. while (!status_stack.empty()) { const DecodingStatus status = status_stack.top(); status_stack.pop(); @@ -263,7 +263,8 @@ bool DynamicIntegerPointsKdTreeDecoder::DecodeInternal( // Fast decoding of remaining bits if number of points is 1 or 2. if (num_remaining_points <= 2) { - // TODO(hemmer): axes_ not necessary, remove would change bitstream! + // TODO(b/199760123): |axes_| not necessary, remove would change + // bitstream! axes_[0] = axis; for (uint32_t i = 1; i < dimension_; i++) { axes_[i] = DRACO_INCREMENT_MOD(axes_[i - 1], dimension_); diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h index 14fa32d7083..65b3d07a6ad 100644 --- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h +++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_encoder.h @@ -280,7 +280,7 @@ void DynamicIntegerPointsKdTreeEncoder::EncodeInternal( std::stack status_stack; status_stack.push(init_status); - // TODO(hemmer): use preallocated vector instead of stack. + // TODO(b/199760123): Use preallocated vector instead of stack. while (!status_stack.empty()) { Status status = status_stack.top(); status_stack.pop(); @@ -305,7 +305,8 @@ void DynamicIntegerPointsKdTreeEncoder::EncodeInternal( // Fast encoding of remaining bits if number of points is 1 or 2. // Doing this also for 2 gives a slight additional speed up. if (num_remaining_points <= 2) { - // TODO(hemmer): axes_ not necessary, remove would change bitstream! + // TODO(b/199760123): |axes_| not necessary, remove would change + // bitstream! axes_[0] = axis; for (uint32_t i = 1; i < dimension_; i++) { axes_[i] = DRACO_INCREMENT_MOD(axes_[i - 1], dimension_); diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc index 9e8d895f176..dffaa4c8d20 100644 --- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc +++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.cc @@ -69,18 +69,29 @@ FloatPointsTreeDecoder::FloatPointsTreeDecoder() bool FloatPointsTreeDecoder::DecodePointCloudKdTreeInternal( DecoderBuffer *buffer, std::vector *qpoints) { - if (!buffer->Decode(&qinfo_.quantization_bits)) return false; - if (qinfo_.quantization_bits > 31) return false; - if (!buffer->Decode(&qinfo_.range)) return false; - if (!buffer->Decode(&num_points_)) return false; - if (num_points_from_header_ > 0 && num_points_ != num_points_from_header_) + if (!buffer->Decode(&qinfo_.quantization_bits)) { return false; - if (!buffer->Decode(&compression_level_)) return false; + } + if (qinfo_.quantization_bits > 31) { + return false; + } + if (!buffer->Decode(&qinfo_.range)) { + return false; + } + if (!buffer->Decode(&num_points_)) { + return false; + } + if (num_points_from_header_ > 0 && num_points_ != num_points_from_header_) { + return false; + } + if (!buffer->Decode(&compression_level_)) { + return false; + } // Only allow compression level in [0..6]. if (6 < compression_level_) { - LOGE("FloatPointsTreeDecoder: compression level %i not supported.\n", - compression_level_); + DRACO_LOGE("FloatPointsTreeDecoder: compression level %i not supported.\n", + compression_level_); return false; } diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h index 26ba94f1f59..44c1b3d3a97 100644 --- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h +++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/float_points_tree_encoder.h @@ -44,7 +44,7 @@ namespace draco { // there are more leading zeros, which is then compressed better by the // arithmetic encoding. -// TODO(hemmer): Remove class because it duplicates quantization code. +// TODO(b/199760123): Remove class because it duplicates quantization code. class FloatPointsTreeEncoder { public: explicit FloatPointsTreeEncoder(PointCloudCompressionMethod method); @@ -91,7 +91,7 @@ bool FloatPointsTreeEncoder::EncodePointCloud(InputIteratorT points_begin, // Collect necessary data for encoding. num_points_ = std::distance(points_begin, points_end); - // TODO(hemmer): Extend quantization tools to make this more automatic. + // TODO(b/199760123): Extend quantization tools to make this more automatic. // Compute range of points for quantization std::vector qpoints; qpoints.reserve(num_points_); diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h index 94e523cadaf..bc31af58613 100644 --- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h +++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_decoder.h @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// TODO(hemmer): Make this a wrapper using DynamicIntegerPointsKdTreeDecoder. +// TODO(b/199760123): Make this a wrapper using +// DynamicIntegerPointsKdTreeDecoder. // // See integer_points_kd_tree_encoder.h for documentation. diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h index b8811092ed7..654f14a7866 100644 --- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h +++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/integer_points_kd_tree_encoder.h @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -// TODO(hemmer): Make this a wrapper using DynamicIntegerPointsKdTreeEncoder. +// TODO(b/199760123): Make this a wrapper using +// DynamicIntegerPointsKdTreeEncoder. #ifndef DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_ #define DRACO_COMPRESSION_POINT_CLOUD_ALGORITHMS_INTEGER_POINTS_KD_TREE_ENCODER_H_ diff --git a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h index 01943ad9e6c..04aa1d95e11 100644 --- a/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h +++ b/extern/draco/draco/src/draco/compression/point_cloud/algorithms/quantize_points_3.h @@ -22,7 +22,7 @@ namespace draco { -// TODO(hemmer): Make this a stable bounding box. +// TODO(b/199760123): Make this a stable bounding box. struct QuantizationInfo { uint32_t quantization_bits; float range; diff --git a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc index 5196edf960c..85f7bc94e33 100644 --- a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc +++ b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_decoder.cc @@ -88,7 +88,9 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options, const uint8_t max_supported_minor_version = header.encoder_type == POINT_CLOUD ? kDracoPointCloudBitstreamVersionMinor : kDracoMeshBitstreamVersionMinor; + // Check for version compatibility. +#ifdef DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED if (version_major_ < 1 || version_major_ > max_supported_major_version) { return Status(Status::UNKNOWN_VERSION, "Unknown major version."); } @@ -96,6 +98,14 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options, version_minor_ > max_supported_minor_version) { return Status(Status::UNKNOWN_VERSION, "Unknown minor version."); } +#else + if (version_major_ != max_supported_major_version) { + return Status(Status::UNKNOWN_VERSION, "Unsupported major version."); + } + if (version_minor_ != max_supported_minor_version) { + return Status(Status::UNKNOWN_VERSION, "Unsupported minor version."); + } +#endif buffer_->set_bitstream_version( DRACO_BITSTREAM_VERSION(version_major_, version_minor_)); diff --git a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc index b4b0ee94093..a1fda8d5a50 100644 --- a/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc +++ b/extern/draco/draco/src/draco/compression/point_cloud/point_cloud_encoder.cc @@ -62,12 +62,14 @@ Status PointCloudEncoder::EncodeHeader() { buffer_->Encode("DRACO", 5); // Version (major, minor). const uint8_t encoder_type = GetGeometryType(); - const uint8_t version_major = encoder_type == POINT_CLOUD - ? kDracoPointCloudBitstreamVersionMajor - : kDracoMeshBitstreamVersionMajor; - const uint8_t version_minor = encoder_type == POINT_CLOUD - ? kDracoPointCloudBitstreamVersionMinor - : kDracoMeshBitstreamVersionMinor; + uint8_t version_major, version_minor; + version_major = encoder_type == POINT_CLOUD + ? kDracoPointCloudBitstreamVersionMajor + : kDracoMeshBitstreamVersionMajor; + version_minor = encoder_type == POINT_CLOUD + ? kDracoPointCloudBitstreamVersionMinor + : kDracoMeshBitstreamVersionMinor; + buffer_->Encode(version_major); buffer_->Encode(version_minor); // Type of the encoder (point cloud, mesh, ...). diff --git a/extern/draco/draco/src/draco/core/bounding_box.cc b/extern/draco/draco/src/draco/core/bounding_box.cc index d95b1e90759..be0d209d857 100644 --- a/extern/draco/draco/src/draco/core/bounding_box.cc +++ b/extern/draco/draco/src/draco/core/bounding_box.cc @@ -16,8 +16,15 @@ namespace draco { -BoundingBox::BoundingBox(const Vector3f &min_point_in, - const Vector3f &max_point_in) - : min_point_(min_point_in), max_point_(max_point_in) {} +BoundingBox::BoundingBox() + : BoundingBox(Vector3f(std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max()), + Vector3f(std::numeric_limits::lowest(), + std::numeric_limits::lowest(), + std::numeric_limits::lowest())) {} + +BoundingBox::BoundingBox(const Vector3f &min_point, const Vector3f &max_point) + : min_point_(min_point), max_point_(max_point) {} } // namespace draco diff --git a/extern/draco/draco/src/draco/core/bounding_box.h b/extern/draco/draco/src/draco/core/bounding_box.h index 1c20fad8bf2..31ba2d68340 100644 --- a/extern/draco/draco/src/draco/core/bounding_box.h +++ b/extern/draco/draco/src/draco/core/bounding_box.h @@ -19,22 +19,27 @@ namespace draco { -// Class for detecting the bounding box of a point_cloud or mesh. -// Use the minimum point and the maximum point to define the bounding box. -// TODO(xiaoxumeng): Change the class of BoundingBox to a template, similar to -// draco/src/draco/core/vector_d.h +// Class for computing the bounding box of points in 3D space. class BoundingBox { public: - // Initialization - BoundingBox(const Vector3f &min_point_in, const Vector3f &max_point_in); + // Creates bounding box object with minimum and maximum points initialized to + // the largest positive and the smallest negative values, respectively. The + // resulting abstract bounding box effectively has no points and can be + // updated by providing any point to Update() method. + BoundingBox(); - inline const Vector3f &min_point() const { return min_point_; } - inline const Vector3f &max_point() const { return max_point_; } + // Creates bounding box object with minimum and maximum points initialized to + // |min_point| and |max_point|, respectively. + BoundingBox(const Vector3f &min_point, const Vector3f &max_point); - // Conditionally updates the bounding box. - // TODO(xiaoxumeng): Change the function to a template function and change the - // argument to an iterator. - inline void update_bounding_box(const Vector3f &new_point) { + // Returns the minimum point of the bounding box. + inline const Vector3f &GetMinPoint() const { return min_point_; } + + // Returns the maximum point of the bounding box. + inline const Vector3f &GetMaxPoint() const { return max_point_; } + + // Conditionally updates the bounding box with a given |new_point|. + void Update(const Vector3f &new_point) { for (int i = 0; i < 3; i++) { if (new_point[i] < min_point_[i]) { min_point_[i] = new_point[i]; @@ -45,6 +50,19 @@ class BoundingBox { } } + // Updates bounding box with minimum and maximum points of the |other| + // bounding box. + void Update(const BoundingBox &other) { + Update(other.GetMinPoint()); + Update(other.GetMaxPoint()); + } + + // Returns the size of the bounding box along each axis. + Vector3f Size() const { return max_point_ - min_point_; } + + // Returns the center of the bounding box. + Vector3f Center() const { return (min_point_ + max_point_) / 2; } + private: Vector3f min_point_; Vector3f max_point_; diff --git a/extern/draco/draco/src/draco/core/cycle_timer.cc b/extern/draco/draco/src/draco/core/cycle_timer.cc index 94b4b28b2f9..58df4df77de 100644 --- a/extern/draco/draco/src/draco/core/cycle_timer.cc +++ b/extern/draco/draco/src/draco/core/cycle_timer.cc @@ -17,31 +17,31 @@ namespace draco { void DracoTimer::Start() { #ifdef _WIN32 - QueryPerformanceCounter(&tv_start); + QueryPerformanceCounter(&tv_start_); #else - gettimeofday(&tv_start, nullptr); + gettimeofday(&tv_start_, nullptr); #endif } void DracoTimer::Stop() { #ifdef _WIN32 - QueryPerformanceCounter(&tv_end); + QueryPerformanceCounter(&tv_end_); #else - gettimeofday(&tv_end, nullptr); + gettimeofday(&tv_end_, nullptr); #endif } int64_t DracoTimer::GetInMs() { #ifdef _WIN32 LARGE_INTEGER elapsed = {0}; - elapsed.QuadPart = tv_end.QuadPart - tv_start.QuadPart; + elapsed.QuadPart = tv_end_.QuadPart - tv_start_.QuadPart; LARGE_INTEGER frequency = {0}; QueryPerformanceFrequency(&frequency); return elapsed.QuadPart * 1000 / frequency.QuadPart; #else - const int64_t seconds = (tv_end.tv_sec - tv_start.tv_sec) * 1000; - const int64_t milliseconds = (tv_end.tv_usec - tv_start.tv_usec) / 1000; + const int64_t seconds = (tv_end_.tv_sec - tv_start_.tv_sec) * 1000; + const int64_t milliseconds = (tv_end_.tv_usec - tv_start_.tv_usec) / 1000; return seconds + milliseconds; #endif } diff --git a/extern/draco/draco/src/draco/core/cycle_timer.h b/extern/draco/draco/src/draco/core/cycle_timer.h index 172f1c2e9b5..f480cc9d389 100644 --- a/extern/draco/draco/src/draco/core/cycle_timer.h +++ b/extern/draco/draco/src/draco/core/cycle_timer.h @@ -20,9 +20,10 @@ #define WIN32_LEAN_AND_MEAN #endif #include -typedef LARGE_INTEGER timeval; +typedef LARGE_INTEGER DracoTimeVal; #else #include +typedef timeval DracoTimeVal; #endif #include @@ -39,8 +40,8 @@ class DracoTimer { int64_t GetInMs(); private: - timeval tv_start; - timeval tv_end; + DracoTimeVal tv_start_; + DracoTimeVal tv_end_; }; typedef DracoTimer CycleTimer; diff --git a/extern/draco/draco/src/draco/core/data_buffer.cc b/extern/draco/draco/src/draco/core/data_buffer.cc index f0b43d67dbd..96a3787987c 100644 --- a/extern/draco/draco/src/draco/core/data_buffer.cc +++ b/extern/draco/draco/src/draco/core/data_buffer.cc @@ -52,7 +52,7 @@ void DataBuffer::Resize(int64_t size) { } void DataBuffer::WriteDataToStream(std::ostream &stream) { - if (data_.size() == 0) { + if (data_.empty()) { return; } stream.write(reinterpret_cast(data_.data()), data_.size()); diff --git a/extern/draco/draco/src/draco/core/decoder_buffer.h b/extern/draco/draco/src/draco/core/decoder_buffer.h index 0559abbe415..be98e52d60e 100644 --- a/extern/draco/draco/src/draco/core/decoder_buffer.h +++ b/extern/draco/draco/src/draco/core/decoder_buffer.h @@ -54,12 +54,11 @@ class DecoderBuffer { // Decodes up to 32 bits into out_val. Can be called only in between // StartBitDecoding and EndBitDecoding. Otherwise returns false. - bool DecodeLeastSignificantBits32(int nbits, uint32_t *out_value) { + bool DecodeLeastSignificantBits32(uint32_t nbits, uint32_t *out_value) { if (!bit_decoder_active()) { return false; } - bit_decoder_.GetBits(nbits, out_value); - return true; + return bit_decoder_.GetBits(nbits, out_value); } // Decodes an arbitrary data type. @@ -158,9 +157,10 @@ class DecoderBuffer { inline void ConsumeBits(int k) { bit_offset_ += k; } // Returns |nbits| bits in |x|. - inline bool GetBits(int32_t nbits, uint32_t *x) { - DRACO_DCHECK_GE(nbits, 0); - DRACO_DCHECK_LE(nbits, 32); + inline bool GetBits(uint32_t nbits, uint32_t *x) { + if (nbits > 32) { + return false; + } uint32_t value = 0; for (int32_t bit = 0; bit < nbits; ++bit) { value |= GetBit() << bit; diff --git a/extern/draco/draco/src/draco/core/draco_index_type_vector.h b/extern/draco/draco/src/draco/core/draco_index_type_vector.h index d47ab3b04eb..0fefc43b23d 100644 --- a/extern/draco/draco/src/draco/core/draco_index_type_vector.h +++ b/extern/draco/draco/src/draco/core/draco_index_type_vector.h @@ -28,7 +28,6 @@ namespace draco { // draco_index_type.h . // TODO(ostava): Make the interface more complete. It's currently missing // features such as iterators. -// TODO(vytyaz): Add more unit tests for this class. template class IndexTypeVector { public: @@ -56,7 +55,7 @@ class IndexTypeVector { void push_back(ValueTypeT &&val) { vector_.push_back(std::move(val)); } template - void emplace_back(Args &&... args) { + void emplace_back(Args &&...args) { vector_.emplace_back(std::forward(args)...); } diff --git a/extern/draco/draco/src/draco/core/draco_version.h b/extern/draco/draco/src/draco/core/draco_version.h index ffd7948c64d..5f2676ad7e9 100644 --- a/extern/draco/draco/src/draco/core/draco_version.h +++ b/extern/draco/draco/src/draco/core/draco_version.h @@ -18,7 +18,7 @@ namespace draco { // Draco version is comprised of ... -static const char kDracoVersion[] = "1.3.6"; +static const char kDracoVersion[] = "1.5.2"; const char *Version() { return kDracoVersion; } diff --git a/extern/draco/draco/src/draco/core/macros.h b/extern/draco/draco/src/draco/core/macros.h index 89b706e53a5..64647d129d5 100644 --- a/extern/draco/draco/src/draco/core/macros.h +++ b/extern/draco/draco/src/draco/core/macros.h @@ -21,11 +21,13 @@ #ifdef ANDROID_LOGGING #include #define LOG_TAG "draco" -#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) -#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) +#define DRACO_LOGI(...) \ + __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) +#define DRACO_LOGE(...) \ + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #else -#define LOGI printf -#define LOGE printf +#define DRACO_LOGI printf +#define DRACO_LOGE printf #endif #include @@ -88,6 +90,10 @@ namespace draco { #define DRACO_MACROS_IMPL_CONCAT_INNER_(x, y) x##y #define DRACO_MACROS_IMPL_CONCAT_(x, y) DRACO_MACROS_IMPL_CONCAT_INNER_(x, y) +#define DRACO_MACROS_IMPL_CONCAT_INNER_3_(x, y, z) x##y##z +#define DRACO_MACROS_IMPL_CONCAT_3_(x, y, z) \ + DRACO_MACROS_IMPL_CONCAT_INNER_3_(x, y, z) + // Expand the n-th argument of the macro. Used to select an argument based on // the number of entries in a variadic macro argument. Example usage: // @@ -98,13 +104,20 @@ namespace draco { // #define VARIADIC_MACRO(...) // DRACO_SELECT_NTH_FROM_3(__VA_ARGS__, FUNC_3, FUNC_2, FUNC_1) __VA_ARGS__ // -#define DRACO_SELECT_NTH_FROM_2(_1, _2, NAME) NAME -#define DRACO_SELECT_NTH_FROM_3(_1, _2, _3, NAME) NAME -#define DRACO_SELECT_NTH_FROM_4(_1, _2, _3, _4, NAME) NAME +#define DRACO_SELECT_NTH_FROM_2(_1, _2, NAME, ...) NAME +#define DRACO_SELECT_NTH_FROM_3(_1, _2, _3, NAME, ...) NAME +#define DRACO_SELECT_NTH_FROM_4(_1, _2, _3, _4, NAME, ...) NAME // Macro that converts the Draco bit-stream into one uint16_t number. // Useful mostly when checking version numbers. #define DRACO_BITSTREAM_VERSION(MAJOR, MINOR) \ ((static_cast(MAJOR) << 8) | MINOR) +// Macro that converts the uint16_t Draco bit-stream number into the major +// and minor components respectively. +#define DRACO_BISTREAM_VERSION_MAJOR(VERSION) \ + (static_cast(VERSION >> 8)) +#define DRACO_BISTREAM_VERSION_MINOR(VERSION) \ + (static_cast(VERSION & 0xFF)) + #endif // DRACO_CORE_MACROS_H_ diff --git a/extern/draco/draco/src/draco/core/options.h b/extern/draco/draco/src/draco/core/options.h index 1bc4dc0fb7b..9dc22ce16c2 100644 --- a/extern/draco/draco/src/draco/core/options.h +++ b/extern/draco/draco/src/draco/core/options.h @@ -71,8 +71,6 @@ class Options { private: // All entries are internally stored as strings and converted to the desired // return type based on the used Get* method. - // TODO(ostava): Consider adding type safety mechanism that would prevent - // unsafe operations such as a conversion from vector to int. std::map options_; }; diff --git a/extern/draco/draco/src/draco/core/status.h b/extern/draco/draco/src/draco/core/status.h index 449ad8566de..ee7f43ee59c 100644 --- a/extern/draco/draco/src/draco/core/status.h +++ b/extern/draco/draco/src/draco/core/status.h @@ -15,6 +15,7 @@ #ifndef DRACO_CORE_STATUS_H_ #define DRACO_CORE_STATUS_H_ +#include #include namespace draco { @@ -61,6 +62,9 @@ inline std::ostream &operator<<(std::ostream &os, const Status &status) { } inline Status OkStatus() { return Status(Status::OK); } +inline Status ErrorStatus(const std::string &msg) { + return Status(Status::DRACO_ERROR, msg); +} // Evaluates an expression that returns draco::Status. If the status is not OK, // the macro returns the status object. diff --git a/extern/draco/draco/src/draco/core/varint_decoding.h b/extern/draco/draco/src/draco/core/varint_decoding.h index 4e86df732e0..cff47e930b4 100644 --- a/extern/draco/draco/src/draco/core/varint_decoding.h +++ b/extern/draco/draco/src/draco/core/varint_decoding.h @@ -58,6 +58,7 @@ bool DecodeVarintUnsigned(int depth, IntTypeT *out_val, DecoderBuffer *buffer) { // Decodes a specified integer as varint. Note that the IntTypeT must be the // same as the one used in the corresponding EncodeVarint() call. +// out_val is undefined if this returns false. template bool DecodeVarint(IntTypeT *out_val, DecoderBuffer *buffer) { if (std::is_unsigned::value) { diff --git a/extern/draco/draco/src/draco/core/vector_d.h b/extern/draco/draco/src/draco/core/vector_d.h index bed97304feb..a0ec2dedf2e 100644 --- a/extern/draco/draco/src/draco/core/vector_d.h +++ b/extern/draco/draco/src/draco/core/vector_d.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "draco/core/macros.h" @@ -33,7 +34,7 @@ class VectorD { typedef ScalarT Scalar; typedef VectorD Self; - // TODO(hemmer): Deprecate. + // TODO(b/199760123): Deprecate. typedef ScalarT CoefficientType; VectorD() { @@ -44,7 +45,7 @@ class VectorD { // The following constructor does not compile in opt mode, which for now led // to the constructors further down, which is not ideal. - // TODO(hemmer): fix constructor below and remove others. + // TODO(b/199760123): Fix constructor below and remove others. // template // explicit VectorD(Args... args) : v_({args...}) {} @@ -110,7 +111,7 @@ class VectorD { Scalar &operator[](int i) { return v_[i]; } const Scalar &operator[](int i) const { return v_[i]; } - // TODO(hemmer): remove. + // TODO(b/199760123): Remove. // Similar to interface of Eigen library. Scalar &operator()(int i) { return v_[i]; } const Scalar &operator()(int i) const { return v_[i]; } @@ -236,7 +237,12 @@ class VectorD { Scalar AbsSum() const { Scalar result(0); for (int i = 0; i < dimension; ++i) { - result += std::abs(v_[i]); + Scalar next_value = std::abs(v_[i]); + if (result > std::numeric_limits::max() - next_value) { + // Return the max if adding would have caused an overflow. + return std::numeric_limits::max(); + } + result += next_value; } return result; } diff --git a/extern/draco/draco/src/draco/draco_features.h b/extern/draco/draco/src/draco/draco_features.h index 27e3d7f136a..d0a630e5465 100644 --- a/extern/draco/draco/src/draco/draco_features.h +++ b/extern/draco/draco/src/draco/draco_features.h @@ -4,7 +4,5 @@ #define DRACO_MESH_COMPRESSION_SUPPORTED #define DRACO_NORMAL_ENCODING_SUPPORTED #define DRACO_STANDARD_EDGEBREAKER_SUPPORTED -#define DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED -#define DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED #endif // DRACO_FEATURES_H_ diff --git a/extern/draco/draco/src/draco/mesh/corner_table.cc b/extern/draco/draco/src/draco/mesh/corner_table.cc index 6066e58bd8b..3f92f651ab6 100644 --- a/extern/draco/draco/src/draco/mesh/corner_table.cc +++ b/extern/draco/draco/src/draco/mesh/corner_table.cc @@ -66,12 +66,13 @@ bool CornerTable::Reset(int num_faces, int num_vertices) { if (num_faces < 0 || num_vertices < 0) { return false; } - if (static_cast(num_faces) > + const unsigned int num_faces_unsigned = num_faces; + if (num_faces_unsigned > std::numeric_limits::max() / 3) { return false; } - corner_to_vertex_map_.assign(num_faces * 3, kInvalidVertexIndex); - opposite_corners_.assign(num_faces * 3, kInvalidCornerIndex); + corner_to_vertex_map_.assign(num_faces_unsigned * 3, kInvalidVertexIndex); + opposite_corners_.assign(num_faces_unsigned * 3, kInvalidCornerIndex); vertex_corners_.reserve(num_vertices); valence_cache_.ClearValenceCache(); valence_cache_.ClearValenceCacheInaccurate(); diff --git a/extern/draco/draco/src/draco/mesh/mesh.h b/extern/draco/draco/src/draco/mesh/mesh.h index f4506da81c9..b1577c03986 100644 --- a/extern/draco/draco/src/draco/mesh/mesh.h +++ b/extern/draco/draco/src/draco/mesh/mesh.h @@ -119,6 +119,10 @@ class Mesh : public PointCloud { const std::vector &unique_point_ids) override; #endif + // Exposes |faces_|. Use |faces_| at your own risk. DO NOT store the + // reference: the |faces_| object is destroyed with the mesh. + IndexTypeVector &faces() { return faces_; } + private: // Mesh specific per-attribute data. std::vector attribute_data_; diff --git a/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h b/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h index 7dad25cf1d2..6f02453d2d4 100644 --- a/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h +++ b/extern/draco/draco/src/draco/mesh/mesh_attribute_corner_table.h @@ -130,6 +130,12 @@ class MeshAttributeCornerTable { return false; } + bool IsDegenerated(FaceIndex face) const { + // Introducing seams can't change the degeneracy of the individual faces, + // therefore we can delegate the check to the original |corner_table_|. + return corner_table_->IsDegenerated(face); + } + bool no_interior_seams() const { return no_interior_seams_; } const CornerTable *corner_table() const { return corner_table_; } diff --git a/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc b/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc index 773c1e18fe6..bc44c831c4e 100644 --- a/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc +++ b/extern/draco/draco/src/draco/mesh/mesh_cleanup.cc @@ -14,25 +14,42 @@ // #include "draco/mesh/mesh_cleanup.h" +#include + +#include "draco/core/hash_utils.h" + namespace draco { -bool MeshCleanup::operator()(Mesh *mesh, const MeshCleanupOptions &options) { - if (!options.remove_degenerated_faces && !options.remove_unused_attributes) { - return true; // Nothing to cleanup. +Status MeshCleanup::Cleanup(Mesh *mesh, const MeshCleanupOptions &options) { + if (!options.remove_degenerated_faces && !options.remove_unused_attributes && + !options.remove_duplicate_faces && !options.make_geometry_manifold) { + return OkStatus(); // Nothing to cleanup. } const PointAttribute *const pos_att = mesh->GetNamedAttribute(GeometryAttribute::POSITION); if (pos_att == nullptr) { - return false; + return Status(Status::DRACO_ERROR, "Missing position attribute."); } - // Array that is going to store whether a corresponding point is used. - std::vector is_point_used; + + if (options.remove_degenerated_faces) { + RemoveDegeneratedFaces(mesh); + } + + if (options.remove_duplicate_faces) { + RemoveDuplicateFaces(mesh); + } + if (options.remove_unused_attributes) { - is_point_used.resize(mesh->num_points(), false); + RemoveUnusedAttributes(mesh); } + return OkStatus(); +} + +void MeshCleanup::RemoveDegeneratedFaces(Mesh *mesh) { + const PointAttribute *const pos_att = + mesh->GetNamedAttribute(GeometryAttribute::POSITION); FaceIndex::ValueType num_degenerated_faces = 0; - PointIndex::ValueType num_new_points = 0; // Array for storing position indices on a face. std::array pos_indices; for (FaceIndex f(0); f < mesh->num_faces(); ++f) { @@ -40,149 +57,195 @@ bool MeshCleanup::operator()(Mesh *mesh, const MeshCleanupOptions &options) { for (int p = 0; p < 3; ++p) { pos_indices[p] = pos_att->mapped_index(face[p]); } - bool is_face_valid = true; - if (options.remove_degenerated_faces) { - if (pos_indices[0] == pos_indices[1] || - pos_indices[0] == pos_indices[2] || - pos_indices[1] == pos_indices[2]) { - ++num_degenerated_faces; - is_face_valid = false; - } else if (num_degenerated_faces > 0) { - // Copy the face to its new location. - mesh->SetFace(f - num_degenerated_faces, face); - } - } - if (options.remove_unused_attributes && is_face_valid) { - for (int p = 0; p < 3; ++p) { - if (!is_point_used[face[p].value()]) { - is_point_used[face[p].value()] = true; - ++num_new_points; - } - } + if (pos_indices[0] == pos_indices[1] || pos_indices[0] == pos_indices[2] || + pos_indices[1] == pos_indices[2]) { + ++num_degenerated_faces; + } else if (num_degenerated_faces > 0) { + // Copy the face to its new location. + mesh->SetFace(f - num_degenerated_faces, face); } } if (num_degenerated_faces > 0) { mesh->SetNumFaces(mesh->num_faces() - num_degenerated_faces); } - if (options.remove_unused_attributes) { - bool points_changed = false; - const PointIndex::ValueType num_original_points = mesh->num_points(); - // Map from old points to the new ones. - IndexTypeVector point_map(num_original_points); - if (num_new_points < static_cast(mesh->num_points())) { - // Some of the points were removed. We need to remap the old points to the - // new ones. - num_new_points = 0; - for (PointIndex i(0); i < num_original_points; ++i) { - if (is_point_used[i.value()]) { - point_map[i] = num_new_points++; - } else { - point_map[i] = kInvalidPointIndex; - } +} + +void MeshCleanup::RemoveDuplicateFaces(Mesh *mesh) { + const PointAttribute *const pos_att = + mesh->GetNamedAttribute(GeometryAttribute::POSITION); + + typedef std::array PosTriplet; + PosTriplet pos_indices; + std::unordered_set> is_face_used; + + uint32_t num_duplicate_faces = 0; + for (FaceIndex fi(0); fi < mesh->num_faces(); ++fi) { + const auto f = mesh->face(fi); + for (int c = 0; c < 3; ++c) { + pos_indices[c] = pos_att->mapped_index(f[c]).value(); + } + // Shift the position indices until the smallest index is the first one. + while (pos_indices[0] > pos_indices[1] || pos_indices[0] > pos_indices[2]) { + // Shift to the left. + std::swap(pos_indices[0], pos_indices[1]); + std::swap(pos_indices[1], pos_indices[2]); + } + // Check if have encountered the same position triplet on a different face. + if (is_face_used.find(pos_indices) != is_face_used.end()) { + // Duplicate face. Ignore it. + num_duplicate_faces++; + } else { + // Insert new face to the set. + is_face_used.insert(pos_indices); + if (num_duplicate_faces > 0) { + // Copy the face to its new location. + mesh->SetFace(fi - num_duplicate_faces, f); } - // Go over faces and update their points. - for (FaceIndex f(0); f < mesh->num_faces(); ++f) { - Mesh::Face face = mesh->face(f); - for (int p = 0; p < 3; ++p) { - face[p] = point_map[face[p]]; - } - mesh->SetFace(f, face); + } + } + if (num_duplicate_faces > 0) { + mesh->SetNumFaces(mesh->num_faces() - num_duplicate_faces); + } +} + +void MeshCleanup::RemoveUnusedAttributes(Mesh *mesh) { + // Array that is going to store whether a corresponding point is used. + std::vector is_point_used; + PointIndex::ValueType num_new_points = 0; + is_point_used.resize(mesh->num_points(), false); + for (FaceIndex f(0); f < mesh->num_faces(); ++f) { + const Mesh::Face &face = mesh->face(f); + for (int p = 0; p < 3; ++p) { + if (!is_point_used[face[p].value()]) { + is_point_used[face[p].value()] = true; + ++num_new_points; } - // Set the new number of points. - mesh->set_num_points(num_new_points); - points_changed = true; - } else { - // No points were removed. Initialize identity map between the old and new - // points. - for (PointIndex i(0); i < num_original_points; ++i) { - point_map[i] = i; + } + } + + bool points_changed = false; + const PointIndex::ValueType num_original_points = mesh->num_points(); + // Map from old points to the new ones. + IndexTypeVector point_map(num_original_points); + if (num_new_points < static_cast(mesh->num_points())) { + // Some of the points were removed. We need to remap the old points to the + // new ones. + num_new_points = 0; + for (PointIndex i(0); i < num_original_points; ++i) { + if (is_point_used[i.value()]) { + point_map[i] = num_new_points++; + } else { + point_map[i] = kInvalidPointIndex; + } + } + // Go over faces and update their points. + for (FaceIndex f(0); f < mesh->num_faces(); ++f) { + Mesh::Face face = mesh->face(f); + for (int p = 0; p < 3; ++p) { + face[p] = point_map[face[p]]; } + mesh->SetFace(f, face); } + // Set the new number of points. + mesh->set_num_points(num_new_points); + points_changed = true; + } else { + // No points were removed. Initialize identity map between the old and new + // points. + for (PointIndex i(0); i < num_original_points; ++i) { + point_map[i] = i; + } + } - // Update index mapping for attributes. - IndexTypeVector is_att_index_used; - IndexTypeVector att_index_map; - for (int a = 0; a < mesh->num_attributes(); ++a) { - PointAttribute *const att = mesh->attribute(a); - // First detect which attribute entries are used (included in a point). - is_att_index_used.assign(att->size(), 0); - att_index_map.clear(); - AttributeValueIndex::ValueType num_used_entries = 0; - for (PointIndex i(0); i < num_original_points; ++i) { - if (point_map[i] != kInvalidPointIndex) { - const AttributeValueIndex entry_id = att->mapped_index(i); - if (!is_att_index_used[entry_id]) { - is_att_index_used[entry_id] = 1; - ++num_used_entries; - } + // Update index mapping for attributes. + IndexTypeVector is_att_index_used; + IndexTypeVector att_index_map; + for (int a = 0; a < mesh->num_attributes(); ++a) { + PointAttribute *const att = mesh->attribute(a); + // First detect which attribute entries are used (included in a point). + is_att_index_used.assign(att->size(), 0); + att_index_map.clear(); + AttributeValueIndex::ValueType num_used_entries = 0; + for (PointIndex i(0); i < num_original_points; ++i) { + if (point_map[i] != kInvalidPointIndex) { + const AttributeValueIndex entry_id = att->mapped_index(i); + if (!is_att_index_used[entry_id]) { + is_att_index_used[entry_id] = 1; + ++num_used_entries; } } - bool att_indices_changed = false; - // If there are some unused attribute entries, remap the attribute values - // in the attribute buffer. - if (num_used_entries < static_cast(att->size())) { - att_index_map.resize(att->size()); - num_used_entries = 0; - for (AttributeValueIndex i(0); i < static_cast(att->size()); - ++i) { - if (is_att_index_used[i]) { - att_index_map[i] = num_used_entries; - if (i > num_used_entries) { - const uint8_t *const src_add = att->GetAddress(i); - att->buffer()->Write( - att->GetBytePos(AttributeValueIndex(num_used_entries)), - src_add, att->byte_stride()); - } - ++num_used_entries; + } + bool att_indices_changed = false; + // If there are some unused attribute entries, remap the attribute values + // in the attribute buffer. + if (num_used_entries < static_cast(att->size())) { + att_index_map.resize(att->size()); + num_used_entries = 0; + for (AttributeValueIndex i(0); i < static_cast(att->size()); + ++i) { + if (is_att_index_used[i]) { + att_index_map[i] = num_used_entries; + if (i > num_used_entries) { + const uint8_t *const src_add = att->GetAddress(i); + att->buffer()->Write( + att->GetBytePos(AttributeValueIndex(num_used_entries)), src_add, + att->byte_stride()); } + ++num_used_entries; } - // Update the number of unique entries in the vertex buffer. - att->Resize(num_used_entries); - att_indices_changed = true; } - // If either the points or attribute indices have changed, we need to - // update the attribute index mapping. - if (points_changed || att_indices_changed) { - if (att->is_mapping_identity()) { - // The mapping was identity. It'll remain identity only if the - // number of point and attribute indices is still the same. - if (num_used_entries != static_cast(mesh->num_points())) { - // We need to create an explicit mapping. - // First we need to initialize the explicit map to the original - // number of points to recreate the original identity map. - att->SetExplicitMapping(num_original_points); - // Set the entries of the explicit map to identity. - for (PointIndex::ValueType i = 0; i < num_original_points; ++i) { - att->SetPointMapEntry(PointIndex(i), AttributeValueIndex(i)); - } + // Update the number of unique entries in the vertex buffer. + att->Resize(num_used_entries); + att_indices_changed = true; + } + // If either the points or attribute indices have changed, we need to + // update the attribute index mapping. + if (points_changed || att_indices_changed) { + if (att->is_mapping_identity()) { + // The mapping was identity. It'll remain identity only if the + // number of point and attribute indices is still the same. + if (num_used_entries != static_cast(mesh->num_points())) { + // We need to create an explicit mapping. + // First we need to initialize the explicit map to the original + // number of points to recreate the original identity map. + att->SetExplicitMapping(num_original_points); + // Set the entries of the explicit map to identity. + for (PointIndex::ValueType i = 0; i < num_original_points; ++i) { + att->SetPointMapEntry(PointIndex(i), AttributeValueIndex(i)); } } - if (!att->is_mapping_identity()) { - // Explicit mapping between points and local attribute indices. - for (PointIndex i(0); i < num_original_points; ++i) { - // The new point id that maps to the currently processed attribute - // entry. - const PointIndex new_point_id = point_map[i]; - if (new_point_id == kInvalidPointIndex) { - continue; - } - // Index of the currently processed attribute entry in the original - // mesh. - const AttributeValueIndex original_entry_index = - att->mapped_index(i); - // New index of the same entry after unused entries were removed. - const AttributeValueIndex new_entry_index = - att_index_map[original_entry_index]; - att->SetPointMapEntry(new_point_id, new_entry_index); + } + if (!att->is_mapping_identity()) { + // Explicit mapping between points and local attribute indices. + for (PointIndex i(0); i < num_original_points; ++i) { + // The new point id that maps to the currently processed attribute + // entry. + const PointIndex new_point_id = point_map[i]; + if (new_point_id == kInvalidPointIndex) { + continue; } - // If the number of points changed, we need to set a new explicit map - // size. - att->SetExplicitMapping(mesh->num_points()); + // Index of the currently processed attribute entry in the original + // mesh. + const AttributeValueIndex original_entry_index = att->mapped_index(i); + // New index of the same entry after unused entries were removed. + const AttributeValueIndex new_entry_index = + att_indices_changed ? att_index_map[original_entry_index] + : original_entry_index; + + // Update the mapping. Note that the new point index is always smaller + // than the processed index |i|, making this operation safe. + att->SetPointMapEntry(new_point_id, new_entry_index); } + // If the number of points changed, we need to set a new explicit map + // size. + att->SetExplicitMapping(mesh->num_points()); } } } - return true; +} + +Status MeshCleanup::MakeGeometryManifold(Mesh *mesh) { + return Status(Status::DRACO_ERROR, "Unsupported function."); } } // namespace draco diff --git a/extern/draco/draco/src/draco/mesh/mesh_cleanup.h b/extern/draco/draco/src/draco/mesh/mesh_cleanup.h index b56129dce58..0acdc2ae5b8 100644 --- a/extern/draco/draco/src/draco/mesh/mesh_cleanup.h +++ b/extern/draco/draco/src/draco/mesh/mesh_cleanup.h @@ -15,27 +15,44 @@ #ifndef DRACO_MESH_MESH_CLEANUP_H_ #define DRACO_MESH_MESH_CLEANUP_H_ +#include "draco/core/status.h" #include "draco/mesh/mesh.h" namespace draco { // Options used by the MeshCleanup class. struct MeshCleanupOptions { - MeshCleanupOptions() - : remove_degenerated_faces(true), remove_unused_attributes(true) {} // If true, the cleanup tool removes any face where two or more vertices // share the same position index. - bool remove_degenerated_faces; + bool remove_degenerated_faces = true; + + // If true, the cleanup tool removes all duplicate faces. A pair of faces is + // duplicate if both faces share the same position indices on all vertices + // (that is, position values have to be duduplicated). Note that all + // non-position properties are currently ignored. + bool remove_duplicate_faces = true; + // If true, the cleanup tool removes any unused attribute value or unused // point id. For example, it can be used to remove isolated vertices. - bool remove_unused_attributes; + bool remove_unused_attributes = true; + + // If true, the cleanup tool splits vertices along non-manifold edges and + // vertices. This ensures that the connectivity defined by position indices + // is manifold. + bool make_geometry_manifold = false; }; // Tool that can be used for removing bad or unused data from draco::Meshes. class MeshCleanup { public: // Performs in-place cleanup of the input mesh according to the input options. - bool operator()(Mesh *mesh, const MeshCleanupOptions &options); + static Status Cleanup(Mesh *mesh, const MeshCleanupOptions &options); + + private: + static void RemoveDegeneratedFaces(Mesh *mesh); + static void RemoveDuplicateFaces(Mesh *mesh); + static void RemoveUnusedAttributes(Mesh *mesh); + static Status MakeGeometryManifold(Mesh *mesh); }; } // namespace draco diff --git a/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h b/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h index b450bc80cd8..0a3bcf49782 100644 --- a/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h +++ b/extern/draco/draco/src/draco/mesh/mesh_misc_functions.h @@ -67,7 +67,6 @@ inline bool IsCornerOppositeToAttributeSeam(CornerIndex ci, // Interpolates an attribute value on a face using given barycentric // coordinates. InterpolatedVectorT should be a VectorD that corresponds to the // values stored in the attribute. -// TODO(ostava): Find a better place for this. template InterpolatedVectorT ComputeInterpolatedAttributeValueOnMeshFace( const Mesh &mesh, const PointAttribute &attribute, FaceIndex fi, diff --git a/extern/draco/draco/src/draco/mesh/mesh_stripifier.h b/extern/draco/draco/src/draco/mesh/mesh_stripifier.h index 0c298f48e86..8e8d8d9f21f 100644 --- a/extern/draco/draco/src/draco/mesh/mesh_stripifier.h +++ b/extern/draco/draco/src/draco/mesh/mesh_stripifier.h @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. // -#ifndef DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_ -#define DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_ +#ifndef DRACO_MESH_MESH_STRIPIFIER_H_ +#define DRACO_MESH_MESH_STRIPIFIER_H_ #include "draco/mesh/mesh_misc_functions.h" @@ -71,8 +71,6 @@ class MeshStripifier { mesh_ = &mesh; num_strips_ = 0; num_encoded_faces_ = 0; - // TODO(ostava): We may be able to avoid computing the corner table if we - // already have it stored somewhere. corner_table_ = CreateCornerTableFromPositionAttribute(mesh_); if (corner_table_ == nullptr) { return false; @@ -257,4 +255,4 @@ bool MeshStripifier::GenerateTriangleStripsWithDegenerateTriangles( } // namespace draco -#endif // DRACO_SRC_DRACO_MESH_MESH_STRIPIFIER_H_ +#endif // DRACO_MESH_MESH_STRIPIFIER_H_ diff --git a/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc b/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc index 60b0c50b8d5..cb767f871a9 100644 --- a/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc +++ b/extern/draco/draco/src/draco/mesh/triangle_soup_mesh_builder.cc @@ -41,8 +41,6 @@ void TriangleSoupMeshBuilder::SetAttributeValuesForFace( att->SetAttributeValue(AttributeValueIndex(start_index), corner_value_0); att->SetAttributeValue(AttributeValueIndex(start_index + 1), corner_value_1); att->SetAttributeValue(AttributeValueIndex(start_index + 2), corner_value_2); - // TODO(ostava): The below code should be called only for one attribute. - // It will work OK even for multiple attributes, but it's redundant. mesh_->SetFace(face_id, {{PointIndex(start_index), PointIndex(start_index + 1), PointIndex(start_index + 2)}}); diff --git a/extern/draco/draco/src/draco/metadata/geometry_metadata.cc b/extern/draco/draco/src/draco/metadata/geometry_metadata.cc index b83898140ae..b6a882c0b1b 100644 --- a/extern/draco/draco/src/draco/metadata/geometry_metadata.cc +++ b/extern/draco/draco/src/draco/metadata/geometry_metadata.cc @@ -18,6 +18,19 @@ namespace draco { +AttributeMetadata::AttributeMetadata(const AttributeMetadata &metadata) + : Metadata(metadata) { + att_unique_id_ = metadata.att_unique_id_; +} + +GeometryMetadata::GeometryMetadata(const GeometryMetadata &metadata) + : Metadata(metadata) { + for (size_t i = 0; i < metadata.att_metadatas_.size(); ++i) { + att_metadatas_.push_back(std::unique_ptr( + new AttributeMetadata(*metadata.att_metadatas_[i]))); + } +} + const AttributeMetadata *GeometryMetadata::GetAttributeMetadataByStringEntry( const std::string &entry_name, const std::string &entry_value) const { for (auto &&att_metadata : att_metadatas_) { @@ -35,7 +48,7 @@ const AttributeMetadata *GeometryMetadata::GetAttributeMetadataByStringEntry( bool GeometryMetadata::AddAttributeMetadata( std::unique_ptr att_metadata) { - if (!att_metadata.get()) { + if (!att_metadata) { return false; } att_metadatas_.push_back(std::move(att_metadata)); diff --git a/extern/draco/draco/src/draco/metadata/geometry_metadata.h b/extern/draco/draco/src/draco/metadata/geometry_metadata.h index ec7ecb9ee68..531bdef2540 100644 --- a/extern/draco/draco/src/draco/metadata/geometry_metadata.h +++ b/extern/draco/draco/src/draco/metadata/geometry_metadata.h @@ -25,6 +25,7 @@ namespace draco { class AttributeMetadata : public Metadata { public: AttributeMetadata() : att_unique_id_(0) {} + AttributeMetadata(const AttributeMetadata &metadata); explicit AttributeMetadata(const Metadata &metadata) : Metadata(metadata), att_unique_id_(0) {} @@ -57,6 +58,7 @@ struct AttributeMetadataHasher { class GeometryMetadata : public Metadata { public: GeometryMetadata() {} + GeometryMetadata(const GeometryMetadata &metadata); explicit GeometryMetadata(const Metadata &metadata) : Metadata(metadata) {} const AttributeMetadata *GetAttributeMetadataByStringEntry( diff --git a/extern/draco/draco/src/draco/metadata/metadata.cc b/extern/draco/draco/src/draco/metadata/metadata.cc index 9141907ed71..51b4e93a328 100644 --- a/extern/draco/draco/src/draco/metadata/metadata.cc +++ b/extern/draco/draco/src/draco/metadata/metadata.cc @@ -122,6 +122,14 @@ const Metadata *Metadata::GetSubMetadata(const std::string &name) const { return sub_ptr->second.get(); } +Metadata *Metadata::sub_metadata(const std::string &name) { + auto sub_ptr = sub_metadatas_.find(name); + if (sub_ptr == sub_metadatas_.end()) { + return nullptr; + } + return sub_ptr->second.get(); +} + void Metadata::RemoveEntry(const std::string &name) { // Actually just remove "name", no need to check if it exists. auto entry_ptr = entries_.find(name); diff --git a/extern/draco/draco/src/draco/metadata/metadata.h b/extern/draco/draco/src/draco/metadata/metadata.h index 56d05e46a3e..12c1ba97439 100644 --- a/extern/draco/draco/src/draco/metadata/metadata.h +++ b/extern/draco/draco/src/draco/metadata/metadata.h @@ -147,6 +147,7 @@ class Metadata { bool AddSubMetadata(const std::string &name, std::unique_ptr sub_metadata); const Metadata *GetSubMetadata(const std::string &name) const; + Metadata *sub_metadata(const std::string &name); void RemoveEntry(const std::string &name); diff --git a/extern/draco/draco/src/draco/metadata/metadata_decoder.cc b/extern/draco/draco/src/draco/metadata/metadata_decoder.cc index e664e4fa524..a8e66f854cf 100644 --- a/extern/draco/draco/src/draco/metadata/metadata_decoder.cc +++ b/extern/draco/draco/src/draco/metadata/metadata_decoder.cc @@ -78,8 +78,10 @@ bool MetadataDecoder::DecodeMetadata(Metadata *metadata) { std::unique_ptr sub_metadata = std::unique_ptr(new Metadata()); metadata = sub_metadata.get(); - mp.parent_metadata->AddSubMetadata(sub_metadata_name, - std::move(sub_metadata)); + if (!mp.parent_metadata->AddSubMetadata(sub_metadata_name, + std::move(sub_metadata))) { + return false; + } } if (metadata == nullptr) { return false; @@ -98,6 +100,10 @@ bool MetadataDecoder::DecodeMetadata(Metadata *metadata) { if (!DecodeVarint(&num_sub_metadata, buffer_)) { return false; } + if (num_sub_metadata > buffer_->remaining_size()) { + // The decoded number of metadata items is unreasonably high. + return false; + } for (uint32_t i = 0; i < num_sub_metadata; ++i) { metadata_stack.push_back({metadata, nullptr}); } diff --git a/extern/draco/draco/src/draco/point_cloud/point_cloud.cc b/extern/draco/draco/src/draco/point_cloud/point_cloud.cc index 8eb638f80d4..55ad6670da5 100644 --- a/extern/draco/draco/src/draco/point_cloud/point_cloud.cc +++ b/extern/draco/draco/src/draco/point_cloud/point_cloud.cc @@ -241,7 +241,7 @@ void PointCloud::ApplyPointIdDeduplication( bool PointCloud::DeduplicateAttributeValues() { // Go over all attributes and create mapping between duplicate entries. if (num_points() == 0) { - return false; // Unexpected attribute size. + return true; // Nothing to deduplicate. } // Deduplicate all attributes. for (int32_t att_id = 0; att_id < num_attributes(); ++att_id) { @@ -253,17 +253,11 @@ bool PointCloud::DeduplicateAttributeValues() { } #endif -// TODO(xiaoxumeng): Consider to cash the BBox. +// TODO(b/199760503): Consider to cache the BBox. BoundingBox PointCloud::ComputeBoundingBox() const { - BoundingBox bounding_box = - BoundingBox(Vector3f(std::numeric_limits::max(), - std::numeric_limits::max(), - std::numeric_limits::max()), - Vector3f(-std::numeric_limits::max(), - -std::numeric_limits::max(), - -std::numeric_limits::max())); + BoundingBox bounding_box; auto pc_att = GetNamedAttribute(GeometryAttribute::POSITION); - // TODO(xiaoxumeng): Make the BoundingBox a template type, it may not be easy + // TODO(b/199760503): Make the BoundingBox a template type, it may not be easy // because PointCloud is not a template. // Or simply add some preconditioning here to make sure the position attribute // is valid, because the current code works only if the position attribute is @@ -274,7 +268,7 @@ BoundingBox PointCloud::ComputeBoundingBox() const { for (AttributeValueIndex i(0); i < static_cast(pc_att->size()); ++i) { pc_att->GetValue(i, &p[0]); - bounding_box.update_bounding_box(p); + bounding_box.Update(p); } return bounding_box; } diff --git a/extern/draco/patches/blender.patch b/extern/draco/patches/blender.patch new file mode 100644 index 00000000000..de39260367b --- /dev/null +++ b/extern/draco/patches/blender.patch @@ -0,0 +1,30 @@ +diff --git a/draco/src/draco/attributes/geometry_attribute.h b/draco/src/draco/attributes/geometry_attribute.h +index fd478a4..c1c0148 100644 +--- a/draco/src/draco/attributes/geometry_attribute.h ++++ b/draco/src/draco/attributes/geometry_attribute.h +@@ -285,11 +285,25 @@ class GeometryAttribute { + // Make sure the in_value fits within the range of values that OutT + // is able to represent. Perform the check only for integral types. + if (std::is_integral::value && std::is_integral::value) { ++#ifdef _MSC_VER ++# pragma warning(push) ++# pragma warning(disable:4804) ++#endif ++#if defined(__GNUC__) && !defined(__clang__) ++# pragma GCC diagnostic push ++# pragma GCC diagnostic ignored "-Wbool-compare" ++#endif + static constexpr OutT kOutMin = + std::is_signed::value ? std::numeric_limits::lowest() : 0; + if (in_value < kOutMin || in_value > std::numeric_limits::max()) { + return false; + } ++#ifdef __GNUC__ ++# pragma GCC diagnostic pop ++#endif ++#ifdef _MSC_VER ++# pragma warning(pop) ++#endif + } + + out_value[i] = static_cast(in_value); diff --git a/extern/draco/src/common.cpp b/extern/draco/src/common.cpp index 6f98d8db7ef..3a11c126ece 100644 --- a/extern/draco/src/common.cpp +++ b/extern/draco/src/common.cpp @@ -54,20 +54,20 @@ size_t getComponentByteLength(size_t componentType) { switch (componentType) { - case ComponentType::Byte: - case ComponentType::UnsignedByte: - return 1; - - case ComponentType::Short: - case ComponentType::UnsignedShort: - return 2; - - case ComponentType::UnsignedInt: - case ComponentType::Float: - return 4; - - default: - return 0; + case ComponentType::Byte: + case ComponentType::UnsignedByte: + return 1; + + case ComponentType::Short: + case ComponentType::UnsignedShort: + return 2; + + case ComponentType::UnsignedInt: + case ComponentType::Float: + return 4; + + default: + return 0; } } diff --git a/extern/draco/src/common.h b/extern/draco/src/common.h index beaf7d91adb..eef50596350 100644 --- a/extern/draco/src/common.h +++ b/extern/draco/src/common.h @@ -33,7 +33,7 @@ #define API(returnType) extern "C" returnType #endif -enum ComponentType: size_t +enum ComponentType : size_t { Byte = 5120, UnsignedByte = 5121, diff --git a/extern/draco/src/decoder.cpp b/extern/draco/src/decoder.cpp index 3f3e03bd9f2..e5ec2b65e6c 100644 --- a/extern/draco/src/decoder.cpp +++ b/extern/draco/src/decoder.cpp @@ -17,7 +17,6 @@ * @date 2020-11-18 */ - #include "decoder.h" #include @@ -30,7 +29,8 @@ #define LOG_PREFIX "DracoDecoder | " -struct Decoder { +struct Decoder +{ std::unique_ptr mesh; std::vector indexBuffer; std::map> buffers; @@ -54,20 +54,20 @@ bool decoderDecode(Decoder *decoder, void *data, size_t byteLength) draco::Decoder dracoDecoder; draco::DecoderBuffer dracoDecoderBuffer; dracoDecoderBuffer.Init(reinterpret_cast(data), byteLength); - + auto decoderStatus = dracoDecoder.DecodeMeshFromBuffer(&dracoDecoderBuffer); if (!decoderStatus.ok()) { printf(LOG_PREFIX "Error during Draco decoding: %s\n", decoderStatus.status().error_msg()); return false; } - + decoder->mesh = std::move(decoderStatus).value(); decoder->vertexCount = decoder->mesh->num_points(); decoder->indexCount = decoder->mesh->num_faces() * 3; - + printf(LOG_PREFIX "Decoded %" PRIu32 " vertices, %" PRIu32 " indices\n", decoder->vertexCount, decoder->indexCount); - + return true; } @@ -83,32 +83,32 @@ uint32_t decoderGetIndexCount(Decoder *decoder) bool decoderAttributeIsNormalized(Decoder *decoder, uint32_t id) { - const draco::PointAttribute* attribute = decoder->mesh->GetAttributeByUniqueId(id); + const draco::PointAttribute *attribute = decoder->mesh->GetAttributeByUniqueId(id); return attribute != nullptr && attribute->normalized(); } bool decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType) { - const draco::PointAttribute* attribute = decoder->mesh->GetAttributeByUniqueId(id); - + const draco::PointAttribute *attribute = decoder->mesh->GetAttributeByUniqueId(id); + if (attribute == nullptr) { printf(LOG_PREFIX "Attribute with id=%" PRIu32 " does not exist in Draco data\n", id); return false; } - + size_t stride = getAttributeStride(componentType, dataType); - + std::vector decodedData; decodedData.resize(stride * decoder->vertexCount); - + for (uint32_t i = 0; i < decoder->vertexCount; ++i) { auto index = attribute->mapped_index(draco::PointIndex(i)); uint8_t *value = decodedData.data() + i * stride; - + bool converted = false; - + switch (componentType) { case ComponentType::Byte: @@ -139,7 +139,7 @@ bool decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, c return false; } } - + decoder->buffers[id] = decodedData; return true; } @@ -166,13 +166,13 @@ void decoderCopyAttribute(Decoder *decoder, size_t id, void *output) } } -template +template void decodeIndices(Decoder *decoder) { std::vector decodedIndices; decodedIndices.resize(decoder->indexCount * sizeof(T)); T *typedView = reinterpret_cast(decodedIndices.data()); - + for (uint32_t faceIndex = 0; faceIndex < decoder->mesh->num_faces(); ++faceIndex) { const draco::Mesh::Face &face = decoder->mesh->face(draco::FaceIndex(faceIndex)); @@ -180,7 +180,7 @@ void decodeIndices(Decoder *decoder) typedView[faceIndex * 3 + 1] = face[1].value(); typedView[faceIndex * 3 + 2] = face[2].value(); } - + decoder->indexBuffer = decodedIndices; } @@ -188,26 +188,26 @@ bool decoderReadIndices(Decoder *decoder, size_t indexComponentType) { switch (indexComponentType) { - case ComponentType::Byte: - decodeIndices(decoder); - break; - case ComponentType::UnsignedByte: - decodeIndices(decoder); - break; - case ComponentType::Short: - decodeIndices(decoder); - break; - case ComponentType::UnsignedShort: - decodeIndices(decoder); - break; - case ComponentType::UnsignedInt: - decodeIndices(decoder); - break; - default: - printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType); - return false; + case ComponentType::Byte: + decodeIndices(decoder); + break; + case ComponentType::UnsignedByte: + decodeIndices(decoder); + break; + case ComponentType::Short: + decodeIndices(decoder); + break; + case ComponentType::UnsignedShort: + decodeIndices(decoder); + break; + case ComponentType::UnsignedInt: + decodeIndices(decoder); + break; + default: + printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType); + return false; } - + return true; } diff --git a/extern/draco/src/decoder.h b/extern/draco/src/decoder.h index 914eb776e8f..c154b426c59 100644 --- a/extern/draco/src/decoder.h +++ b/extern/draco/src/decoder.h @@ -28,26 +28,38 @@ struct Decoder; -API(Decoder *) decoderCreate(); +API(Decoder *) +decoderCreate(); -API(void) decoderRelease(Decoder *decoder); +API(void) +decoderRelease(Decoder *decoder); -API(bool) decoderDecode(Decoder *decoder, void *data, size_t byteLength); +API(bool) +decoderDecode(Decoder *decoder, void *data, size_t byteLength); -API(uint32_t) decoderGetVertexCount(Decoder *decoder); +API(uint32_t) +decoderGetVertexCount(Decoder *decoder); -API(uint32_t) decoderGetIndexCount(Decoder *decoder); +API(uint32_t) +decoderGetIndexCount(Decoder *decoder); -API(bool) decoderAttributeIsNormalized(Decoder *decoder, uint32_t id); +API(bool) +decoderAttributeIsNormalized(Decoder *decoder, uint32_t id); -API(bool) decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType); +API(bool) +decoderReadAttribute(Decoder *decoder, uint32_t id, size_t componentType, char *dataType); -API(size_t) decoderGetAttributeByteLength(Decoder *decoder, size_t id); +API(size_t) +decoderGetAttributeByteLength(Decoder *decoder, size_t id); -API(void) decoderCopyAttribute(Decoder *decoder, size_t id, void *output); +API(void) +decoderCopyAttribute(Decoder *decoder, size_t id, void *output); -API(bool) decoderReadIndices(Decoder *decoder, size_t indexComponentType); +API(bool) +decoderReadIndices(Decoder *decoder, size_t indexComponentType); -API(size_t) decoderGetIndicesByteLength(Decoder *decoder); +API(size_t) +decoderGetIndicesByteLength(Decoder *decoder); -API(void) decoderCopyIndices(Decoder *decoder, void *output); +API(void) +decoderCopyIndices(Decoder *decoder, void *output); diff --git a/extern/draco/src/encoder.cpp b/extern/draco/src/encoder.cpp index ff7570ecfcd..34282ced8c6 100644 --- a/extern/draco/src/encoder.cpp +++ b/extern/draco/src/encoder.cpp @@ -59,7 +59,8 @@ void encoderRelease(Encoder *encoder) delete encoder; } -void encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel) { +void encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel) +{ encoder->compressionLevel = compressionLevel; } @@ -75,7 +76,7 @@ void encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t no bool encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder) { printf(LOG_PREFIX "Preserve triangle order: %s\n", preserveTriangleOrder ? "yes" : "no"); - + draco::Encoder dracoEncoder; int speed = 10 - static_cast(encoder->compressionLevel); @@ -87,12 +88,12 @@ bool encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder) dracoEncoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR, encoder->quantization.color); dracoEncoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, encoder->quantization.generic); dracoEncoder.SetTrackEncodedProperties(true); - + if (preserveTriangleOrder) { dracoEncoder.SetEncodingMethod(draco::MESH_SEQUENTIAL_ENCODING); } - + auto encoderStatus = dracoEncoder.EncodeMeshToBuffer(encoder->mesh, &encoder->encoderBuffer); if (encoderStatus.ok()) { @@ -130,20 +131,19 @@ void encoderCopy(Encoder *encoder, uint8_t *data) memcpy(data, encoder->encoderBuffer.data(), encoder->encoderBuffer.size()); } -template +template void encodeIndices(Encoder *encoder, uint32_t indexCount, T *indices) { int face_count = indexCount / 3; encoder->mesh.SetNumFaces(static_cast(face_count)); encoder->rawSize += indexCount * sizeof(T); - + for (int i = 0; i < face_count; ++i) { draco::Mesh::Face face = { draco::PointIndex(indices[3 * i + 0]), draco::PointIndex(indices[3 * i + 1]), - draco::PointIndex(indices[3 * i + 2]) - }; + draco::PointIndex(indices[3 * i + 2])}; encoder->mesh.SetFace(draco::FaceIndex(static_cast(i)), face); } } @@ -152,23 +152,23 @@ void encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t ind { switch (indexComponentType) { - case ComponentType::Byte: - encodeIndices(encoder, indexCount, reinterpret_cast(indices)); - break; - case ComponentType::UnsignedByte: - encodeIndices(encoder, indexCount, reinterpret_cast(indices)); - break; - case ComponentType::Short: - encodeIndices(encoder, indexCount, reinterpret_cast(indices)); - break; - case ComponentType::UnsignedShort: - encodeIndices(encoder, indexCount, reinterpret_cast(indices)); - break; - case ComponentType::UnsignedInt: - encodeIndices(encoder, indexCount, reinterpret_cast(indices)); - break; - default: - printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType); + case ComponentType::Byte: + encodeIndices(encoder, indexCount, reinterpret_cast(indices)); + break; + case ComponentType::UnsignedByte: + encodeIndices(encoder, indexCount, reinterpret_cast(indices)); + break; + case ComponentType::Short: + encodeIndices(encoder, indexCount, reinterpret_cast(indices)); + break; + case ComponentType::UnsignedShort: + encodeIndices(encoder, indexCount, reinterpret_cast(indices)); + break; + case ComponentType::UnsignedInt: + encodeIndices(encoder, indexCount, reinterpret_cast(indices)); + break; + default: + printf(LOG_PREFIX "Index component type %zu not supported\n", indexComponentType); } } @@ -190,7 +190,7 @@ draco::GeometryAttribute::Type getAttributeSemantics(char *attribute) { return draco::GeometryAttribute::COLOR; } - + return draco::GeometryAttribute::GENERIC; } @@ -198,37 +198,38 @@ draco::DataType getDataType(size_t componentType) { switch (componentType) { - case ComponentType::Byte: - return draco::DataType::DT_INT8; - - case ComponentType::UnsignedByte: - return draco::DataType::DT_UINT8; - - case ComponentType::Short: - return draco::DataType::DT_INT16; - - case ComponentType::UnsignedShort: - return draco::DataType::DT_UINT16; - - case ComponentType::UnsignedInt: - return draco::DataType::DT_UINT32; - - case ComponentType::Float: - return draco::DataType::DT_FLOAT32; - - default: - return draco::DataType::DT_INVALID; + case ComponentType::Byte: + return draco::DataType::DT_INT8; + + case ComponentType::UnsignedByte: + return draco::DataType::DT_UINT8; + + case ComponentType::Short: + return draco::DataType::DT_INT16; + + case ComponentType::UnsignedShort: + return draco::DataType::DT_UINT16; + + case ComponentType::UnsignedInt: + return draco::DataType::DT_UINT32; + + case ComponentType::Float: + return draco::DataType::DT_FLOAT32; + + default: + return draco::DataType::DT_INVALID; } } -API(uint32_t) encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data) +API(uint32_t) +encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data) { auto buffer = std::make_unique(); uint32_t count = encoder->mesh.num_points(); size_t componentCount = getNumberOfComponents(dataType); size_t stride = getAttributeStride(componentType, dataType); draco::DataType dracoDataType = getDataType(componentType); - + draco::GeometryAttribute::Type semantics = getAttributeSemantics(attributeName); draco::GeometryAttribute attribute; attribute.Init(semantics, &*buffer, componentCount, getDataType(componentType), false, stride, 0); diff --git a/extern/draco/src/encoder.h b/extern/draco/src/encoder.h index 2f7f21a469b..c6fdc30295b 100644 --- a/extern/draco/src/encoder.h +++ b/extern/draco/src/encoder.h @@ -28,24 +28,35 @@ struct Encoder; -API(Encoder *) encoderCreate(uint32_t vertexCount); +API(Encoder *) +encoderCreate(uint32_t vertexCount); -API(void) encoderRelease(Encoder *encoder); +API(void) +encoderRelease(Encoder *encoder); -API(void) encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel); +API(void) +encoderSetCompressionLevel(Encoder *encoder, uint32_t compressionLevel); -API(void) encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t normal, uint32_t uv, uint32_t color, uint32_t generic); +API(void) +encoderSetQuantizationBits(Encoder *encoder, uint32_t position, uint32_t normal, uint32_t uv, uint32_t color, uint32_t generic); -API(bool) encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder); +API(bool) +encoderEncode(Encoder *encoder, uint8_t preserveTriangleOrder); -API(uint64_t) encoderGetByteLength(Encoder *encoder); +API(uint64_t) +encoderGetByteLength(Encoder *encoder); -API(void) encoderCopy(Encoder *encoder, uint8_t *data); +API(void) +encoderCopy(Encoder *encoder, uint8_t *data); -API(void) encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t indexCount, void *indices); +API(void) +encoderSetIndices(Encoder *encoder, size_t indexComponentType, uint32_t indexCount, void *indices); -API(uint32_t) encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data); +API(uint32_t) +encoderSetAttribute(Encoder *encoder, char *attributeName, size_t componentType, char *dataType, void *data); -API(uint32_t) encoderGetEncodedVertexCount(Encoder *encoder); +API(uint32_t) +encoderGetEncodedVertexCount(Encoder *encoder); -API(uint32_t) encoderGetEncodedIndexCount(Encoder *encoder); +API(uint32_t) +encoderGetEncodedIndexCount(Encoder *encoder); -- cgit v1.2.3