diff options
author | Jim Eckerlein <UX3D-eckerlein> | 2019-12-05 21:11:53 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-12-05 21:12:10 +0300 |
commit | 9febff7e14c564fc560f48626817350a1bf8086f (patch) | |
tree | 36ea267182f0b243bd412ff5a2379ef6ee56ca8b /extern/draco | |
parent | 05ef758f46ae30b6d3a9e35fa8a2558d1216bee9 (diff) |
glTF: upgrade Draco to version 1.3.5 and add mesh skinning support
This will fix exporting meshes with armatures using Draco compression, like:
https://github.com/KhronosGroup/glTF-Blender-IO/issues/617
Differential Revision: https://developer.blender.org/D6342
Diffstat (limited to 'extern/draco')
81 files changed, 1208 insertions, 659 deletions
diff --git a/extern/draco/CMakeLists.txt b/extern/draco/CMakeLists.txt index c51af24c9a4..1355766960a 100644 --- a/extern/draco/CMakeLists.txt +++ b/extern/draco/CMakeLists.txt @@ -24,6 +24,6 @@ set(CMAKE_CXX_STANDARD 14) add_subdirectory(dracoenc) # Build blender-draco-exporter module. -add_library(extern_draco SHARED src/draco-compressor.cpp) +add_library(extern_draco SHARED src/draco-compressor.cpp src/draco-compressor.h) target_include_directories(extern_draco PUBLIC dracoenc/src) target_link_libraries(extern_draco PUBLIC dracoenc) diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc b/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc index 41193f1452f..237becefc61 100644 --- a/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc +++ b/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc @@ -92,6 +92,11 @@ bool AttributeQuantizationTransform::ComputeParameters( range_ = dif; } + // In case all values are the same, initialize the range to unit length. This + // will ensure that all values are quantized properly to the same value. + if (range_ == 0.f) + range_ = 1.f; + return true; } diff --git a/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h b/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h index 5244056f0aa..80e43e30a13 100644 --- a/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h +++ b/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h @@ -28,11 +28,11 @@ DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, AttributeValueIndex) // Index of a point in a PointCloud. DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, PointIndex) // Vertex index in a Mesh or CornerTable. -DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, VertexIndex); +DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, VertexIndex) // Corner index that identifies a corner in a Mesh or CornerTable. -DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, CornerIndex); +DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, CornerIndex) // Face index for Mesh and CornerTable. -DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, FaceIndex); +DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, FaceIndex) // Constants denoting invalid indices. static constexpr AttributeValueIndex kInvalidAttributeValueIndex( diff --git a/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc b/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc index 4428f332b93..0c4e8e1c738 100644 --- a/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc +++ b/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc @@ -64,7 +64,7 @@ bool PointAttribute::Reset(size_t num_attribute_values) { return true; } -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED AttributeValueIndex::ValueType PointAttribute::DeduplicateValues( const GeometryAttribute &in_att) { return DeduplicateValues(in_att, AttributeValueIndex(0)); diff --git a/extern/draco/dracoenc/src/draco/attributes/point_attribute.h b/extern/draco/dracoenc/src/draco/attributes/point_attribute.h index dffde50356d..46e58a40aa1 100644 --- a/extern/draco/dracoenc/src/draco/attributes/point_attribute.h +++ b/extern/draco/dracoenc/src/draco/attributes/point_attribute.h @@ -105,7 +105,7 @@ class PointAttribute : public GeometryAttribute { return GetValue(mapped_index(point_index), out_data); } -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED // Deduplicate |in_att| values into |this| attribute. |in_att| can be equal // to |this|. // Returns -1 if the deduplication failed. @@ -130,7 +130,7 @@ class PointAttribute : public GeometryAttribute { } private: -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED template <typename T> AttributeValueIndex::ValueType DeduplicateTypedValues( const GeometryAttribute &in_att, AttributeValueIndex in_att_offset); diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h b/extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h index 4148770fe77..ce99c8014d7 100644 --- a/extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h +++ b/extern/draco/dracoenc/src/draco/compression/attributes/point_d_vector.h @@ -42,7 +42,7 @@ class PseudoPointD { // Specifically copies referenced memory void swap(PseudoPointD &other) noexcept { - for (auto dim = 0; dim < dimension_; dim += 1) + for (internal_t dim = 0; dim < dimension_; dim += 1) std::swap(mem_[dim], other.mem_[dim]); } diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h index 3a00bda943c..db835554385 100644 --- a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h +++ b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_decoder_factory.h @@ -21,7 +21,9 @@ #include "draco/draco_features.h" #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_decoder.h" +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_decoder.h" +#endif #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_decoder.h" #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_decoder.h" #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_decoder.h" @@ -82,16 +84,20 @@ struct MeshPredictionSchemeDecoderFactory { new MeshPredictionSchemeTexCoordsPortableDecoder< DataTypeT, TransformT, MeshDataT>(attribute, transform, mesh_data)); - } else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { + } +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED + else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { return std::unique_ptr<PredictionSchemeDecoder<DataTypeT, TransformT>>( new MeshPredictionSchemeGeometricNormalDecoder< DataTypeT, TransformT, MeshDataT>(attribute, transform, mesh_data)); } +#endif return nullptr; } }; +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED // Operator () specialized for normal octahedron transforms. These transforms // are currently used only by the geometric normal prediction scheme (the // transform is also used by delta coding, but delta predictor is not @@ -128,6 +134,7 @@ struct MeshPredictionSchemeDecoderFactory { return nullptr; } }; +#endif template <class TransformT, class MeshDataT> std::unique_ptr<PredictionSchemeDecoder<DataTypeT, TransformT>> operator()( diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc index 3144bdb9a6b..6b74e571c6d 100644 --- a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc +++ b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.cc @@ -32,10 +32,12 @@ PredictionSchemeMethod SelectPredictionMethod( } } if (att->attribute_type() == GeometryAttribute::NORMAL) { +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED if (encoder->options()->GetSpeed() < 4) { // Use geometric normal prediction for speeds 0, 1, 2, 3. return MESH_PREDICTION_GEOMETRIC_NORMAL; } +#endif return PREDICTION_DIFFERENCE; // default } // Handle other attribute types. diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h index cde5ba2435f..4cc40010773 100644 --- a/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h +++ b/extern/draco/dracoenc/src/draco/compression/attributes/prediction_schemes/prediction_scheme_encoder_factory.h @@ -19,7 +19,9 @@ #define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_PREDICTION_SCHEME_ENCODER_FACTORY_H_ #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_constrained_multi_parallelogram_encoder.h" +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_geometric_normal_encoder.h" +#endif #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_multi_parallelogram_encoder.h" #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_parallelogram_encoder.h" #include "draco/compression/attributes/prediction_schemes/mesh_prediction_scheme_tex_coords_encoder.h" @@ -49,32 +51,25 @@ struct MeshPredictionSchemeEncoderFactory { new MeshPredictionSchemeParallelogramEncoder<DataTypeT, TransformT, MeshDataT>( attribute, transform, mesh_data)); - } else if (method == MESH_PREDICTION_MULTI_PARALLELOGRAM) { - return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>( - new MeshPredictionSchemeMultiParallelogramEncoder< - DataTypeT, TransformT, MeshDataT>(attribute, transform, - mesh_data)); } else if (method == MESH_PREDICTION_CONSTRAINED_MULTI_PARALLELOGRAM) { return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>( new MeshPredictionSchemeConstrainedMultiParallelogramEncoder< DataTypeT, TransformT, MeshDataT>(attribute, transform, mesh_data)); - } else if (method == MESH_PREDICTION_TEX_COORDS_DEPRECATED) { - return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>( - new MeshPredictionSchemeTexCoordsEncoder<DataTypeT, TransformT, - MeshDataT>( - attribute, transform, mesh_data)); } else if (method == MESH_PREDICTION_TEX_COORDS_PORTABLE) { return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>( new MeshPredictionSchemeTexCoordsPortableEncoder< DataTypeT, TransformT, MeshDataT>(attribute, transform, mesh_data)); - } else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { + } +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED + else if (method == MESH_PREDICTION_GEOMETRIC_NORMAL) { return std::unique_ptr<PredictionSchemeEncoder<DataTypeT, TransformT>>( new MeshPredictionSchemeGeometricNormalEncoder<DataTypeT, TransformT, MeshDataT>( attribute, transform, mesh_data)); } +#endif return nullptr; } }; diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc b/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc index fcd295039f6..2676eb7905c 100644 --- a/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc +++ b/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_decoders_controller.cc @@ -13,7 +13,9 @@ // limitations under the License. // #include "draco/compression/attributes/sequential_attribute_decoders_controller.h" +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED #include "draco/compression/attributes/sequential_normal_attribute_decoder.h" +#endif #include "draco/compression/attributes/sequential_quantization_attribute_decoder.h" #include "draco/compression/config/compression_shared.h" @@ -123,9 +125,11 @@ SequentialAttributeDecodersController::CreateSequentialDecoder( case SEQUENTIAL_ATTRIBUTE_ENCODER_QUANTIZATION: return std::unique_ptr<SequentialAttributeDecoder>( new SequentialQuantizationAttributeDecoder()); +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED case SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS: return std::unique_ptr<SequentialNormalAttributeDecoder>( new SequentialNormalAttributeDecoder()); +#endif default: break; } diff --git a/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc b/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc index 467508b226f..b40cef842ae 100644 --- a/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc +++ b/extern/draco/dracoenc/src/draco/compression/attributes/sequential_attribute_encoders_controller.cc @@ -13,7 +13,9 @@ // limitations under the License. // #include "draco/compression/attributes/sequential_attribute_encoders_controller.h" +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED #include "draco/compression/attributes/sequential_normal_attribute_encoder.h" +#endif #include "draco/compression/attributes/sequential_quantization_attribute_encoder.h" #include "draco/compression/point_cloud/point_cloud_encoder.h" @@ -121,15 +123,19 @@ SequentialAttributeEncodersController::CreateSequentialEncoder(int i) { case DT_FLOAT32: if (encoder()->options()->GetAttributeInt(att_id, "quantization_bits", -1) > 0) { +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED if (att->attribute_type() == GeometryAttribute::NORMAL) { // We currently only support normals with float coordinates // and must be quantized. return std::unique_ptr<SequentialAttributeEncoder>( new SequentialNormalAttributeEncoder()); } else { +#endif return std::unique_ptr<SequentialAttributeEncoder>( new SequentialQuantizationAttributeEncoder()); +#ifdef DRACO_NORMAL_ENCODING_SUPPORTED } +#endif } break; default: diff --git a/extern/draco/dracoenc/src/draco/compression/decode.cc b/extern/draco/dracoenc/src/draco/compression/decode.cc index a9ac2d5025f..ab70ef1ec60 100644 --- a/extern/draco/dracoenc/src/draco/compression/decode.cc +++ b/extern/draco/dracoenc/src/draco/compression/decode.cc @@ -37,7 +37,7 @@ StatusOr<std::unique_ptr<PointCloudDecoder>> CreatePointCloudDecoder( } else if (method == POINT_CLOUD_KD_TREE_ENCODING) { return std::unique_ptr<PointCloudDecoder>(new PointCloudKdTreeDecoder()); } - return Status(Status::ERROR, "Unsupported encoding method."); + return Status(Status::DRACO_ERROR, "Unsupported encoding method."); } #endif @@ -48,7 +48,7 @@ StatusOr<std::unique_ptr<MeshDecoder>> CreateMeshDecoder(uint8_t method) { } else if (method == MESH_EDGEBREAKER_ENCODING) { return std::unique_ptr<MeshDecoder>(new MeshEdgebreakerDecoder()); } - return Status(Status::ERROR, "Unsupported encoding method."); + return Status(Status::DRACO_ERROR, "Unsupported encoding method."); } #endif @@ -77,7 +77,7 @@ StatusOr<std::unique_ptr<PointCloud>> Decoder::DecodePointCloudFromBuffer( return static_cast<std::unique_ptr<PointCloud>>(std::move(mesh)); #endif } - return Status(Status::ERROR, "Unsupported geometry type."); + return Status(Status::DRACO_ERROR, "Unsupported geometry type."); } StatusOr<std::unique_ptr<Mesh>> Decoder::DecodeMeshFromBuffer( @@ -94,7 +94,7 @@ Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer, DracoHeader header; DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header)) if (header.encoder_type != POINT_CLOUD) { - return Status(Status::ERROR, "Input is not a point cloud."); + return Status(Status::DRACO_ERROR, "Input is not a point cloud."); } DRACO_ASSIGN_OR_RETURN(std::unique_ptr<PointCloudDecoder> decoder, CreatePointCloudDecoder(header.encoder_method)) @@ -102,7 +102,7 @@ Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer, DRACO_RETURN_IF_ERROR(decoder->Decode(options_, in_buffer, out_geometry)) return OkStatus(); #else - return Status(Status::ERROR, "Unsupported geometry type."); + return Status(Status::DRACO_ERROR, "Unsupported geometry type."); #endif } @@ -113,7 +113,7 @@ Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer, DracoHeader header; DRACO_RETURN_IF_ERROR(PointCloudDecoder::DecodeHeader(&temp_buffer, &header)) if (header.encoder_type != TRIANGULAR_MESH) { - return Status(Status::ERROR, "Input is not a mesh."); + return Status(Status::DRACO_ERROR, "Input is not a mesh."); } DRACO_ASSIGN_OR_RETURN(std::unique_ptr<MeshDecoder> decoder, CreateMeshDecoder(header.encoder_method)) @@ -121,7 +121,7 @@ Status Decoder::DecodeBufferToGeometry(DecoderBuffer *in_buffer, DRACO_RETURN_IF_ERROR(decoder->Decode(options_, in_buffer, out_geometry)) return OkStatus(); #else - return Status(Status::ERROR, "Unsupported geometry type."); + return Status(Status::DRACO_ERROR, "Unsupported geometry type."); #endif } diff --git a/extern/draco/dracoenc/src/draco/compression/decode.h b/extern/draco/dracoenc/src/draco/compression/decode.h index 9e24ce8d5d6..0216d72586a 100644 --- a/extern/draco/dracoenc/src/draco/compression/decode.h +++ b/extern/draco/dracoenc/src/draco/compression/decode.h @@ -20,7 +20,7 @@ #include "draco/compression/config/compression_shared.h" #include "draco/compression/config/decoder_options.h" #include "draco/core/decoder_buffer.h" -#include "draco/core/statusor.h" +#include "draco/core/status_or.h" #include "draco/mesh/mesh.h" namespace draco { diff --git a/extern/draco/dracoenc/src/draco/compression/encode_base.h b/extern/draco/dracoenc/src/draco/compression/encode_base.h index fa263f8fa3d..451d970eb6f 100644 --- a/extern/draco/dracoenc/src/draco/compression/encode_base.h +++ b/extern/draco/dracoenc/src/draco/compression/encode_base.h @@ -68,23 +68,28 @@ class EncoderBase { Status CheckPredictionScheme(GeometryAttribute::Type att_type, int prediction_scheme) const { // Out of bound checks: - if (prediction_scheme < 0) - return Status(Status::ERROR, "Invalid prediction scheme requested."); + if (prediction_scheme < PREDICTION_NONE) + return Status(Status::DRACO_ERROR, + "Invalid prediction scheme requested."); if (prediction_scheme >= NUM_PREDICTION_SCHEMES) - return Status(Status::ERROR, "Invalid prediction scheme requested."); + return Status(Status::DRACO_ERROR, + "Invalid prediction scheme requested."); // Deprecated prediction schemes: if (prediction_scheme == MESH_PREDICTION_TEX_COORDS_DEPRECATED) - return Status(Status::ERROR, + return Status(Status::DRACO_ERROR, "MESH_PREDICTION_TEX_COORDS_DEPRECATED is deprecated."); + if (prediction_scheme == MESH_PREDICTION_MULTI_PARALLELOGRAM) + return Status(Status::DRACO_ERROR, + "MESH_PREDICTION_MULTI_PARALLELOGRAM is deprecated."); // Attribute specific checks: if (prediction_scheme == MESH_PREDICTION_TEX_COORDS_PORTABLE) { if (att_type != GeometryAttribute::TEX_COORD) - return Status(Status::ERROR, + return Status(Status::DRACO_ERROR, "Invalid prediction scheme for attribute type."); } if (prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL) { if (att_type != GeometryAttribute::NORMAL) { - return Status(Status::ERROR, + return Status(Status::DRACO_ERROR, "Invalid prediction scheme for attribute type."); } } @@ -92,7 +97,7 @@ class EncoderBase { if (att_type == GeometryAttribute::NORMAL) { if (!(prediction_scheme == PREDICTION_DIFFERENCE || prediction_scheme == MESH_PREDICTION_GEOMETRIC_NORMAL)) { - return Status(Status::ERROR, + return Status(Status::DRACO_ERROR, "Invalid prediction scheme for attribute type."); } } diff --git a/extern/draco/dracoenc/src/draco/compression/entropy/ans.h b/extern/draco/dracoenc/src/draco/compression/entropy/ans.h index 40b08ed33c6..310ae256667 100644 --- a/extern/draco/dracoenc/src/draco/compression/entropy/ans.h +++ b/extern/draco/dracoenc/src/draco/compression/entropy/ans.h @@ -20,29 +20,29 @@ #include <vector> -#define ANS_DIVIDE_BY_MULTIPLY 1 -#if ANS_DIVIDE_BY_MULTIPLY +#define DRACO_ANS_DIVIDE_BY_MULTIPLY 1 +#if DRACO_ANS_DIVIDE_BY_MULTIPLY #include "draco/core/divide.h" #endif #include "draco/core/macros.h" namespace draco { -#if ANS_DIVIDE_BY_MULTIPLY +#if DRACO_ANS_DIVIDE_BY_MULTIPLY -#define ANS_DIVREM(quotient, remainder, dividend, divisor) \ - do { \ - quotient = fastdiv(dividend, divisor); \ - remainder = dividend - quotient * divisor; \ +#define DRACO_ANS_DIVREM(quotient, remainder, dividend, divisor) \ + do { \ + quotient = fastdiv(dividend, divisor); \ + remainder = dividend - quotient * divisor; \ } while (0) -#define ANS_DIV(dividend, divisor) fastdiv(dividend, divisor) +#define DRACO_ANS_DIV(dividend, divisor) fastdiv(dividend, divisor) #else -#define ANS_DIVREM(quotient, remainder, dividend, divisor) \ - do { \ - quotient = dividend / divisor; \ - remainder = dividend % divisor; \ +#define DRACO_ANS_DIVREM(quotient, remainder, dividend, divisor) \ + do { \ + quotient = dividend / divisor; \ + remainder = dividend % divisor; \ } while (0) -#define ANS_DIV(dividend, divisor) ((dividend) / (divisor)) +#define DRACO_ANS_DIV(dividend, divisor) ((dividend) / (divisor)) #endif struct AnsCoder { @@ -60,13 +60,9 @@ struct AnsDecoder { }; typedef uint8_t AnsP8; -#define ans_p8_precision 256u -#define ans_p8_shift 8 -#define ans_p10_precision 1024u - -#define l_base (ans_p10_precision * 4) // l_base % precision must be 0 -#define io_base 256 -// Range I = { l_base, l_base + 1, ..., l_base * io_base - 1 } +#define DRACO_ANS_P8_PRECISION 256u +#define DRACO_ANS_L_BASE (4096u) +#define DRACO_ANS_IO_BASE 256 static uint32_t mem_get_le16(const void *vmem) { uint32_t val; @@ -126,14 +122,14 @@ static inline void ans_write_init(struct AnsCoder *const ans, uint8_t *const buf) { ans->buf = buf; ans->buf_offset = 0; - ans->state = l_base; + ans->state = DRACO_ANS_L_BASE; } static inline int ans_write_end(struct AnsCoder *const ans) { uint32_t state; - DRACO_DCHECK_GE(ans->state, l_base); - DRACO_DCHECK_LT(ans->state, l_base * io_base); - state = ans->state - l_base; + DRACO_DCHECK_GE(ans->state, DRACO_ANS_L_BASE); + DRACO_DCHECK_LT(ans->state, DRACO_ANS_L_BASE * DRACO_ANS_IO_BASE); + state = ans->state - DRACO_ANS_L_BASE; if (state < (1 << 6)) { ans->buf[ans->buf_offset] = (0x00 << 6) + state; return ans->buf_offset + 1; @@ -149,43 +145,44 @@ static inline int ans_write_end(struct AnsCoder *const ans) { } } -// rABS with descending spread -// p or p0 takes the place of l_s from the paper -// ans_p8_precision is m +// rABS with descending spread. +// p or p0 takes the place of l_s from the paper. +// DRACO_ANS_P8_PRECISION is m. static inline void rabs_desc_write(struct AnsCoder *ans, int val, AnsP8 p0) { - const AnsP8 p = ans_p8_precision - p0; + const AnsP8 p = DRACO_ANS_P8_PRECISION - p0; const unsigned l_s = val ? p : p0; unsigned quot, rem; - if (ans->state >= l_base / ans_p8_precision * io_base * l_s) { - ans->buf[ans->buf_offset++] = ans->state % io_base; - ans->state /= io_base; + if (ans->state >= + DRACO_ANS_L_BASE / DRACO_ANS_P8_PRECISION * DRACO_ANS_IO_BASE * l_s) { + ans->buf[ans->buf_offset++] = ans->state % DRACO_ANS_IO_BASE; + ans->state /= DRACO_ANS_IO_BASE; } - ANS_DIVREM(quot, rem, ans->state, l_s); - ans->state = quot * ans_p8_precision + rem + (val ? 0 : p); + DRACO_ANS_DIVREM(quot, rem, ans->state, l_s); + ans->state = quot * DRACO_ANS_P8_PRECISION + rem + (val ? 0 : p); } -#define ANS_IMPL1 0 +#define DRACO_ANS_IMPL1 0 #define UNPREDICTABLE(x) x static inline int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) { int val; -#if ANS_IMPL1 +#if DRACO_ANS_IMPL1 unsigned l_s; #else unsigned quot, rem, x, xn; #endif - const AnsP8 p = ans_p8_precision - p0; - if (ans->state < l_base && ans->buf_offset > 0) { - ans->state = ans->state * io_base + ans->buf[--ans->buf_offset]; + const AnsP8 p = DRACO_ANS_P8_PRECISION - p0; + if (ans->state < DRACO_ANS_L_BASE && ans->buf_offset > 0) { + ans->state = ans->state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset]; } -#if ANS_IMPL1 - val = ans->state % ans_p8_precision < p; +#if DRACO_ANS_IMPL1 + val = ans->state % DRACO_ANS_P8_PRECISION < p; l_s = val ? p : p0; - ans->state = (ans->state / ans_p8_precision) * l_s + - ans->state % ans_p8_precision - (!val * p); + ans->state = (ans->state / DRACO_ANS_P8_PRECISION) * l_s + + ans->state % DRACO_ANS_P8_PRECISION - (!val * p); #else x = ans->state; - quot = x / ans_p8_precision; - rem = x % ans_p8_precision; + quot = x / DRACO_ANS_P8_PRECISION; + rem = x % DRACO_ANS_P8_PRECISION; xn = quot * p; val = rem < p; if (UNPREDICTABLE(val)) { @@ -198,41 +195,42 @@ static inline int rabs_desc_read(struct AnsDecoder *ans, AnsP8 p0) { return val; } -// rABS with ascending spread -// p or p0 takes the place of l_s from the paper -// ans_p8_precision is m +// rABS with ascending spread. +// p or p0 takes the place of l_s from the paper. +// DRACO_ANS_P8_PRECISION is m. static inline void rabs_asc_write(struct AnsCoder *ans, int val, AnsP8 p0) { - const AnsP8 p = ans_p8_precision - p0; + const AnsP8 p = DRACO_ANS_P8_PRECISION - p0; const unsigned l_s = val ? p : p0; unsigned quot, rem; - if (ans->state >= l_base / ans_p8_precision * io_base * l_s) { - ans->buf[ans->buf_offset++] = ans->state % io_base; - ans->state /= io_base; + if (ans->state >= + DRACO_ANS_L_BASE / DRACO_ANS_P8_PRECISION * DRACO_ANS_IO_BASE * l_s) { + ans->buf[ans->buf_offset++] = ans->state % DRACO_ANS_IO_BASE; + ans->state /= DRACO_ANS_IO_BASE; } - ANS_DIVREM(quot, rem, ans->state, l_s); - ans->state = quot * ans_p8_precision + rem + (val ? p0 : 0); + DRACO_ANS_DIVREM(quot, rem, ans->state, l_s); + ans->state = quot * DRACO_ANS_P8_PRECISION + rem + (val ? p0 : 0); } static inline int rabs_asc_read(struct AnsDecoder *ans, AnsP8 p0) { int val; -#if ANS_IMPL1 +#if DRACO_ANS_IMPL1 unsigned l_s; #else unsigned quot, rem, x, xn; #endif - const AnsP8 p = ans_p8_precision - p0; - if (ans->state < l_base) { - ans->state = ans->state * io_base + ans->buf[--ans->buf_offset]; + const AnsP8 p = DRACO_ANS_P8_PRECISION - p0; + if (ans->state < DRACO_ANS_L_BASE) { + ans->state = ans->state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset]; } -#if ANS_IMPL1 - val = ans->state % ans_p8_precision < p; +#if DRACO_ANS_IMPL1 + val = ans->state % DRACO_ANS_P8_PRECISION < p; l_s = val ? p : p0; - ans->state = (ans->state / ans_p8_precision) * l_s + - ans->state % ans_p8_precision - (!val * p); + ans->state = (ans->state / DRACO_ANS_P8_PRECISION) * l_s + + ans->state % DRACO_ANS_P8_PRECISION - (!val * p); #else x = ans->state; - quot = x / ans_p8_precision; - rem = x % ans_p8_precision; + quot = x / DRACO_ANS_P8_PRECISION; + rem = x % DRACO_ANS_P8_PRECISION; xn = quot * p; val = rem >= p0; if (UNPREDICTABLE(val)) { @@ -248,32 +246,34 @@ static inline int rabs_asc_read(struct AnsDecoder *ans, AnsP8 p0) { #define rabs_read rabs_desc_read #define rabs_write rabs_desc_write -// uABS with normalization +// uABS with normalization. static inline void uabs_write(struct AnsCoder *ans, int val, AnsP8 p0) { - AnsP8 p = ans_p8_precision - p0; + AnsP8 p = DRACO_ANS_P8_PRECISION - p0; const unsigned l_s = val ? p : p0; - while (ans->state >= l_base / ans_p8_precision * io_base * l_s) { - ans->buf[ans->buf_offset++] = ans->state % io_base; - ans->state /= io_base; + while (ans->state >= + DRACO_ANS_L_BASE / DRACO_ANS_P8_PRECISION * DRACO_ANS_IO_BASE * l_s) { + ans->buf[ans->buf_offset++] = ans->state % DRACO_ANS_IO_BASE; + ans->state /= DRACO_ANS_IO_BASE; } if (!val) - ans->state = ANS_DIV(ans->state * ans_p8_precision, p0); + ans->state = DRACO_ANS_DIV(ans->state * DRACO_ANS_P8_PRECISION, p0); else - ans->state = ANS_DIV((ans->state + 1) * ans_p8_precision + p - 1, p) - 1; + ans->state = + DRACO_ANS_DIV((ans->state + 1) * DRACO_ANS_P8_PRECISION + p - 1, p) - 1; } static inline int uabs_read(struct AnsDecoder *ans, AnsP8 p0) { - AnsP8 p = ans_p8_precision - p0; + AnsP8 p = DRACO_ANS_P8_PRECISION - p0; int s; // unsigned int xp1; unsigned xp, sp; unsigned state = ans->state; - while (state < l_base && ans->buf_offset > 0) { - state = state * io_base + ans->buf[--ans->buf_offset]; + while (state < DRACO_ANS_L_BASE && ans->buf_offset > 0) { + state = state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset]; } sp = state * p; - // xp1 = (sp + p) / ans_p8_precision; - xp = sp / ans_p8_precision; + // xp1 = (sp + p) / DRACO_ANS_P8_PRECISION; + xp = sp / DRACO_ANS_P8_PRECISION; // s = xp1 - xp; s = (sp & 0xFF) >= p0; if (UNPREDICTABLE(s)) @@ -286,8 +286,8 @@ static inline int uabs_read(struct AnsDecoder *ans, AnsP8 p0) { static inline int uabs_read_bit(struct AnsDecoder *ans) { int s; unsigned state = ans->state; - while (state < l_base && ans->buf_offset > 0) { - state = state * io_base + ans->buf[--ans->buf_offset]; + while (state < DRACO_ANS_L_BASE && ans->buf_offset > 0) { + state = state * DRACO_ANS_IO_BASE + ans->buf[--ans->buf_offset]; } s = static_cast<int>(state & 1); ans->state = state >> 1; @@ -317,23 +317,23 @@ static inline int ans_read_init(struct AnsDecoder *const ans, } else { return 1; } - ans->state += l_base; - if (ans->state >= l_base * io_base) + ans->state += DRACO_ANS_L_BASE; + if (ans->state >= DRACO_ANS_L_BASE * DRACO_ANS_IO_BASE) return 1; return 0; } static inline int ans_read_end(struct AnsDecoder *const ans) { - return ans->state == l_base; + return ans->state == DRACO_ANS_L_BASE; } static inline int ans_reader_has_error(const struct AnsDecoder *const ans) { - return ans->state < l_base && ans->buf_offset == 0; + return ans->state < DRACO_ANS_L_BASE && ans->buf_offset == 0; } struct rans_sym { uint32_t prob; - uint32_t cum_prob; // not-inclusive + uint32_t cum_prob; // not-inclusive. }; // Class for performing rANS encoding using a desired number of precision bits. @@ -356,7 +356,7 @@ class RAnsEncoder { inline int write_end() { uint32_t state; DRACO_DCHECK_GE(ans_.state, l_rans_base); - DRACO_DCHECK_LT(ans_.state, l_rans_base * io_base); + DRACO_DCHECK_LT(ans_.state, l_rans_base * DRACO_ANS_IO_BASE); state = ans_.state - l_rans_base; if (state < (1 << 6)) { ans_.buf[ans_.buf_offset] = (0x00 << 6) + state; @@ -376,14 +376,14 @@ class RAnsEncoder { } } - // rANS with normalization - // sym->prob takes the place of l_s from the paper - // rans_precision is m + // rANS with normalization. + // sym->prob takes the place of l_s from the paper. + // rans_precision is m. inline void rans_write(const struct rans_sym *const sym) { const uint32_t p = sym->prob; - while (ans_.state >= l_rans_base / rans_precision * io_base * p) { - ans_.buf[ans_.buf_offset++] = ans_.state % io_base; - ans_.state /= io_base; + while (ans_.state >= l_rans_base / rans_precision * DRACO_ANS_IO_BASE * p) { + 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 = @@ -399,7 +399,7 @@ class RAnsEncoder { struct rans_dec_sym { uint32_t val; uint32_t prob; - uint32_t cum_prob; // not-inclusive + uint32_t cum_prob; // not-inclusive. }; // Class for performing rANS decoding using a desired number of precision bits. @@ -439,7 +439,7 @@ class RAnsDecoder { return 1; } ans_.state += l_rans_base; - if (ans_.state >= l_rans_base * io_base) + if (ans_.state >= l_rans_base * DRACO_ANS_IO_BASE) return 1; return 0; } @@ -455,7 +455,7 @@ class RAnsDecoder { unsigned quo; struct rans_dec_sym sym; while (ans_.state < l_rans_base && ans_.buf_offset > 0) { - ans_.state = ans_.state * io_base + ans_.buf[--ans_.buf_offset]; + ans_.state = ans_.state * DRACO_ANS_IO_BASE + ans_.buf[--ans_.buf_offset]; } // |rans_precision| is a power of two compile time constant, and the below // division and modulo are going to be optimized by the compiler. @@ -507,7 +507,10 @@ class RAnsDecoder { AnsDecoder ans_; }; -#undef ANS_DIVREM +#undef DRACO_ANS_DIVREM +#undef DRACO_ANS_P8_PRECISION +#undef DRACO_ANS_L_BASE +#undef DRACO_ANS_IO_BASE } // namespace draco diff --git a/extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h b/extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h index 8d06644a9b9..0a68e29fe26 100644 --- a/extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h +++ b/extern/draco/dracoenc/src/draco/compression/entropy/rans_symbol_coding.h @@ -40,8 +40,8 @@ constexpr int ComputeRAnsPrecisionFromUniqueSymbolsBitLength( // Compute approximate frequency table size needed for storing the provided // symbols. -static int64_t ApproximateRAnsFrequencyTableBits(int32_t max_value, - int num_unique_symbols) { +static inline int64_t ApproximateRAnsFrequencyTableBits( + int32_t max_value, int num_unique_symbols) { // Approximate number of bits for storing zero frequency entries using the // run length encoding (with max length of 64). const int64_t table_zero_frequency_bits = diff --git a/extern/draco/dracoenc/src/draco/compression/expert_encode.cc b/extern/draco/dracoenc/src/draco/compression/expert_encode.cc index f62d16630cb..112e6ae3d3e 100644 --- a/extern/draco/dracoenc/src/draco/compression/expert_encode.cc +++ b/extern/draco/dracoenc/src/draco/compression/expert_encode.cc @@ -16,8 +16,10 @@ #include "draco/compression/mesh/mesh_edgebreaker_encoder.h" #include "draco/compression/mesh/mesh_sequential_encoder.h" +#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED #include "draco/compression/point_cloud/point_cloud_kd_tree_encoder.h" #include "draco/compression/point_cloud/point_cloud_sequential_encoder.h" +#endif namespace draco { @@ -29,7 +31,7 @@ ExpertEncoder::ExpertEncoder(const Mesh &mesh) Status ExpertEncoder::EncodeToBuffer(EncoderBuffer *out_buffer) { if (point_cloud_ == nullptr) - return Status(Status::ERROR, "Invalid input geometry."); + return Status(Status::DRACO_ERROR, "Invalid input geometry."); if (mesh_ == nullptr) { return EncodePointCloudToBuffer(*point_cloud_, out_buffer); } @@ -38,6 +40,7 @@ Status ExpertEncoder::EncodeToBuffer(EncoderBuffer *out_buffer) { Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc, EncoderBuffer *out_buffer) { +#ifdef DRACO_POINT_CLOUD_COMPRESSION_SUPPORTED std::unique_ptr<PointCloudEncoder> encoder; const int encoding_method = options().GetGlobalInt("encoding_method", -1); @@ -74,7 +77,7 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc, } else if (encoding_method == POINT_CLOUD_KD_TREE_ENCODING) { // Encoding method was explicitly specified but we cannot use it for // the given input (some of the checks above failed). - return Status(Status::ERROR, "Invalid encoding method."); + return Status(Status::DRACO_ERROR, "Invalid encoding method."); } } if (!encoder) { @@ -87,6 +90,9 @@ Status ExpertEncoder::EncodePointCloudToBuffer(const PointCloud &pc, set_num_encoded_points(encoder->num_encoded_points()); set_num_encoded_faces(0); return OkStatus(); +#else + return Status(Status::DRACO_ERROR, "Point cloud encoding is not enabled."); +#endif } Status ExpertEncoder::EncodeMeshToBuffer(const Mesh &m, diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc index ad87f9403af..54fd55a483c 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.cc @@ -31,9 +31,7 @@ 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(ostava): For now we have a set limit for forcing the basic edgebreaker - // based on the number of faces, but a more complex heuristic may be used if - // needed. + // TODO(b/111065939): Check if this can be improved. const bool is_tiny_mesh = mesh()->num_faces() < 1000; int selected_edgebreaker_method = @@ -81,7 +79,7 @@ bool MeshEdgebreakerEncoder::EncodeAttributesEncoderIdentifier( return true; } -bool MeshEdgebreakerEncoder::EncodeConnectivity() { +Status MeshEdgebreakerEncoder::EncodeConnectivity() { return impl_->EncodeConnectivity(); } diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h index 78615fb0287..70d4d5061a7 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder.h @@ -51,7 +51,7 @@ class MeshEdgebreakerEncoder : public MeshEncoder { protected: bool InitializeEncoder() override; - bool EncodeConnectivity() override; + Status EncodeConnectivity() override; bool GenerateAttributesEncoder(int32_t att_id) override; bool EncodeAttributesEncoderIdentifier(int32_t att_encoder_id) override; void ComputeNumberOfEncodedPoints() override; diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc index 89e6f0b5b12..f69ec993f9e 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.cc @@ -263,7 +263,7 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>:: } template <class TraversalEncoder> -bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() { +Status MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() { // To encode the mesh, we need face connectivity data stored in a corner // table. To compute the connectivity we must use indices associated with // POSITION attribute, because they define which edges can be connected @@ -279,7 +279,7 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() { corner_table_->num_faces() == corner_table_->NumDegeneratedFaces()) { // Failed to construct the corner table. // TODO(ostava): Add better error reporting. - return false; + return Status(Status::DRACO_ERROR, "All triangles are degenerate."); } traversal_encoder_.Init(this); @@ -317,10 +317,10 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() { pos_encoding_data_.num_values = 0; if (!FindHoles()) - return false; + return Status(Status::DRACO_ERROR, "Failed to process mesh holes."); if (!InitAttributeData()) - return false; + return Status(Status::DRACO_ERROR, "Failed to initialize attribute data."); const uint8_t num_attribute_data = static_cast<uint8_t>(attribute_data_.size()); @@ -376,7 +376,7 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() { if (opp_face_id != kInvalidFaceIndex && !visited_faces_[opp_face_id.value()]) { if (!EncodeConnectivityFromCorner(opp_id)) - return false; + return Status(Status::DRACO_ERROR, "Failed to encode mesh component."); } } else { // Boundary configuration. We start on a boundary rather than on a face. @@ -385,7 +385,7 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() { // Start processing the face opposite to the boundary edge (the face // containing the start_corner). if (!EncodeConnectivityFromCorner(start_corner)) - return false; + return Status(Status::DRACO_ERROR, "Failed to encode mesh component."); } } // Reverse the order of connectivity corners to match the order in which @@ -417,11 +417,11 @@ bool MeshEdgebreakerEncoderImpl<TraversalEncoder>::EncodeConnectivity() { // Append the traversal buffer. if (!EncodeSplitData()) - return false; + return Status(Status::DRACO_ERROR, "Failed to encode split data."); encoder_->buffer()->Encode(traversal_encoder_.buffer().data(), traversal_encoder_.buffer().size()); - return true; + return OkStatus(); } template <class TraversalEncoder> diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h index 997bd1565e3..fb33771637e 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl.h @@ -45,7 +45,7 @@ class MeshEdgebreakerEncoderImpl : public MeshEdgebreakerEncoderImplInterface { bool GenerateAttributesEncoder(int32_t att_id) override; bool EncodeAttributesEncoderIdentifier(int32_t att_encoder_id) override; - bool EncodeConnectivity() override; + Status EncodeConnectivity() override; const CornerTable *GetCornerTable() const override { return corner_table_.get(); diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h index 8da3541ec86..627d5126296 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_edgebreaker_encoder_impl_interface.h @@ -41,7 +41,7 @@ class MeshEdgebreakerEncoderImplInterface { int att_id) const = 0; virtual bool GenerateAttributesEncoder(int32_t att_id) = 0; virtual bool EncodeAttributesEncoderIdentifier(int32_t att_encoder_id) = 0; - virtual bool EncodeConnectivity() = 0; + virtual Status EncodeConnectivity() = 0; // Returns corner table of the encoded mesh. virtual const CornerTable *GetCornerTable() const = 0; diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc index 19d1355a443..2da5de1fc82 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.cc @@ -23,12 +23,11 @@ void MeshEncoder::SetMesh(const Mesh &m) { SetPointCloud(m); } -bool MeshEncoder::EncodeGeometryData() { - if (!EncodeConnectivity()) - return false; +Status MeshEncoder::EncodeGeometryData() { + DRACO_RETURN_IF_ERROR(EncodeConnectivity()); if (options()->GetGlobalBool("store_number_of_encoded_faces", false)) ComputeNumberOfEncodedFaces(); - return true; + return OkStatus(); } } // namespace draco diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h index 41387d569c6..30ec4fa3492 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder.h @@ -61,10 +61,10 @@ class MeshEncoder : public PointCloudEncoder { const Mesh *mesh() const { return mesh_; } protected: - bool EncodeGeometryData() override; + Status EncodeGeometryData() override; // Needs to be implemented by the derived classes. - virtual bool EncodeConnectivity() = 0; + virtual Status EncodeConnectivity() = 0; // Computes and sets the num_encoded_faces_ for the encoder. virtual void ComputeNumberOfEncodedFaces() = 0; diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc index e67861a2ec2..9f056fc22e3 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_encoder_test.cc @@ -87,7 +87,7 @@ TEST_P(MeshEncoderTest, EncodeGoldenMesh) { } } -INSTANTIATE_TEST_CASE_P(MeshEncoderTests, MeshEncoderTest, - ::testing::Values("sequential", "edgebreaker")); +INSTANTIATE_TEST_SUITE_P(MeshEncoderTests, MeshEncoderTest, + ::testing::Values("sequential", "edgebreaker")); } // namespace draco diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc index 44b3b20b63c..b53ff0c25a6 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.cc @@ -25,7 +25,7 @@ namespace draco { MeshSequentialEncoder::MeshSequentialEncoder() {} -bool MeshSequentialEncoder::EncodeConnectivity() { +Status MeshSequentialEncoder::EncodeConnectivity() { // Serialize indices. const uint32_t num_faces = mesh()->num_faces(); EncodeVarint(num_faces, buffer()); @@ -38,7 +38,7 @@ bool MeshSequentialEncoder::EncodeConnectivity() { // 0 = Encode compressed indices. buffer()->Encode(static_cast<uint8_t>(0)); if (!CompressAndEncodeIndices()) - return false; + return Status(Status::DRACO_ERROR, "Failed to compress connectivity."); } else { // 1 = Encode indices directly. buffer()->Encode(static_cast<uint8_t>(1)); @@ -77,7 +77,7 @@ bool MeshSequentialEncoder::EncodeConnectivity() { } } } - return true; + return OkStatus(); } bool MeshSequentialEncoder::GenerateAttributesEncoder(int32_t att_id) { diff --git a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h index 47a4fec837c..672609642b0 100644 --- a/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h +++ b/extern/draco/dracoenc/src/draco/compression/mesh/mesh_sequential_encoder.h @@ -42,7 +42,7 @@ class MeshSequentialEncoder : public MeshEncoder { } protected: - bool EncodeConnectivity() override; + Status EncodeConnectivity() override; bool GenerateAttributesEncoder(int32_t att_id) override; void ComputeNumberOfEncodedPoints() override; void ComputeNumberOfEncodedFaces() override; diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h index e220a2ab166..61a153560ae 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/dynamic_integer_points_kd_tree_decoder.h @@ -95,8 +95,11 @@ class DynamicIntegerPointsKdTreeDecoder { // Decodes a integer point cloud from |buffer|. template <class OutputIteratorT> bool DecodePoints(DecoderBuffer *buffer, OutputIteratorT &oit); + +#ifndef DRACO_OLD_GCC template <class OutputIteratorT> bool DecodePoints(DecoderBuffer *buffer, OutputIteratorT &&oit); +#endif // DRACO_OLD_GCC const uint32_t dimension() const { return dimension_; } @@ -138,6 +141,7 @@ class DynamicIntegerPointsKdTreeDecoder { }; // Decodes a point cloud from |buffer|. +#ifndef DRACO_OLD_GCC template <int compression_level_t> template <class OutputIteratorT> bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodePoints( @@ -145,6 +149,7 @@ bool DynamicIntegerPointsKdTreeDecoder<compression_level_t>::DecodePoints( OutputIteratorT local = std::forward<OutputIteratorT>(oit); return DecodePoints(buffer, local); } +#endif // DRACO_OLD_GCC template <int compression_level_t> template <class OutputIteratorT> diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h index 80be0c9d373..d3425696a5a 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/float_points_tree_decoder.h @@ -33,8 +33,12 @@ class FloatPointsTreeDecoder { // Decodes a point cloud from |buffer|. template <class OutputIteratorT> bool DecodePointCloud(DecoderBuffer *buffer, OutputIteratorT &out); + +#ifndef DRACO_OLD_GCC template <class OutputIteratorT> bool DecodePointCloud(DecoderBuffer *buffer, OutputIteratorT &&out); +#endif // DRACO_OLD_GCC + // Initializes a DecoderBuffer from |data|, and calls function above. template <class OutputIteratorT> bool DecodePointCloud(const char *data, size_t data_size, @@ -72,12 +76,16 @@ class FloatPointsTreeDecoder { uint32_t compression_level_; }; +#ifndef DRACO_OLD_GCC +// TODO(vytyaz): Reenable once USD migrates from GCC 4.8 to a higher version +// that can disambiguate calls to overloaded methods taking rvalue reference. template <class OutputIteratorT> bool FloatPointsTreeDecoder::DecodePointCloud(DecoderBuffer *buffer, OutputIteratorT &&out) { OutputIteratorT local = std::forward<OutputIteratorT>(out); return DecodePointCloud(buffer, local); } +#endif // DRACO_OLD_GCC template <class OutputIteratorT> bool FloatPointsTreeDecoder::DecodePointCloud(DecoderBuffer *buffer, diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h index 18307b57209..9541c966856 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/algorithms/point_cloud_compression_method.h @@ -23,7 +23,7 @@ enum PointCloudCompressionMethod { // Generalized version of Encoding using the Octree method by Olivier // Devillers to d dimensions. // "Progressive lossless compression of arbitrary simplicial complexes" - // http://dx.doi.org/10.1145/566570.566591 + // https://doi.org/10.1145/566570.566591 KDTREE = 1, RESERVED_POINT_CLOUD_METHOD_2 = 2, // Reserved for internal use. RESERVED_POINT_CLOUD_METHOD_3 = 0, // Reserved for internal use. diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc index 5f3bff4bbc9..cf5d997e67a 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_decoder.cc @@ -31,7 +31,7 @@ Status PointCloudDecoder::DecodeHeader(DecoderBuffer *buffer, if (!buffer->Decode(out_header->draco_string, 5)) return Status(Status::IO_ERROR, kIoErrorMsg); if (memcmp(out_header->draco_string, "DRACO", 5) != 0) - return Status(Status::ERROR, "Not a Draco file."); + return Status(Status::DRACO_ERROR, "Not a Draco file."); if (!buffer->Decode(&(out_header->version_major))) return Status(Status::IO_ERROR, kIoErrorMsg); if (!buffer->Decode(&(out_header->version_minor))) @@ -50,7 +50,7 @@ Status PointCloudDecoder::DecodeMetadata() { std::unique_ptr<GeometryMetadata>(new GeometryMetadata()); MetadataDecoder metadata_decoder; if (!metadata_decoder.DecodeGeometryMetadata(buffer_, metadata.get())) - return Status(Status::ERROR, "Failed to decode metadata."); + return Status(Status::DRACO_ERROR, "Failed to decode metadata."); point_cloud_->AddMetadata(std::move(metadata)); return OkStatus(); } @@ -66,7 +66,7 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options, // Sanity check that we are really using the right decoder (mostly for cases // where the Decode method was called manually outside of our main API. if (header.encoder_type != GetGeometryType()) - return Status(Status::ERROR, + return Status(Status::DRACO_ERROR, "Using incompatible decoder for the input geometry."); // TODO(ostava): We should check the method as well, but currently decoders // don't expose the decoding method id. @@ -93,11 +93,11 @@ Status PointCloudDecoder::Decode(const DecoderOptions &options, DRACO_RETURN_IF_ERROR(DecodeMetadata()) } if (!InitializeDecoder()) - return Status(Status::ERROR, "Failed to initialize the decoder."); + return Status(Status::DRACO_ERROR, "Failed to initialize the decoder."); if (!DecodeGeometryData()) - return Status(Status::ERROR, "Failed to decode geometry data."); + return Status(Status::DRACO_ERROR, "Failed to decode geometry data."); if (!DecodePointAttributes()) - return Status(Status::ERROR, "Failed to decode point attributes."); + return Status(Status::DRACO_ERROR, "Failed to decode point attributes."); return OkStatus(); } diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc index edf0e4ab20a..986706582f0 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.cc @@ -36,17 +36,16 @@ Status PointCloudEncoder::Encode(const EncoderOptions &options, attributes_encoder_ids_order_.clear(); if (!point_cloud_) - return Status(Status::ERROR, "Invalid input geometry."); + return Status(Status::DRACO_ERROR, "Invalid input geometry."); DRACO_RETURN_IF_ERROR(EncodeHeader()) DRACO_RETURN_IF_ERROR(EncodeMetadata()) if (!InitializeEncoder()) - return Status(Status::ERROR, "Failed to initialize encoder."); + return Status(Status::DRACO_ERROR, "Failed to initialize encoder."); if (!EncodeEncoderData()) - return Status(Status::ERROR, "Failed to encode internal data."); - if (!EncodeGeometryData()) - return Status(Status::ERROR, "Failed to encode geometry data."); + return Status(Status::DRACO_ERROR, "Failed to encode internal data."); + DRACO_RETURN_IF_ERROR(EncodeGeometryData()); if (!EncodePointAttributes()) - return Status(Status::ERROR, "Failed to encode point attributes."); + return Status(Status::DRACO_ERROR, "Failed to encode point attributes."); if (options.GetGlobalBool("store_number_of_encoded_points", false)) ComputeNumberOfEncodedPoints(); return OkStatus(); @@ -87,7 +86,7 @@ Status PointCloudEncoder::EncodeMetadata() { MetadataEncoder metadata_encoder; if (!metadata_encoder.EncodeGeometryMetadata(buffer_, point_cloud_->GetMetadata())) { - return Status(Status::ERROR, "Failed to encode metadata."); + return Status(Status::DRACO_ERROR, "Failed to encode metadata."); } return OkStatus(); } diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h index b15d1401a57..8883f17a789 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_encoder.h @@ -85,7 +85,7 @@ class PointCloudEncoder { virtual bool EncodeEncoderData() { return true; } // Encodes any global geometry data (such as the number of points). - virtual bool EncodeGeometryData() { return true; } + virtual Status EncodeGeometryData() { return OkStatus(); } // encode all attribute values. The attribute encoders are sorted to resolve // any attribute dependencies and all the encoded data is stored into the diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc index 7ecfca2b456..6d0446baad1 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.cc @@ -17,10 +17,10 @@ namespace draco { -bool PointCloudKdTreeEncoder::EncodeGeometryData() { +Status PointCloudKdTreeEncoder::EncodeGeometryData() { const int32_t num_points = point_cloud()->num_points(); buffer()->Encode(num_points); - return true; + return OkStatus(); } bool PointCloudKdTreeEncoder::GenerateAttributesEncoder(int32_t att_id) { diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h index 98bc3d67fde..6acbb949d40 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_kd_tree_encoder.h @@ -35,7 +35,7 @@ class PointCloudKdTreeEncoder : public PointCloudEncoder { } protected: - bool EncodeGeometryData() override; + Status EncodeGeometryData() override; bool GenerateAttributesEncoder(int32_t att_id) override; void ComputeNumberOfEncodedPoints() override; }; diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc index 9b92994b7a6..fa7b6fd905c 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.cc @@ -19,10 +19,10 @@ namespace draco { -bool PointCloudSequentialEncoder::EncodeGeometryData() { +Status PointCloudSequentialEncoder::EncodeGeometryData() { const int32_t num_points = point_cloud()->num_points(); buffer()->Encode(num_points); - return true; + return OkStatus(); } bool PointCloudSequentialEncoder::GenerateAttributesEncoder(int32_t att_id) { diff --git a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h index f73b5a551e4..40d8edcdbb0 100644 --- a/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h +++ b/extern/draco/dracoenc/src/draco/compression/point_cloud/point_cloud_sequential_encoder.h @@ -33,7 +33,7 @@ class PointCloudSequentialEncoder : public PointCloudEncoder { } protected: - bool EncodeGeometryData() override; + Status EncodeGeometryData() override; bool GenerateAttributesEncoder(int32_t att_id) override; void ComputeNumberOfEncodedPoints() override; }; diff --git a/extern/draco/dracoenc/src/draco/core/data_buffer.cc b/extern/draco/dracoenc/src/draco/core/data_buffer.cc index 3b57367bbf1..867760a6fcc 100644 --- a/extern/draco/dracoenc/src/draco/core/data_buffer.cc +++ b/extern/draco/dracoenc/src/draco/core/data_buffer.cc @@ -13,6 +13,7 @@ // limitations under the License. // #include "draco/core/data_buffer.h" +#include <algorithm> namespace draco { diff --git a/extern/draco/dracoenc/src/draco/core/draco_test_utils.cc b/extern/draco/dracoenc/src/draco/core/draco_test_utils.cc index fa225576d9c..a39e19f6b15 100644 --- a/extern/draco/dracoenc/src/draco/core/draco_test_utils.cc +++ b/extern/draco/dracoenc/src/draco/core/draco_test_utils.cc @@ -48,7 +48,7 @@ bool GenerateGoldenFile(const std::string &golden_file_name, const void *data, bool CompareGoldenFile(const std::string &golden_file_name, const void *data, int data_size) { const std::string golden_path = GetTestFileFullPath(golden_file_name); - std::ifstream in_file(golden_path); + std::ifstream in_file(golden_path, std::ios::binary); if (!in_file || data_size < 0) return false; const char *const data_c8 = static_cast<const char *>(data); diff --git a/extern/draco/dracoenc/src/draco/core/draco_test_utils.h b/extern/draco/dracoenc/src/draco/core/draco_test_utils.h index 2ed93cd960b..3113a5d2676 100644 --- a/extern/draco/dracoenc/src/draco/core/draco_test_utils.h +++ b/extern/draco/dracoenc/src/draco/core/draco_test_utils.h @@ -53,6 +53,11 @@ inline std::unique_ptr<Mesh> ReadMeshFromTestFile(const std::string &file_name, const std::string path = GetTestFileFullPath(file_name); return ReadMeshFromFile(path, use_metadata).value(); } +inline std::unique_ptr<Mesh> ReadMeshFromTestFile(const std::string &file_name, + const Options &options) { + const std::string path = GetTestFileFullPath(file_name); + return ReadMeshFromFile(path, options).value(); +} inline std::unique_ptr<PointCloud> ReadPointCloudFromTestFile( const std::string &file_name) { diff --git a/extern/draco/dracoenc/src/draco/core/draco_types.cc b/extern/draco/dracoenc/src/draco/core/draco_types.cc index 45b22470057..9bde05fda80 100644 --- a/extern/draco/dracoenc/src/draco/core/draco_types.cc +++ b/extern/draco/dracoenc/src/draco/core/draco_types.cc @@ -41,4 +41,21 @@ int32_t DataTypeLength(DataType dt) { } } +bool IsDataTypeIntegral(DataType dt) { + switch (dt) { + case DT_INT8: + case DT_UINT8: + case DT_INT16: + case DT_UINT16: + case DT_INT32: + case DT_UINT32: + case DT_INT64: + case DT_UINT64: + case DT_BOOL: + return true; + default: + return false; + } +} + } // namespace draco diff --git a/extern/draco/dracoenc/src/draco/core/draco_types.h b/extern/draco/dracoenc/src/draco/core/draco_types.h index 4a34d7045a3..f5a21e4f1d0 100644 --- a/extern/draco/dracoenc/src/draco/core/draco_types.h +++ b/extern/draco/dracoenc/src/draco/core/draco_types.h @@ -41,6 +41,11 @@ enum DataType { int32_t DataTypeLength(DataType dt); +// Equivalent to std::is_integral for draco::DataType. Returns true for all +// signed and unsigned integer types (including DT_BOOL). Returns false +// otherwise. +bool IsDataTypeIntegral(DataType dt); + } // namespace draco #endif // DRACO_CORE_DRACO_TYPES_H_ diff --git a/extern/draco/dracoenc/src/draco/core/draco_version.h b/extern/draco/dracoenc/src/draco/core/draco_version.h index 45dce22a1d8..9d3a67e4f8e 100644 --- a/extern/draco/dracoenc/src/draco/core/draco_version.h +++ b/extern/draco/dracoenc/src/draco/core/draco_version.h @@ -18,7 +18,7 @@ namespace draco { // Draco version is comprised of <major>.<minor>.<revision>. -static const char kDracoVersion[] = "1.3.4"; +static const char kDracoVersion[] = "1.3.5"; const char *Version() { return kDracoVersion; } diff --git a/extern/draco/dracoenc/src/draco/core/macros.h b/extern/draco/dracoenc/src/draco/core/macros.h index e968cbb330b..09819e63969 100644 --- a/extern/draco/dracoenc/src/draco/core/macros.h +++ b/extern/draco/dracoenc/src/draco/core/macros.h @@ -32,12 +32,27 @@ #include <iostream> namespace draco { +#ifndef DISALLOW_COPY_AND_ASSIGN #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName &) = delete; \ void operator=(const TypeName &) = delete; +#endif + +#ifndef FALLTHROUGH_INTENDED +#if defined(__clang__) && defined(__has_warning) +#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") +#define FALLTHROUGH_INTENDED [[clang::fallthrough]] +#endif +#elif defined(__GNUC__) && __GNUC__ >= 7 +#define FALLTHROUGH_INTENDED [[gnu::fallthrough]] +#endif +// If FALLTHROUGH_INTENDED is still not defined, define it. #ifndef FALLTHROUGH_INTENDED -#define FALLTHROUGH_INTENDED void(0); +#define FALLTHROUGH_INTENDED \ + do { \ + } while (0) +#endif #endif #ifndef LOG diff --git a/extern/draco/dracoenc/src/draco/core/math_utils.h b/extern/draco/dracoenc/src/draco/core/math_utils.h index 6bf237d4560..50cf5d57199 100644 --- a/extern/draco/dracoenc/src/draco/core/math_utils.h +++ b/extern/draco/dracoenc/src/draco/core/math_utils.h @@ -17,6 +17,8 @@ #include <inttypes.h> +#include "draco/core/vector_d.h" + #define DRACO_INCREMENT_MOD(I, M) (((I) == ((M)-1)) ? 0 : ((I) + 1)) // Returns floor(sqrt(x)) where x is an integer number. The main intend of this diff --git a/extern/draco/dracoenc/src/draco/core/math_utils_test.cc b/extern/draco/dracoenc/src/draco/core/math_utils_test.cc index b12b3431e66..8c255d04680 100644 --- a/extern/draco/dracoenc/src/draco/core/math_utils_test.cc +++ b/extern/draco/dracoenc/src/draco/core/math_utils_test.cc @@ -1,9 +1,12 @@ #include "draco/core/math_utils.h" +#include <cmath> #include <random> #include "draco/core/draco_test_base.h" +using draco::Vector3f; + TEST(MathUtils, Mod) { EXPECT_EQ(DRACO_INCREMENT_MOD(1, 1 << 1), 0); } TEST(MathUtils, IntSqrt) { diff --git a/extern/draco/dracoenc/src/draco/core/options.cc b/extern/draco/dracoenc/src/draco/core/options.cc index c4f6d6a66aa..a9ce14b9837 100644 --- a/extern/draco/dracoenc/src/draco/core/options.cc +++ b/extern/draco/dracoenc/src/draco/core/options.cc @@ -16,11 +16,17 @@ #include <cstdlib> #include <string> +#include <utility> namespace draco { Options::Options() {} +void Options::MergeAndReplace(const Options &other_options) { + for (const auto &item : other_options.options_) + options_[item.first] = item.second; +} + void Options::SetInt(const std::string &name, int val) { options_[name] = std::to_string(val); } diff --git a/extern/draco/dracoenc/src/draco/core/options.h b/extern/draco/dracoenc/src/draco/core/options.h index 0e69844911d..4995299633c 100644 --- a/extern/draco/dracoenc/src/draco/core/options.h +++ b/extern/draco/dracoenc/src/draco/core/options.h @@ -28,6 +28,11 @@ namespace draco { class Options { public: Options(); + + // Merges |other_options| on top of the existing options of this instance + // replacing all entries that are present in both options instances. + void MergeAndReplace(const Options &other_options); + void SetInt(const std::string &name, int val); void SetFloat(const std::string &name, float val); void SetBool(const std::string &name, bool val); diff --git a/extern/draco/dracoenc/src/draco/core/status.h b/extern/draco/dracoenc/src/draco/core/status.h index 0a483f09369..9ac3def7cd1 100644 --- a/extern/draco/dracoenc/src/draco/core/status.h +++ b/extern/draco/dracoenc/src/draco/core/status.h @@ -25,7 +25,7 @@ class Status { public: enum Code { OK = 0, - ERROR = -1, // Used for general errors. + DRACO_ERROR = -1, // Used for general errors. IO_ERROR = -2, // Error when handling input or output stream. INVALID_PARAMETER = -3, // Invalid parameter passed to a function. UNSUPPORTED_VERSION = -4, // Input not compatible with the current version. diff --git a/extern/draco/dracoenc/src/draco/core/status_or.h b/extern/draco/dracoenc/src/draco/core/status_or.h new file mode 100644 index 00000000000..156b9bc02a7 --- /dev/null +++ b/extern/draco/dracoenc/src/draco/core/status_or.h @@ -0,0 +1,81 @@ +// Copyright 2017 The Draco Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#ifndef DRACO_CORE_STATUS_OR_H_ +#define DRACO_CORE_STATUS_OR_H_ + +#include "draco/core/macros.h" +#include "draco/core/status.h" + +namespace draco { + +// Class StatusOr is used to wrap a Status along with a value of a specified +// type |T|. StatusOr is intended to be returned from functions in situations +// where it is desirable to carry over more information about the potential +// errors encountered during the function execution. If there are not errors, +// the caller can simply use the return value, otherwise the Status object +// provides more info about the encountered problem. +template <class T> +class StatusOr { + public: + StatusOr() {} + // Note: Constructors are intentionally not explicit to allow returning + // Status or the return value directly from functions. + StatusOr(const StatusOr &) = default; + StatusOr(StatusOr &&) = default; + StatusOr(const Status &status) : status_(status) {} + StatusOr(const T &value) : status_(OkStatus()), value_(value) {} + StatusOr(T &&value) : status_(OkStatus()), value_(std::move(value)) {} + StatusOr(const Status &status, const T &value) + : status_(status), value_(value) {} + + const Status &status() const { return status_; } + const T &value() const & { return value_; } + const T &&value() const && { return std::move(value_); } + T &&value() && { return std::move(value_); } + + // For consistency with existing Google StatusOr API we also include + // ValueOrDie() that currently returns the value(). + const T &ValueOrDie() const & { return value(); } + T &&ValueOrDie() && { return std::move(value()); } + + bool ok() const { return status_.ok(); } + + private: + Status status_; + T value_; +}; + +// In case StatusOr<T> is ok(), this macro assigns value stored in StatusOr<T> +// to |lhs|, otherwise it returns the error Status. +// +// DRACO_ASSIGN_OR_RETURN(lhs, expression) +// +#define DRACO_ASSIGN_OR_RETURN(lhs, expression) \ + DRACO_ASSIGN_OR_RETURN_IMPL_(DRACO_MACROS_IMPL_CONCAT_(_statusor, __LINE__), \ + lhs, expression, _status) + +// The actual implementation of the above macro. +#define DRACO_ASSIGN_OR_RETURN_IMPL_(statusor, lhs, expression, error_expr) \ + auto statusor = (expression); \ + if (!statusor.ok()) { \ + auto _status = std::move(statusor.status()); \ + (void)_status; /* error_expression may not use it */ \ + return error_expr; \ + } \ + lhs = std::move(statusor).value(); + +} // namespace draco + +#endif // DRACO_CORE_STATUS_OR_H_ diff --git a/extern/draco/dracoenc/src/draco/core/status_test.cc b/extern/draco/dracoenc/src/draco/core/status_test.cc index 451ebe2bfab..c1ad4ab30f4 100644 --- a/extern/draco/dracoenc/src/draco/core/status_test.cc +++ b/extern/draco/dracoenc/src/draco/core/status_test.cc @@ -27,8 +27,8 @@ class StatusTest : public ::testing::Test { TEST_F(StatusTest, TestStatusOutput) { // Tests that the Status can be stored in a provided std::ostream. - const draco::Status status(draco::Status::ERROR, "Error msg."); - ASSERT_EQ(status.code(), draco::Status::ERROR); + const draco::Status status(draco::Status::DRACO_ERROR, "Error msg."); + ASSERT_EQ(status.code(), draco::Status::DRACO_ERROR); std::stringstream str; str << status; diff --git a/extern/draco/dracoenc/src/draco/core/vector_d.h b/extern/draco/dracoenc/src/draco/core/vector_d.h index 57dcd102663..189517f3928 100644 --- a/extern/draco/dracoenc/src/draco/core/vector_d.h +++ b/extern/draco/dracoenc/src/draco/core/vector_d.h @@ -24,16 +24,20 @@ namespace draco { // D-dimensional vector class with basic operations. -template <class CoeffT, int dimension_t> +template <class ScalarT, int dimension_t> class VectorD { public: - typedef VectorD<CoeffT, dimension_t> Self; - typedef CoeffT CoefficientType; static constexpr int dimension = dimension_t; + typedef ScalarT Scalar; + typedef VectorD<Scalar, dimension_t> Self; + + // TODO(hemmer): Deprecate. + typedef ScalarT CoefficientType; + VectorD() { - for (int i = 0; i < dimension_t; ++i) - (*this)[i] = CoeffT(0); + for (int i = 0; i < dimension; ++i) + (*this)[i] = Scalar(0); } // The following constructor does not compile in opt mode, which for now led @@ -42,58 +46,75 @@ class VectorD { // template <typename... Args> // explicit VectorD(Args... args) : v_({args...}) {} - VectorD(const CoeffT &c0, const CoeffT &c1) : v_({{c0, c1}}) { - DRACO_DCHECK_EQ(dimension_t, 2); + VectorD(const Scalar &c0, const Scalar &c1) : v_({{c0, c1}}) { + DRACO_DCHECK_EQ(dimension, 2); v_[0] = c0; v_[1] = c1; } - VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2) + VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2) : v_({{c0, c1, c2}}) { - DRACO_DCHECK_EQ(dimension_t, 3); + DRACO_DCHECK_EQ(dimension, 3); } - VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2, - const CoeffT &c3) + VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2, + const Scalar &c3) : v_({{c0, c1, c2, c3}}) { - DRACO_DCHECK_EQ(dimension_t, 4); + DRACO_DCHECK_EQ(dimension, 4); } - VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2, - const CoeffT &c3, const CoeffT &c4) + VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2, + const Scalar &c3, const Scalar &c4) : v_({{c0, c1, c2, c3, c4}}) { - DRACO_DCHECK_EQ(dimension_t, 5); + DRACO_DCHECK_EQ(dimension, 5); } - VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2, - const CoeffT &c3, const CoeffT &c4, const CoeffT &c5) + VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2, + const Scalar &c3, const Scalar &c4, const Scalar &c5) : v_({{c0, c1, c2, c3, c4, c5}}) { - DRACO_DCHECK_EQ(dimension_t, 6); + DRACO_DCHECK_EQ(dimension, 6); } - VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2, - const CoeffT &c3, const CoeffT &c4, const CoeffT &c5, - const CoeffT &c6) + VectorD(const Scalar &c0, const Scalar &c1, const Scalar &c2, + const Scalar &c3, const Scalar &c4, const Scalar &c5, + const Scalar &c6) : v_({{c0, c1, c2, c3, c4, c5, c6}}) { - DRACO_DCHECK_EQ(dimension_t, 7); + DRACO_DCHECK_EQ(dimension, 7); } VectorD(const Self &o) { - for (int i = 0; i < dimension_t; ++i) + for (int i = 0; i < dimension; ++i) (*this)[i] = o[i]; } - CoeffT &operator[](int i) { return v_[i]; } - const CoeffT &operator[](int i) const { return v_[i]; } + // Constructs the vector from another vector with a different data type or a + // different number of components. If the |src_vector| has more components + // than |this| vector, the excess components are truncated. If the + // |src_vector| has fewer components than |this| vector, the remaining + // components are padded with 0. + // Note that the constructor is intentionally explicit to avoid accidental + // conversions between different vector types. + template <class OtherScalarT, int other_dimension_t> + explicit VectorD(const VectorD<OtherScalarT, other_dimension_t> &src_vector) { + for (int i = 0; i < dimension; ++i) { + if (i < other_dimension_t) + v_[i] = Scalar(src_vector[i]); + else + v_[i] = Scalar(0); + } + } + + Scalar &operator[](int i) { return v_[i]; } + const Scalar &operator[](int i) const { return v_[i]; } // TODO(hemmer): remove. // Similar to interface of Eigen library. - CoeffT &operator()(int i) { return v_[i]; } - const CoeffT &operator()(int i) const { return v_[i]; } + Scalar &operator()(int i) { return v_[i]; } + const Scalar &operator()(int i) const { return v_[i]; } // Unary operators. Self operator-() const { Self ret; - for (int i = 0; i < dimension_t; ++i) { + for (int i = 0; i < dimension; ++i) { ret[i] = -(*this)[i]; } return ret; @@ -102,7 +123,7 @@ class VectorD { // Binary operators. Self operator+(const Self &o) const { Self ret; - for (int i = 0; i < dimension_t; ++i) { + for (int i = 0; i < dimension; ++i) { ret[i] = (*this)[i] + o[i]; } return ret; @@ -110,30 +131,46 @@ class VectorD { Self operator-(const Self &o) const { Self ret; - for (int i = 0; i < dimension_t; ++i) { + for (int i = 0; i < dimension; ++i) { ret[i] = (*this)[i] - o[i]; } return ret; } - Self operator*(const CoeffT &o) const { + Self operator*(const Scalar &o) const { Self ret; - for (int i = 0; i < dimension_t; ++i) { + for (int i = 0; i < dimension; ++i) { ret[i] = (*this)[i] * o; } return ret; } - Self operator/(const CoeffT &o) const { + Self operator/(const Scalar &o) const { Self ret; - for (int i = 0; i < dimension_t; ++i) { + for (int i = 0; i < dimension; ++i) { ret[i] = (*this)[i] / o; } return ret; } + Self operator+(const Scalar &o) const { + Self ret; + for (int i = 0; i < dimension; ++i) { + ret[i] = (*this)[i] + o; + } + return ret; + } + + Self operator-(const Scalar &o) const { + Self ret; + for (int i = 0; i < dimension; ++i) { + ret[i] = (*this)[i] - o; + } + return ret; + } + bool operator==(const Self &o) const { - for (int i = 0; i < dimension_t; ++i) { + for (int i = 0; i < dimension; ++i) { if ((*this)[i] != o[i]) return false; } @@ -143,67 +180,75 @@ class VectorD { bool operator!=(const Self &x) const { return !((*this) == x); } bool operator<(const Self &x) const { - for (int i = 0; i < dimension_t - 1; ++i) { + for (int i = 0; i < dimension - 1; ++i) { if (v_[i] < x.v_[i]) return true; if (v_[i] > x.v_[i]) return false; } // Only one check needed for the last dimension. - if (v_[dimension_t - 1] < x.v_[dimension_t - 1]) + if (v_[dimension - 1] < x.v_[dimension - 1]) return true; return false; } // Functions. - CoeffT SquaredNorm() const { return this->Dot(*this); } + Scalar SquaredNorm() const { return this->Dot(*this); } // Computes L1, the sum of absolute values of all entries. - CoeffT AbsSum() const { - CoeffT result(0); - for (int i = 0; i < dimension_t; ++i) { + Scalar AbsSum() const { + Scalar result(0); + for (int i = 0; i < dimension; ++i) { result += std::abs(v_[i]); } return result; } - CoeffT Dot(const Self &o) const { - CoeffT ret(0); - for (int i = 0; i < dimension_t; ++i) { + Scalar Dot(const Self &o) const { + Scalar ret(0); + for (int i = 0; i < dimension; ++i) { ret += (*this)[i] * o[i]; } return ret; } void Normalize() { - const CoeffT magnitude = std::sqrt(this->SquaredNorm()); + const Scalar magnitude = std::sqrt(this->SquaredNorm()); if (magnitude == 0) { return; } - for (int i = 0; i < dimension_t; ++i) { + for (int i = 0; i < dimension; ++i) { (*this)[i] /= magnitude; } } - CoeffT *data() { return &(v_[0]); } + const Scalar &MaxCoeff() const { + return *std::max_element(v_.begin(), v_.end()); + } + + const Scalar &MinCoeff() const { + return *std::min_element(v_.begin(), v_.end()); + } + + Scalar *data() { return &(v_[0]); } private: - std::array<CoeffT, dimension_t> v_; + std::array<Scalar, dimension> v_; }; // Scalar multiplication from the other side too. -template <class CoeffT, int dimension_t> -VectorD<CoeffT, dimension_t> operator*(const CoeffT &o, - const VectorD<CoeffT, dimension_t> &v) { +template <class ScalarT, int dimension_t> +VectorD<ScalarT, dimension_t> operator*( + const ScalarT &o, const VectorD<ScalarT, dimension_t> &v) { return v * o; } // Calculates the squared distance between two points. -template <class CoeffT, int dimension_t> -CoeffT SquaredDistance(const VectorD<CoeffT, dimension_t> &v1, - const VectorD<CoeffT, dimension_t> &v2) { - CoeffT difference; - CoeffT squared_distance = 0; +template <class ScalarT, int dimension_t> +ScalarT SquaredDistance(const VectorD<ScalarT, dimension_t> &v1, + const VectorD<ScalarT, dimension_t> &v2) { + ScalarT difference; + ScalarT squared_distance = 0; // Check each index separately so difference is never negative and underflow // is avoided for unsigned types. for (int i = 0; i < dimension_t; ++i) { @@ -218,22 +263,22 @@ CoeffT SquaredDistance(const VectorD<CoeffT, dimension_t> &v1, } // Global function computing the cross product of two 3D vectors. -template <class CoeffT> -VectorD<CoeffT, 3> CrossProduct(const VectorD<CoeffT, 3> &u, - const VectorD<CoeffT, 3> &v) { +template <class ScalarT> +VectorD<ScalarT, 3> CrossProduct(const VectorD<ScalarT, 3> &u, + const VectorD<ScalarT, 3> &v) { // Preventing accidental use with uint32_t and the like. - static_assert(std::is_signed<CoeffT>::value, - "CoeffT must be a signed type. "); - VectorD<CoeffT, 3> r; + static_assert(std::is_signed<ScalarT>::value, + "ScalarT must be a signed type. "); + VectorD<ScalarT, 3> r; r[0] = (u[1] * v[2]) - (u[2] * v[1]); r[1] = (u[2] * v[0]) - (u[0] * v[2]); r[2] = (u[0] * v[1]) - (u[1] * v[0]); return r; } -template <class CoeffT, int dimension_t> +template <class ScalarT, int dimension_t> inline std::ostream &operator<<( - std::ostream &out, const draco::VectorD<CoeffT, dimension_t> &vec) { + std::ostream &out, const draco::VectorD<ScalarT, dimension_t> &vec) { for (int i = 0; i < dimension_t - 1; ++i) { out << vec[i] << " "; } diff --git a/extern/draco/dracoenc/src/draco/core/vector_d_test.cc b/extern/draco/dracoenc/src/draco/core/vector_d_test.cc index 967043bb926..bc2bdadaa9f 100644 --- a/extern/draco/dracoenc/src/draco/core/vector_d_test.cc +++ b/extern/draco/dracoenc/src/draco/core/vector_d_test.cc @@ -32,20 +32,17 @@ typedef draco::Vector5ui Vector5ui; typedef draco::VectorD<int32_t, 3> Vector3i; typedef draco::VectorD<int32_t, 4> Vector4i; -class VectorDTest : public ::testing::Test { - protected: - template <class CoeffT, int dimension_t> - void TestSquaredDistance(const draco::VectorD<CoeffT, dimension_t> v1, - const draco::VectorD<CoeffT, dimension_t> v2, - const CoeffT result) { - CoeffT squared_distance = SquaredDistance(v1, v2); - ASSERT_EQ(squared_distance, result); - squared_distance = SquaredDistance(v2, v1); - ASSERT_EQ(squared_distance, result); - } -}; +template <class CoeffT, int dimension_t> +void TestSquaredDistance(const draco::VectorD<CoeffT, dimension_t> v1, + const draco::VectorD<CoeffT, dimension_t> v2, + const CoeffT result) { + CoeffT squared_distance = SquaredDistance(v1, v2); + ASSERT_EQ(squared_distance, result); + squared_distance = SquaredDistance(v2, v1); + ASSERT_EQ(squared_distance, result); +} -TEST_F(VectorDTest, TestOperators) { +TEST(VectorDTest, TestOperators) { { const Vector3f v; ASSERT_EQ(v[0], 0); @@ -58,10 +55,8 @@ TEST_F(VectorDTest, TestOperators) { ASSERT_EQ(v[2], 3); Vector3f w = v; - bool comp = (v == w); - ASSERT_TRUE(comp); - comp = (v != w); - ASSERT_TRUE(!comp); + ASSERT_TRUE(v == w); + ASSERT_FALSE(v != w); ASSERT_EQ(w[0], 1); ASSERT_EQ(w[1], 2); ASSERT_EQ(w[2], 3); @@ -81,10 +76,15 @@ TEST_F(VectorDTest, TestOperators) { ASSERT_EQ(w[1], 2); ASSERT_EQ(w[2], 3); + // Scalar multiplication from left and right. w = v * 2.f; ASSERT_EQ(w[0], 2); ASSERT_EQ(w[1], 4); ASSERT_EQ(w[2], 6); + w = 2.f * v; + ASSERT_EQ(w[0], 2); + ASSERT_EQ(w[1], 4); + ASSERT_EQ(w[2], 6); ASSERT_EQ(v.SquaredNorm(), 14); ASSERT_EQ(v.Dot(v), 14); @@ -109,7 +109,7 @@ TEST_F(VectorDTest, TestOperators) { } } -TEST_F(VectorDTest, TestSquaredDistance) { +TEST(VectorDTest, TestSquaredDistance) { // Test Vector2f: float, 2D. Vector2f v1_2f(5.5, 10.5); Vector2f v2_2f(3.5, 15.5); @@ -158,7 +158,8 @@ TEST_F(VectorDTest, TestSquaredDistance) { result_ui = 158; TestSquaredDistance(v1_5ui, v2_5ui, result_ui); } -TEST_F(VectorDTest, TestCrossProduct3D) { + +TEST(VectorDTest, TestCrossProduct3D) { const Vector3i e1(1, 0, 0); const Vector3i e2(0, 1, 0); const Vector3i e3(0, 0, 1); @@ -181,7 +182,7 @@ TEST_F(VectorDTest, TestCrossProduct3D) { ASSERT_EQ(0, v2.Dot(orth)); } -TEST_F(VectorDTest, TestAbsSum) { +TEST(VectorDTest, TestAbsSum) { // Testing const of function and zero. const Vector3i v(0, 0, 0); ASSERT_EQ(v.AbsSum(), 0); @@ -194,7 +195,18 @@ TEST_F(VectorDTest, TestAbsSum) { ASSERT_EQ(Vector4i(-2, 4, -8, 3).AbsSum(), 17); } -TEST_F(VectorDTest, TestOstream) { +TEST(VectorDTest, TestMinMaxCoeff) { + // Test verifies that MinCoeff() and MaxCoeff() functions work as intended. + const Vector4i vi(-10, 5, 2, 3); + ASSERT_EQ(vi.MinCoeff(), -10); + ASSERT_EQ(vi.MaxCoeff(), 5); + + const Vector3f vf(6.f, 1000.f, -101.f); + ASSERT_EQ(vf.MinCoeff(), -101.f); + ASSERT_EQ(vf.MaxCoeff(), 1000.f); +} + +TEST(VectorDTest, TestOstream) { // Tests that the vector can be stored in a provided std::ostream. const draco::VectorD<int64_t, 3> vector(1, 2, 3); std::stringstream str; @@ -202,4 +214,22 @@ TEST_F(VectorDTest, TestOstream) { ASSERT_EQ(str.str(), "1 2 3 "); } +TEST(VectorDTest, TestConvertConstructor) { + // Tests that a vector can be constructed from another vector with a different + // type. + const draco::VectorD<int64_t, 3> vector(1, 2, 3); + + const draco::VectorD<float, 3> vector3f(vector); + ASSERT_EQ(vector3f, draco::Vector3f(1.f, 2.f, 3.f)); + + const draco::VectorD<float, 2> vector2f(vector); + ASSERT_EQ(vector2f, draco::Vector2f(1.f, 2.f)); + + const draco::VectorD<float, 4> vector4f(vector3f); + ASSERT_EQ(vector4f, draco::Vector4f(1.f, 2.f, 3.f, 0.f)); + + const draco::VectorD<double, 1> vector1d(vector3f); + ASSERT_EQ(vector1d[0], 1.0); +} + } // namespace diff --git a/extern/draco/dracoenc/src/draco/io/mesh_io.cc b/extern/draco/dracoenc/src/draco/io/mesh_io.cc index 807dcfbe06b..5e2f9f51d7a 100644 --- a/extern/draco/dracoenc/src/draco/io/mesh_io.cc +++ b/extern/draco/dracoenc/src/draco/io/mesh_io.cc @@ -16,37 +16,33 @@ #include <fstream> +#include "draco/io/file_utils.h" #include "draco/io/obj_decoder.h" -#include "draco/io/parser_utils.h" #include "draco/io/ply_decoder.h" namespace draco { -namespace { - -// Returns the file extension in lowercase if present, else "" -inline std::string LowercaseFileExtension(const std::string &filename) { - size_t pos = filename.find_last_of('.'); - if (pos == std::string::npos || pos >= filename.length() - 1) - return ""; - return parser::ToLower(filename.substr(pos + 1)); -} - -} // namespace - StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name) { - return ReadMeshFromFile(file_name, false); + const Options options; + return ReadMeshFromFile(file_name, options); } StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name, bool use_metadata) { + Options options; + options.SetBool("use_metadata", use_metadata); + return ReadMeshFromFile(file_name, options); +} + +StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name, + const Options &options) { std::unique_ptr<Mesh> mesh(new Mesh()); // Analyze file extension. const std::string extension = LowercaseFileExtension(file_name); if (extension == "obj") { // Wavefront OBJ file format. ObjDecoder obj_decoder; - obj_decoder.set_use_metadata(use_metadata); + obj_decoder.set_use_metadata(options.GetBool("use_metadata", false)); const Status obj_status = obj_decoder.DecodeFromFile(file_name, mesh.get()); if (!obj_status.ok()) return obj_status; @@ -55,8 +51,7 @@ StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name, if (extension == "ply") { // Wavefront PLY file format. PlyDecoder ply_decoder; - if (!ply_decoder.DecodeFromFile(file_name, mesh.get())) - return Status(Status::ERROR, "Unknown error."); + DRACO_RETURN_IF_ERROR(ply_decoder.DecodeFromFile(file_name, mesh.get())); return std::move(mesh); } @@ -64,9 +59,9 @@ StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name, // draco encoding methods. std::ifstream is(file_name.c_str(), std::ios::binary); if (!is) - return Status(Status::ERROR, "Invalid input stream."); + return Status(Status::DRACO_ERROR, "Invalid input stream."); if (!ReadMeshFromStream(&mesh, is).good()) - return Status(Status::ERROR, + return Status(Status::DRACO_ERROR, "Unknown error."); // Error reading the stream. return std::move(mesh); } diff --git a/extern/draco/dracoenc/src/draco/io/mesh_io.h b/extern/draco/dracoenc/src/draco/io/mesh_io.h index 7649a736265..15cfbb30b97 100644 --- a/extern/draco/dracoenc/src/draco/io/mesh_io.h +++ b/extern/draco/dracoenc/src/draco/io/mesh_io.h @@ -18,6 +18,7 @@ #include "draco/compression/config/compression_shared.h" #include "draco/compression/decode.h" #include "draco/compression/expert_encode.h" +#include "draco/core/options.h" namespace draco { @@ -89,6 +90,13 @@ StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name); StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name, bool use_metadata); +// Reads a mesh from a file. Reading is configured with |options|: +// use_metadata : Read obj file info like material names and object names into +// metadata. Default is false. +// Returns nullptr with an error status if the decoding failed. +StatusOr<std::unique_ptr<Mesh>> ReadMeshFromFile(const std::string &file_name, + const Options &options); + } // namespace draco #endif // DRACO_MESH_MESH_IO_H_ diff --git a/extern/draco/dracoenc/src/draco/io/obj_decoder.cc b/extern/draco/dracoenc/src/draco/io/obj_decoder.cc index 5aaa9f72888..88f470f8b4a 100644 --- a/extern/draco/dracoenc/src/draco/io/obj_decoder.cc +++ b/extern/draco/dracoenc/src/draco/io/obj_decoder.cc @@ -18,6 +18,7 @@ #include <cmath> #include <fstream> +#include "draco/io/file_utils.h" #include "draco/io/parser_utils.h" #include "draco/metadata/geometry_metadata.h" @@ -103,12 +104,12 @@ Status ObjDecoder::DecodeInternal() { // Ensure the number of all entries is same for all attributes. if (num_positions_ == 0) - return Status(Status::ERROR, "No position attribute"); + return Status(Status::DRACO_ERROR, "No position attribute"); if (num_tex_coords_ > 0 && num_tex_coords_ != num_positions_) - return Status(Status::ERROR, + return Status(Status::DRACO_ERROR, "Invalid number of texture coordinates for a point cloud"); if (num_normals_ > 0 && num_normals_ != num_positions_) - return Status(Status::ERROR, + return Status(Status::DRACO_ERROR, "Invalid number of normals for a point cloud"); out_mesh_ = nullptr; // Treat the output geometry as a point cloud. @@ -151,12 +152,13 @@ Status ObjDecoder::DecodeInternal() { } if (num_materials_ > 0 && num_obj_faces_ > 0) { GeometryAttribute va; + const auto geometry_attribute_type = GeometryAttribute::GENERIC; if (num_materials_ < 256) { - va.Init(GeometryAttribute::GENERIC, nullptr, 1, DT_UINT8, false, 1, 0); + va.Init(geometry_attribute_type, nullptr, 1, DT_UINT8, false, 1, 0); } else if (num_materials_ < (1 << 16)) { - va.Init(GeometryAttribute::GENERIC, nullptr, 1, DT_UINT16, false, 2, 0); + va.Init(geometry_attribute_type, nullptr, 1, DT_UINT16, false, 2, 0); } else { - va.Init(GeometryAttribute::GENERIC, nullptr, 1, DT_UINT32, false, 4, 0); + va.Init(geometry_attribute_type, nullptr, 1, DT_UINT32, false, 4, 0); } material_att_id_ = out_point_cloud_->AddAttribute(va, false, num_materials_); @@ -234,10 +236,13 @@ Status ObjDecoder::DecodeInternal() { out_mesh_->SetFace(i, face); } } -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED + +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED if (deduplicate_input_values_) { out_point_cloud_->DeduplicateAttributeValues(); } +#endif +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED out_point_cloud_->DeduplicatePointIds(); #endif return status; @@ -298,7 +303,7 @@ bool ObjDecoder::ParseVertexPosition(Status *status) { for (int i = 0; i < 3; ++i) { parser::SkipWhitespace(buffer()); if (!parser::ParseFloat(buffer(), val + i)) { - *status = Status(Status::ERROR, "Failed to parse a float number"); + *status = Status(Status::DRACO_ERROR, "Failed to parse a float number"); // The definition is processed so return true. return true; } @@ -326,7 +331,7 @@ bool ObjDecoder::ParseNormal(Status *status) { for (int i = 0; i < 3; ++i) { parser::SkipWhitespace(buffer()); if (!parser::ParseFloat(buffer(), val + i)) { - *status = Status(Status::ERROR, "Failed to parse a float number"); + *status = Status(Status::DRACO_ERROR, "Failed to parse a float number"); // The definition is processed so return true. return true; } @@ -354,7 +359,7 @@ bool ObjDecoder::ParseTexCoord(Status *status) { for (int i = 0; i < 2; ++i) { parser::SkipWhitespace(buffer()); if (!parser::ParseFloat(buffer(), val + i)) { - *status = Status(Status::ERROR, "Failed to parse a float number"); + *status = Status(Status::DRACO_ERROR, "Failed to parse a float number"); // The definition is processed so return true. return true; } @@ -385,7 +390,7 @@ bool ObjDecoder::ParseFace(Status *status) { if (i == 3) { break; // It's OK if there is no fourth vertex index. } - *status = Status(Status::ERROR, "Failed to parse vertex indices"); + *status = Status(Status::DRACO_ERROR, "Failed to parse vertex indices"); return true; } ++num_valid_indices; @@ -430,7 +435,8 @@ bool ObjDecoder::ParseFace(Status *status) { } } if (num_indices < 3 || num_indices > 4) { - *status = Status(Status::ERROR, "Invalid number of indices on a face"); + *status = + Status(Status::DRACO_ERROR, "Invalid number of indices on a face"); return false; } // Either one or two new triangles. @@ -455,7 +461,7 @@ bool ObjDecoder::ParseMaterialLib(Status *status) { parser::SkipWhitespace(&line_buffer); material_file_name_.clear(); if (!parser::ParseString(&line_buffer, &material_file_name_)) { - *status = Status(Status::ERROR, "Failed to parse material file name"); + *status = Status(Status::DRACO_ERROR, "Failed to parse material file name"); return true; } parser::SkipLine(&line_buffer); @@ -492,6 +498,7 @@ bool ObjDecoder::ParseMaterial(Status * /* status */) { // will be added to the list. last_material_id_ = num_materials_; material_name_to_id_[mat_name] = num_materials_++; + return true; } last_material_id_ = it->second; @@ -626,15 +633,7 @@ void ObjDecoder::MapPointToVertexIndices( bool ObjDecoder::ParseMaterialFile(const std::string &file_name, Status *status) { - // Get the correct path to the |file_name| using the folder from - // |input_file_name_| as the root folder. - const auto pos = input_file_name_.find_last_of("/\\"); - std::string full_path; - if (pos != std::string::npos) { - full_path = input_file_name_.substr(0, pos + 1); - } - full_path += file_name; - + const std::string full_path = GetFullPath(file_name, input_file_name_); std::ifstream file(full_path, std::ios::binary); if (!file) return false; @@ -676,15 +675,14 @@ bool ObjDecoder::ParseMaterialFileDefinition(Status * /* status */) { std::string str; if (!parser::ParseString(buffer(), &str)) return false; - if (str.compare("newmtl") == 0) { + if (str == "newmtl") { parser::SkipWhitespace(buffer()); parser::ParseLine(buffer(), &str); - if (str.length() == 0) + if (str.empty()) return false; // Add new material to our map. material_name_to_id_[str] = num_materials_++; } - parser::SkipLine(buffer()); return true; } diff --git a/extern/draco/dracoenc/src/draco/io/obj_encoder.h b/extern/draco/dracoenc/src/draco/io/obj_encoder.h index 352a04774c2..509d39baf39 100644 --- a/extern/draco/dracoenc/src/draco/io/obj_encoder.h +++ b/extern/draco/dracoenc/src/draco/io/obj_encoder.h @@ -15,6 +15,8 @@ #ifndef DRACO_IO_OBJ_ENCODER_H_ #define DRACO_IO_OBJ_ENCODER_H_ +#include <unordered_map> + #include "draco/core/encoder_buffer.h" #include "draco/mesh/mesh.h" diff --git a/extern/draco/dracoenc/src/draco/io/parser_utils.cc b/extern/draco/dracoenc/src/draco/io/parser_utils.cc index e68abb1f263..0a22ba114ab 100644 --- a/extern/draco/dracoenc/src/draco/io/parser_utils.cc +++ b/extern/draco/dracoenc/src/draco/io/parser_utils.cc @@ -128,7 +128,7 @@ bool ParseFloat(DecoderBuffer *buffer, float *value) { return false; // Apply exponent scaling to value. - v *= pow(10.0, exponent); + v *= pow(static_cast<double>(10.0), exponent); } } diff --git a/extern/draco/dracoenc/src/draco/io/ply_decoder.cc b/extern/draco/dracoenc/src/draco/io/ply_decoder.cc index 01a97e3dacc..69a1c546cf7 100644 --- a/extern/draco/dracoenc/src/draco/io/ply_decoder.cc +++ b/extern/draco/dracoenc/src/draco/io/ply_decoder.cc @@ -17,28 +17,30 @@ #include <fstream> #include "draco/core/macros.h" +#include "draco/core/status.h" #include "draco/io/ply_property_reader.h" namespace draco { PlyDecoder::PlyDecoder() : out_mesh_(nullptr), out_point_cloud_(nullptr) {} -bool PlyDecoder::DecodeFromFile(const std::string &file_name, Mesh *out_mesh) { +Status PlyDecoder::DecodeFromFile(const std::string &file_name, + Mesh *out_mesh) { out_mesh_ = out_mesh; return DecodeFromFile(file_name, static_cast<PointCloud *>(out_mesh)); } -bool PlyDecoder::DecodeFromFile(const std::string &file_name, - PointCloud *out_point_cloud) { +Status PlyDecoder::DecodeFromFile(const std::string &file_name, + PointCloud *out_point_cloud) { std::ifstream file(file_name, std::ios::binary); if (!file) - return false; + return Status(Status::IO_ERROR, "Couldn't open file"); // Read the whole file into a buffer. auto pos0 = file.tellg(); file.seekg(0, std::ios::end); auto file_size = file.tellg() - pos0; if (file_size == 0) - return false; + return Status(Status::IO_ERROR, "Zero file size"); file.seekg(0, std::ios::beg); std::vector<char> data(file_size); file.read(&data[0], file_size); @@ -47,44 +49,46 @@ bool PlyDecoder::DecodeFromFile(const std::string &file_name, return DecodeFromBuffer(&buffer_, out_point_cloud); } -bool PlyDecoder::DecodeFromBuffer(DecoderBuffer *buffer, Mesh *out_mesh) { +Status PlyDecoder::DecodeFromBuffer(DecoderBuffer *buffer, Mesh *out_mesh) { out_mesh_ = out_mesh; return DecodeFromBuffer(buffer, static_cast<PointCloud *>(out_mesh)); } -bool PlyDecoder::DecodeFromBuffer(DecoderBuffer *buffer, - PointCloud *out_point_cloud) { +Status PlyDecoder::DecodeFromBuffer(DecoderBuffer *buffer, + PointCloud *out_point_cloud) { out_point_cloud_ = out_point_cloud; buffer_.Init(buffer->data_head(), buffer->remaining_size()); return DecodeInternal(); } -bool PlyDecoder::DecodeInternal() { +Status PlyDecoder::DecodeInternal() { PlyReader ply_reader; - if (!ply_reader.Read(buffer())) - return false; + DRACO_RETURN_IF_ERROR(ply_reader.Read(buffer())); // First, decode the connectivity data. - if (out_mesh_ && !DecodeFaceData(ply_reader.GetElementByName("face"))) - return false; + if (out_mesh_) + DRACO_RETURN_IF_ERROR(DecodeFaceData(ply_reader.GetElementByName("face"))); // Decode all attributes. - if (!DecodeVertexData(ply_reader.GetElementByName("vertex"))) - return false; -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED + DRACO_RETURN_IF_ERROR( + DecodeVertexData(ply_reader.GetElementByName("vertex"))); // In case there are no faces this is just a point cloud which does // not require deduplication. if (out_mesh_ && out_mesh_->num_faces() != 0) { +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED if (!out_point_cloud_->DeduplicateAttributeValues()) - return false; + return Status(Status::DRACO_ERROR, + "Could not deduplicate attribute values"); +#endif +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED out_point_cloud_->DeduplicatePointIds(); - } #endif - return true; + } + return OkStatus(); } -bool PlyDecoder::DecodeFaceData(const PlyElement *face_element) { +Status PlyDecoder::DecodeFaceData(const PlyElement *face_element) { // We accept point clouds now. if (face_element == nullptr) { - return true; + return Status(Status::INVALID_PARAMETER, "face_element is null"); } const int64_t num_faces = face_element->num_entries(); out_mesh_->SetNumFaces(num_faces); @@ -95,7 +99,7 @@ bool PlyDecoder::DecodeFaceData(const PlyElement *face_element) { vertex_indices = face_element->GetPropertyByName("vertex_index"); } if (vertex_indices == nullptr || !vertex_indices->is_list()) { - return false; // No faces defined. + return Status(Status::DRACO_ERROR, "No faces defined"); } PlyPropertyReader<PointIndex::ValueType> vertex_index_reader(vertex_indices); @@ -114,7 +118,7 @@ bool PlyDecoder::DecodeFaceData(const PlyElement *face_element) { face_index++; } out_mesh_->SetNumFaces(face_index.value()); - return true; + return OkStatus(); } template <typename DataTypeT> @@ -138,9 +142,9 @@ bool PlyDecoder::ReadPropertiesToAttribute( return true; } -bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) { +Status PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) { if (vertex_element == nullptr) - return false; + return Status(Status::INVALID_PARAMETER, "vertex_element is null"); // TODO(ostava): For now, try to load x,y,z vertices and red,green,blue,alpha // colors. We need to add other properties later. const PlyProperty *const x_prop = vertex_element->GetPropertyByName("x"); @@ -149,7 +153,7 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) { if (!x_prop || !y_prop || !z_prop) { // Currently, we require 3 vertex coordinates (this should be generalized // later on). - return false; + return Status(Status::INVALID_PARAMETER, "x, y, or z property is missing"); } const PointIndex::ValueType num_vertices = vertex_element->num_entries(); out_point_cloud_->set_num_points(num_vertices); @@ -158,12 +162,14 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) { // All properties must have the same type. if (x_prop->data_type() != y_prop->data_type() || y_prop->data_type() != z_prop->data_type()) { - return false; + return Status(Status::INVALID_PARAMETER, + "x, y, and z properties must have the same type"); } // TODO(ostava): For now assume the position types are float32 or int32. const DataType dt = x_prop->data_type(); if (dt != DT_FLOAT32 && dt != DT_INT32) - return false; + return Status(Status::INVALID_PARAMETER, + "x, y, and z properties must be of type float32 or int32"); GeometryAttribute va; va.Init(GeometryAttribute::POSITION, nullptr, 3, dt, false, @@ -232,7 +238,8 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) { // TODO(ostava): For now ensure the data type of all components is uint8. DRACO_DCHECK_EQ(true, p->data_type() == DT_UINT8); if (p->data_type() != DT_UINT8) - return false; + return Status(Status::INVALID_PARAMETER, + "Type of 'red' property must be uint8"); color_readers.push_back(std::unique_ptr<PlyPropertyReader<uint8_t>>( new PlyPropertyReader<uint8_t>(p))); } @@ -241,7 +248,8 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) { // TODO(ostava): For now ensure the data type of all components is uint8. DRACO_DCHECK_EQ(true, p->data_type() == DT_UINT8); if (p->data_type() != DT_UINT8) - return false; + return Status(Status::INVALID_PARAMETER, + "Type of 'green' property must be uint8"); color_readers.push_back(std::unique_ptr<PlyPropertyReader<uint8_t>>( new PlyPropertyReader<uint8_t>(p))); } @@ -250,7 +258,8 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) { // TODO(ostava): For now ensure the data type of all components is uint8. DRACO_DCHECK_EQ(true, p->data_type() == DT_UINT8); if (p->data_type() != DT_UINT8) - return false; + return Status(Status::INVALID_PARAMETER, + "Type of 'blue' property must be uint8"); color_readers.push_back(std::unique_ptr<PlyPropertyReader<uint8_t>>( new PlyPropertyReader<uint8_t>(p))); } @@ -259,7 +268,8 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) { // TODO(ostava): For now ensure the data type of all components is uint8. DRACO_DCHECK_EQ(true, p->data_type() == DT_UINT8); if (p->data_type() != DT_UINT8) - return false; + return Status(Status::INVALID_PARAMETER, + "Type of 'alpha' property must be uint8"); color_readers.push_back(std::unique_ptr<PlyPropertyReader<uint8_t>>( new PlyPropertyReader<uint8_t>(p))); } @@ -279,7 +289,7 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) { } } - return true; + return OkStatus(); } } // namespace draco diff --git a/extern/draco/dracoenc/src/draco/io/ply_decoder.h b/extern/draco/dracoenc/src/draco/io/ply_decoder.h index 60a48de730e..9e667ab192f 100644 --- a/extern/draco/dracoenc/src/draco/io/ply_decoder.h +++ b/extern/draco/dracoenc/src/draco/io/ply_decoder.h @@ -20,6 +20,7 @@ #include "draco/draco_features.h" #include "draco/core/decoder_buffer.h" +#include "draco/core/status.h" #include "draco/io/ply_reader.h" #include "draco/mesh/mesh.h" @@ -35,21 +36,20 @@ class PlyDecoder { PlyDecoder(); // Decodes an obj file stored in the input file. - // Returns nullptr if the decoding failed. - bool DecodeFromFile(const std::string &file_name, Mesh *out_mesh); - bool DecodeFromFile(const std::string &file_name, - PointCloud *out_point_cloud); + Status DecodeFromFile(const std::string &file_name, Mesh *out_mesh); + Status DecodeFromFile(const std::string &file_name, + PointCloud *out_point_cloud); - bool DecodeFromBuffer(DecoderBuffer *buffer, Mesh *out_mesh); - bool DecodeFromBuffer(DecoderBuffer *buffer, PointCloud *out_point_cloud); + Status DecodeFromBuffer(DecoderBuffer *buffer, Mesh *out_mesh); + Status DecodeFromBuffer(DecoderBuffer *buffer, PointCloud *out_point_cloud); protected: - bool DecodeInternal(); + Status DecodeInternal(); DecoderBuffer *buffer() { return &buffer_; } private: - bool DecodeFaceData(const PlyElement *face_element); - bool DecodeVertexData(const PlyElement *vertex_element); + Status DecodeFaceData(const PlyElement *face_element); + Status DecodeVertexData(const PlyElement *vertex_element); template <typename DataTypeT> bool ReadPropertiesToAttribute( diff --git a/extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc b/extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc index 39a52274ce6..647324ea904 100644 --- a/extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc +++ b/extern/draco/dracoenc/src/draco/io/ply_decoder_test.cc @@ -26,8 +26,11 @@ class PlyDecoderTest : public ::testing::Test { const std::string path = GetTestFileFullPath(file_name); PlyDecoder decoder; std::unique_ptr<Geometry> geometry(new Geometry()); - if (!decoder.DecodeFromFile(path, geometry.get())) + Status status = decoder.DecodeFromFile(path, geometry.get()); + if (!status.ok()) { + LOG(DRACO_ERROR) << "Failed to decode " << file_name << ": " << status; return nullptr; + } return geometry; } diff --git a/extern/draco/dracoenc/src/draco/io/ply_reader.cc b/extern/draco/dracoenc/src/draco/io/ply_reader.cc index f924550e23f..772c4381176 100644 --- a/extern/draco/dracoenc/src/draco/io/ply_reader.cc +++ b/extern/draco/dracoenc/src/draco/io/ply_reader.cc @@ -17,6 +17,7 @@ #include <array> #include <regex> +#include "draco/core/status.h" #include "draco/io/parser_utils.h" #include "draco/io/ply_property_writer.h" @@ -34,13 +35,11 @@ PlyElement::PlyElement(const std::string &name, int64_t num_entries) PlyReader::PlyReader() : format_(kLittleEndian) {} -bool PlyReader::Read(DecoderBuffer *buffer) { - error_message_.clear(); +Status PlyReader::Read(DecoderBuffer *buffer) { std::string value; // The first line needs to by "ply". if (!parser::ParseString(buffer, &value) || value != "ply") { - error_message_ = "Not a valid ply file."; - return false; + return Status(Status::INVALID_PARAMETER, "Not a valid ply file"); } parser::SkipLine(buffer); @@ -52,52 +51,49 @@ bool PlyReader::Read(DecoderBuffer *buffer) { format = words[1]; version = words[2]; } else { - error_message_ = "Missing or wrong format line."; - return false; + return Status(Status::INVALID_PARAMETER, "Missing or wrong format line"); } if (version != "1.0") { - error_message_ = "Unsupported PLY version."; - return false; // Wrong version. + return Status(Status::UNSUPPORTED_VERSION, "Unsupported PLY version"); } if (format == "binary_big_endian") { - error_message_ = - "Unsupported format. Currently we support only ascii and" - " binary_little_endian format."; - return false; + return Status(Status::UNSUPPORTED_VERSION, + "Unsupported format. Currently we support only ascii and" + " binary_little_endian format."); } if (format == "ascii") { format_ = kAscii; } else { format_ = kLittleEndian; } - if (!ParseHeader(buffer)) - return false; - if (!ParsePropertiesData(buffer)) - return false; - return true; + DRACO_RETURN_IF_ERROR(ParseHeader(buffer)); + if (!ParsePropertiesData(buffer)) { + return Status(Status::INVALID_PARAMETER, "Couldn't parse properties"); + } + return OkStatus(); } -bool PlyReader::ParseHeader(DecoderBuffer *buffer) { - while (error_message_.length() == 0 && !ParseEndHeader(buffer)) { +Status PlyReader::ParseHeader(DecoderBuffer *buffer) { + while (true) { + DRACO_ASSIGN_OR_RETURN(bool end, ParseEndHeader(buffer)); + if (end) + break; if (ParseElement(buffer)) continue; - if (ParseProperty(buffer)) + DRACO_ASSIGN_OR_RETURN(bool property_parsed, ParseProperty(buffer)); + if (property_parsed) continue; parser::SkipLine(buffer); } - if (error_message_.length() > 0) { - printf("ERROR %s\n", error_message_.c_str()); - return false; - } - return true; + return OkStatus(); } -bool PlyReader::ParseEndHeader(DecoderBuffer *buffer) { +StatusOr<bool> PlyReader::ParseEndHeader(DecoderBuffer *buffer) { parser::SkipWhitespace(buffer); std::array<char, 10> c; if (!buffer->Peek(&c)) { - error_message_ = "End of file reached before the end_header."; - return false; + return Status(Status::INVALID_PARAMETER, + "End of file reached before the end_header"); } if (std::memcmp(&c[0], "end_header", 10) != 0) return false; @@ -126,7 +122,7 @@ bool PlyReader::ParseElement(DecoderBuffer *buffer) { return true; } -bool PlyReader::ParseProperty(DecoderBuffer *buffer) { +StatusOr<bool> PlyReader::ParseProperty(DecoderBuffer *buffer) { if (elements_.empty()) return false; // Ignore properties if there is no active element. DecoderBuffer line_buffer(*buffer); @@ -154,15 +150,13 @@ bool PlyReader::ParseProperty(DecoderBuffer *buffer) { } const DataType data_type = GetDataTypeFromString(data_type_str); if (data_type == DT_INVALID) { - error_message_ = "Wrong property data type."; - return true; // Parsed. + return Status(Status::INVALID_PARAMETER, "Wrong property data type"); } DataType list_type = DT_INVALID; if (property_list_search) { list_type = GetDataTypeFromString(list_type_str); if (list_type == DT_INVALID) { - error_message_ = "Wrong property list type."; - return true; // Parsed. + return Status(Status::INVALID_PARAMETER, "Wrong property list type"); } } elements_.back().AddProperty( diff --git a/extern/draco/dracoenc/src/draco/io/ply_reader.h b/extern/draco/dracoenc/src/draco/io/ply_reader.h index 8d0f21ff1cb..845ef2326ae 100644 --- a/extern/draco/dracoenc/src/draco/io/ply_reader.h +++ b/extern/draco/dracoenc/src/draco/io/ply_reader.h @@ -26,6 +26,8 @@ #include "draco/core/decoder_buffer.h" #include "draco/core/draco_types.h" +#include "draco/core/status.h" +#include "draco/core/status_or.h" namespace draco { @@ -111,7 +113,7 @@ class PlyElement { class PlyReader { public: PlyReader(); - bool Read(DecoderBuffer *buffer); + Status Read(DecoderBuffer *buffer); const PlyElement *GetElementByName(const std::string &name) const { const auto it = element_index_.find(name); @@ -128,10 +130,10 @@ class PlyReader { private: enum Format { kLittleEndian = 0, kAscii }; - bool ParseHeader(DecoderBuffer *buffer); - bool ParseEndHeader(DecoderBuffer *buffer); + Status ParseHeader(DecoderBuffer *buffer); + StatusOr<bool> ParseEndHeader(DecoderBuffer *buffer); bool ParseElement(DecoderBuffer *buffer); - bool ParseProperty(DecoderBuffer *buffer); + StatusOr<bool> ParseProperty(DecoderBuffer *buffer); bool ParsePropertiesData(DecoderBuffer *buffer); bool ParseElementData(DecoderBuffer *buffer, int element_index); bool ParseElementDataAscii(DecoderBuffer *buffer, int element_index); @@ -141,7 +143,6 @@ class PlyReader { DataType GetDataTypeFromString(const std::string &name) const; std::vector<PlyElement> elements_; - std::string error_message_; std::map<std::string, int> element_index_; Format format_; }; diff --git a/extern/draco/dracoenc/src/draco/io/ply_reader_test.cc b/extern/draco/dracoenc/src/draco/io/ply_reader_test.cc index 98f9c601971..6804dc33de3 100644 --- a/extern/draco/dracoenc/src/draco/io/ply_reader_test.cc +++ b/extern/draco/dracoenc/src/draco/io/ply_reader_test.cc @@ -45,7 +45,8 @@ TEST_F(PlyReaderTest, TestReader) { DecoderBuffer buf; buf.Init(data.data(), data.size()); PlyReader reader; - ASSERT_TRUE(reader.Read(&buf)); + Status status = reader.Read(&buf); + ASSERT_TRUE(status.ok()) << status; ASSERT_EQ(reader.num_elements(), 2); ASSERT_EQ(reader.element(0).num_properties(), 7); ASSERT_EQ(reader.element(1).num_properties(), 1); @@ -68,13 +69,15 @@ TEST_F(PlyReaderTest, TestReaderAscii) { DecoderBuffer buf; buf.Init(data.data(), data.size()); PlyReader reader; - ASSERT_TRUE(reader.Read(&buf)); + Status status = reader.Read(&buf); + ASSERT_TRUE(status.ok()) << status; const std::string file_name_ascii = "test_pos_color_ascii.ply"; const std::vector<char> data_ascii = ReadPlyFile(file_name_ascii); buf.Init(data_ascii.data(), data_ascii.size()); PlyReader reader_ascii; - ASSERT_TRUE(reader_ascii.Read(&buf)); + status = reader_ascii.Read(&buf); + ASSERT_TRUE(status.ok()) << status; ASSERT_EQ(reader.num_elements(), reader_ascii.num_elements()); ASSERT_EQ(reader.element(0).num_properties(), reader_ascii.element(0).num_properties()); @@ -97,7 +100,8 @@ TEST_F(PlyReaderTest, TestReaderExtraWhitespace) { DecoderBuffer buf; buf.Init(data.data(), data.size()); PlyReader reader; - ASSERT_TRUE(reader.Read(&buf)); + Status status = reader.Read(&buf); + ASSERT_TRUE(status.ok()) << status; ASSERT_EQ(reader.num_elements(), 2); ASSERT_EQ(reader.element(0).num_properties(), 7); @@ -121,7 +125,8 @@ TEST_F(PlyReaderTest, TestReaderMoreDataTypes) { DecoderBuffer buf; buf.Init(data.data(), data.size()); PlyReader reader; - ASSERT_TRUE(reader.Read(&buf)); + Status status = reader.Read(&buf); + ASSERT_TRUE(status.ok()) << status; ASSERT_EQ(reader.num_elements(), 2); ASSERT_EQ(reader.element(0).num_properties(), 7); diff --git a/extern/draco/dracoenc/src/draco/io/point_cloud_io.cc b/extern/draco/dracoenc/src/draco/io/point_cloud_io.cc index 068f7a139e4..e91142eaaea 100644 --- a/extern/draco/dracoenc/src/draco/io/point_cloud_io.cc +++ b/extern/draco/dracoenc/src/draco/io/point_cloud_io.cc @@ -40,8 +40,7 @@ StatusOr<std::unique_ptr<PointCloud>> ReadPointCloudFromFile( if (extension == ".ply") { // Wavefront PLY file format. PlyDecoder ply_decoder; - if (!ply_decoder.DecodeFromFile(file_name, pc.get())) - return Status(Status::ERROR, "Unknown error."); + DRACO_RETURN_IF_ERROR(ply_decoder.DecodeFromFile(file_name, pc.get())); return std::move(pc); } @@ -49,9 +48,9 @@ StatusOr<std::unique_ptr<PointCloud>> ReadPointCloudFromFile( // draco encoding methods. std::ifstream is(file_name.c_str(), std::ios::binary); if (!is) - return Status(Status::ERROR, "Invalid input stream."); + return Status(Status::DRACO_ERROR, "Invalid input stream."); if (!ReadPointCloudFromStream(&pc, is).good()) - return Status(Status::ERROR, + return Status(Status::DRACO_ERROR, "Unknown error."); // Error reading the stream. return std::move(pc); } diff --git a/extern/draco/dracoenc/src/draco/mesh/corner_table.cc b/extern/draco/dracoenc/src/draco/mesh/corner_table.cc index e4608fe8f9d..dcfd7967c0b 100644 --- a/extern/draco/dracoenc/src/draco/mesh/corner_table.cc +++ b/extern/draco/dracoenc/src/draco/mesh/corner_table.cc @@ -16,6 +16,7 @@ #include <limits> +#include "draco/attributes/geometry_indices.h" #include "draco/mesh/corner_table_iterators.h" namespace draco { @@ -46,6 +47,8 @@ bool CornerTable::Init(const IndexTypeVector<FaceIndex, FaceType> &faces) { int num_vertices = -1; if (!ComputeOppositeCorners(&num_vertices)) return false; + if (!BreakNonManifoldEdges()) + return false; if (!ComputeVertexCorners(num_vertices)) return false; return true; @@ -193,6 +196,110 @@ bool CornerTable::ComputeOppositeCorners(int *num_vertices) { return true; } +bool CornerTable::BreakNonManifoldEdges() { + // This function detects and breaks non-manifold edges that are caused by + // folds in 1-ring neighborhood around a vertex. Non-manifold edges can occur + // when the 1-ring surface around a vertex self-intersects in a common edge. + // For example imagine a surface around a pivot vertex 0, where the 1-ring + // is defined by vertices |1, 2, 3, 1, 4|. The surface passes edge <0, 1> + // twice which would result in a non-manifold edge that needs to be broken. + // For now all faces connected to these non-manifold edges are disconnected + // resulting in open boundaries on the mesh. New vertices will be created + // automatically for each new disjoint patch in the ComputeVertexCorners() + // method. + // Note that all other non-manifold edges are implicitly handled by the + // function ComputeVertexCorners() that automatically creates new vertices + // on disjoint 1-ring surface patches. + + std::vector<bool> visited_corners(num_corners(), false); + std::vector<std::pair<VertexIndex, CornerIndex>> sink_vertices; + bool mesh_connectivity_updated = false; + do { + mesh_connectivity_updated = false; + for (CornerIndex c(0); c < num_corners(); ++c) { + if (visited_corners[c.value()]) + continue; + sink_vertices.clear(); + + // First swing all the way to find the left-most corner connected to the + // corner's vertex. + CornerIndex first_c = c; + CornerIndex current_c = c; + CornerIndex next_c; + while (next_c = SwingLeft(current_c), + next_c != first_c && next_c != kInvalidCornerIndex && + !visited_corners[next_c.value()]) { + current_c = next_c; + } + + first_c = current_c; + + // Swing right from the first corner and check if all visited edges + // are unique. + do { + visited_corners[current_c.value()] = true; + // Each new edge is defined by the pivot vertex (that is the same for + // all faces) and by the sink vertex (that is the |next| vertex from the + // currently processed pivot corner. I.e., each edge is uniquely defined + // by the sink vertex index. + const CornerIndex sink_c = Next(current_c); + const VertexIndex sink_v = corner_to_vertex_map_[sink_c]; + + // Corner that defines the edge on the face. + const CornerIndex edge_corner = Previous(current_c); + bool vertex_connectivity_updated = false; + // Go over all processed edges (sink vertices). If the current sink + // vertex has been already encountered before it may indicate a + // non-manifold edge that needs to be broken. + for (auto &&attached_sink_vertex : sink_vertices) { + if (attached_sink_vertex.first == sink_v) { + // Sink vertex has been already processed. + const CornerIndex other_edge_corner = attached_sink_vertex.second; + const CornerIndex opp_edge_corner = Opposite(edge_corner); + + if (opp_edge_corner == other_edge_corner) { + // We are closing the loop so no need to change the connectivity. + continue; + } + + // Break the connectivity on the non-manifold edge. + // TODO(ostava): It may be possible to reconnect the faces in a way + // that the final surface would be manifold. + const CornerIndex opp_other_edge_corner = + Opposite(other_edge_corner); + if (opp_edge_corner != kInvalidCornerIndex) + SetOppositeCorner(opp_edge_corner, kInvalidCornerIndex); + if (opp_other_edge_corner != kInvalidCornerIndex) + SetOppositeCorner(opp_other_edge_corner, kInvalidCornerIndex); + + SetOppositeCorner(edge_corner, kInvalidCornerIndex); + SetOppositeCorner(other_edge_corner, kInvalidCornerIndex); + + vertex_connectivity_updated = true; + break; + } + } + if (vertex_connectivity_updated) { + // Because of the updated connectivity, not all corners connected to + // this vertex have been processed and we need to go over them again. + // TODO(ostava): This can be optimized as we don't really need to + // iterate over all corners. + mesh_connectivity_updated = true; + break; + } + // Insert new sink vertex information <sink vertex index, edge corner>. + std::pair<VertexIndex, CornerIndex> new_sink_vert; + new_sink_vert.first = corner_to_vertex_map_[Previous(current_c)]; + new_sink_vert.second = sink_c; + sink_vertices.push_back(new_sink_vert); + + current_c = SwingRight(current_c); + } while (current_c != first_c && current_c != kInvalidCornerIndex); + } + } while (mesh_connectivity_updated); + return true; +} + bool CornerTable::ComputeVertexCorners(int num_vertices) { DRACO_DCHECK(GetValenceCache().IsCacheEmpty()); num_original_vertices_ = num_vertices; diff --git a/extern/draco/dracoenc/src/draco/mesh/corner_table.h b/extern/draco/dracoenc/src/draco/mesh/corner_table.h index b916b995f66..704a7b1b5c4 100644 --- a/extern/draco/dracoenc/src/draco/mesh/corner_table.h +++ b/extern/draco/dracoenc/src/draco/mesh/corner_table.h @@ -51,7 +51,6 @@ namespace draco { // non-manifold edges and vertices are automatically split. class CornerTable { public: - // TODO(hemmer): rename to Face. // Corner table face type. typedef std::array<VertexIndex, 3> FaceType; @@ -333,10 +332,14 @@ class CornerTable { private: // Computes opposite corners mapping from the data stored in - // |corner_to_vertex_map_|. Any non-manifold edge will be split so the result - // is always a 2-manifold surface. + // |corner_to_vertex_map_|. bool ComputeOppositeCorners(int *num_vertices); + // Finds and breaks non-manifold edges in the 1-ring neighborhood around + // vertices (vertices themselves will be split in the ComputeVertexCorners() + // function if necessary). + bool BreakNonManifoldEdges(); + // Computes the lookup map for going from a vertex to a corner. This method // can handle non-manifold vertices by splitting them into multiple manifold // vertices. diff --git a/extern/draco/dracoenc/src/draco/mesh/mesh.cc b/extern/draco/dracoenc/src/draco/mesh/mesh.cc index dd37a88d1fa..a78a6ec96a8 100644 --- a/extern/draco/dracoenc/src/draco/mesh/mesh.cc +++ b/extern/draco/dracoenc/src/draco/mesh/mesh.cc @@ -27,7 +27,7 @@ using conditional_t = typename std::conditional<B, T, F>::type; Mesh::Mesh() {} -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED void Mesh::ApplyPointIdDeduplication( const IndexTypeVector<PointIndex, PointIndex> &id_map, const std::vector<PointIndex> &unique_point_ids) { diff --git a/extern/draco/dracoenc/src/draco/mesh/mesh.h b/extern/draco/dracoenc/src/draco/mesh/mesh.h index dd41f6cde4a..b8ca5353a81 100644 --- a/extern/draco/dracoenc/src/draco/mesh/mesh.h +++ b/extern/draco/dracoenc/src/draco/mesh/mesh.h @@ -17,11 +17,11 @@ #include <memory> -#include "draco/draco_features.h" - #include "draco/attributes/geometry_indices.h" #include "draco/core/hash_utils.h" #include "draco/core/macros.h" +#include "draco/core/status.h" +#include "draco/draco_features.h" #include "draco/point_cloud/point_cloud.h" namespace draco { @@ -109,7 +109,7 @@ class Mesh : public PointCloud { }; protected: -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED // Extends the point deduplication to face corners. This method is called from // the PointCloud::DeduplicatePointIds() and it remaps all point ids stored in // |faces_| to the new deduplicated point ids using the map |id_map|. diff --git a/extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h b/extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h index fc038bd7445..b972109e679 100644 --- a/extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h +++ b/extern/draco/dracoenc/src/draco/mesh/mesh_misc_functions.h @@ -56,6 +56,25 @@ inline bool IsCornerOppositeToAttributeSeam(CornerIndex ci, return false; } +// 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 <typename InterpolatedVectorT> +InterpolatedVectorT ComputeInterpolatedAttributeValueOnMeshFace( + const Mesh &mesh, const PointAttribute &attribute, FaceIndex fi, + const std::array<float, 3> &barycentric_coord) { + const Mesh::Face &face = mesh.face(fi); + // Get values for all three corners of the face. + InterpolatedVectorT val[3]; + for (int c = 0; c < 3; ++c) { + attribute.GetMappedValue(face[c], &(val[c][0])); + } + // Return an interpolated value. + return barycentric_coord[0] * val[0] + barycentric_coord[1] * val[1] + + barycentric_coord[2] * val[2]; +} + } // namespace draco #endif // DRACO_MESH_MESH_MISC_FUNCTIONS_H_ diff --git a/extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc b/extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc index a21d5e77cf7..7a76745342b 100644 --- a/extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc +++ b/extern/draco/dracoenc/src/draco/mesh/triangle_soup_mesh_builder.cc @@ -65,10 +65,12 @@ void TriangleSoupMeshBuilder::SetPerFaceAttributeValueForFace( } std::unique_ptr<Mesh> TriangleSoupMeshBuilder::Finalize() { -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED // First deduplicate attribute values. if (!mesh_->DeduplicateAttributeValues()) return nullptr; +#endif +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED // Also deduplicate vertex indices. mesh_->DeduplicatePointIds(); #endif diff --git a/extern/draco/dracoenc/src/draco/metadata/metadata.h b/extern/draco/dracoenc/src/draco/metadata/metadata.h index b4dd202c991..bf0be36f3b1 100644 --- a/extern/draco/dracoenc/src/draco/metadata/metadata.h +++ b/extern/draco/dracoenc/src/draco/metadata/metadata.h @@ -18,7 +18,7 @@ #include <cstring> #include <memory> #include <string> -#include <unordered_map> +#include <map> #include <vector> #include "draco/core/hash_utils.h" @@ -101,27 +101,45 @@ class Metadata { // accessing entries of common data types. For now, developers need to know // the type of entries they are requesting. void AddEntryInt(const std::string &name, int32_t value); + + // Returns false if Metadata does not contain an entry with a key of |name|. + // This function does not guarantee that entry's type is int32_t. bool GetEntryInt(const std::string &name, int32_t *value) const; void AddEntryIntArray(const std::string &name, const std::vector<int32_t> &value); + + // Returns false if Metadata does not contain an entry with a key of |name|. + // This function does not guarantee that entry's type is a vector of int32_t. bool GetEntryIntArray(const std::string &name, std::vector<int32_t> *value) const; void AddEntryDouble(const std::string &name, double value); + + // Returns false if Metadata does not contain an entry with a key of |name|. + // This function does not guarantee that entry's type is double. bool GetEntryDouble(const std::string &name, double *value) const; void AddEntryDoubleArray(const std::string &name, const std::vector<double> &value); + + // Returns false if Metadata does not contain an entry with a key of |name|. + // This function does not guarantee that entry's type is a vector of double. bool GetEntryDoubleArray(const std::string &name, std::vector<double> *value) const; void AddEntryString(const std::string &name, const std::string &value); + + // Returns false if Metadata does not contain an entry with a key of |name|. + // This function does not guarantee that entry's type is std::string. bool GetEntryString(const std::string &name, std::string *value) const; // Add a blob of data as an entry. void AddEntryBinary(const std::string &name, const std::vector<uint8_t> &value); + + // Returns false if Metadata does not contain an entry with a key of |name|. + // This function does not guarantee that entry's type is a vector of uint8_t. bool GetEntryBinary(const std::string &name, std::vector<uint8_t> *value) const; @@ -132,10 +150,10 @@ class Metadata { void RemoveEntry(const std::string &name); int num_entries() const { return static_cast<int>(entries_.size()); } - const std::unordered_map<std::string, EntryValue> &entries() const { + const std::map<std::string, EntryValue> &entries() const { return entries_; } - const std::unordered_map<std::string, std::unique_ptr<Metadata>> + const std::map<std::string, std::unique_ptr<Metadata>> &sub_metadatas() const { return sub_metadatas_; } @@ -160,8 +178,8 @@ class Metadata { return itr->second.GetValue(entry_value); } - std::unordered_map<std::string, EntryValue> entries_; - std::unordered_map<std::string, std::unique_ptr<Metadata>> sub_metadatas_; + std::map<std::string, EntryValue> entries_; + std::map<std::string, std::unique_ptr<Metadata>> sub_metadatas_; friend struct MetadataHasher; }; diff --git a/extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc b/extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc index c98a334b003..6e85ce6f9d9 100644 --- a/extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc +++ b/extern/draco/dracoenc/src/draco/metadata/metadata_encoder.cc @@ -20,8 +20,7 @@ namespace draco { bool MetadataEncoder::EncodeMetadata(EncoderBuffer *out_buffer, const Metadata *metadata) { - const std::unordered_map<std::string, EntryValue> &entries = - metadata->entries(); + const std::map<std::string, EntryValue> &entries = metadata->entries(); // Encode number of entries. EncodeVarint(static_cast<uint32_t>(metadata->num_entries()), out_buffer); // Encode all entries. @@ -33,8 +32,8 @@ bool MetadataEncoder::EncodeMetadata(EncoderBuffer *out_buffer, EncodeVarint(data_size, out_buffer); out_buffer->Encode(entry_value.data(), data_size); } - const std::unordered_map<std::string, std::unique_ptr<Metadata>> - &sub_metadatas = metadata->sub_metadatas(); + const std::map<std::string, std::unique_ptr<Metadata>> &sub_metadatas = + metadata->sub_metadatas(); // Encode number of sub-metadata EncodeVarint(static_cast<uint32_t>(sub_metadatas.size()), out_buffer); // Encode each sub-metadata diff --git a/extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc b/extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc index fbda6137c39..d8f7f2f6649 100644 --- a/extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc +++ b/extern/draco/dracoenc/src/draco/metadata/metadata_encoder_test.cc @@ -75,9 +75,9 @@ class MetadataEncoderTest : public ::testing::Test { void CheckMetadatasAreEqual(const draco::Metadata &metadata0, const draco::Metadata &metadata1) { ASSERT_EQ(metadata0.num_entries(), metadata1.num_entries()); - const std::unordered_map<std::string, draco::EntryValue> &entries0 = + const std::map<std::string, draco::EntryValue> &entries0 = metadata0.entries(); - const std::unordered_map<std::string, draco::EntryValue> &entries1 = + const std::map<std::string, draco::EntryValue> &entries1 = metadata1.entries(); for (const auto &entry : entries0) { const std::string &entry_name = entry.first; @@ -90,7 +90,7 @@ class MetadataEncoderTest : public ::testing::Test { // Check nested metadata. ASSERT_EQ(metadata0.sub_metadatas().size(), metadata1.sub_metadatas().size()); - const std::unordered_map<std::string, std::unique_ptr<draco::Metadata>> + const std::map<std::string, std::unique_ptr<draco::Metadata>> &sub_metadatas0 = metadata0.sub_metadatas(); // Encode each sub-metadata for (auto &&sub_metadata_entry0 : sub_metadatas0) { diff --git a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc index 63eee27417e..9552654be16 100644 --- a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc +++ b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.cc @@ -87,23 +87,32 @@ int PointCloud::AddAttribute(std::unique_ptr<PointAttribute> pa) { int PointCloud::AddAttribute( const GeometryAttribute &att, bool identity_mapping, AttributeValueIndex::ValueType num_attribute_values) { - const GeometryAttribute::Type type = att.attribute_type(); - if (type == GeometryAttribute::INVALID) + auto pa = CreateAttribute(att, identity_mapping, num_attribute_values); + if (!pa) return -1; - const int32_t att_id = - AddAttribute(std::unique_ptr<PointAttribute>(new PointAttribute(att))); + const int32_t att_id = AddAttribute(std::move(pa)); + return att_id; +} + +std::unique_ptr<PointAttribute> PointCloud::CreateAttribute( + const GeometryAttribute &att, bool identity_mapping, + AttributeValueIndex::ValueType num_attribute_values) const { + if (att.attribute_type() == GeometryAttribute::INVALID) + return nullptr; + std::unique_ptr<PointAttribute> pa = + std::unique_ptr<PointAttribute>(new PointAttribute(att)); // Initialize point cloud specific attribute data. if (!identity_mapping) { // First create mapping between indices. - attribute(att_id)->SetExplicitMapping(num_points_); + pa->SetExplicitMapping(num_points_); } else { - attribute(att_id)->SetIdentityMapping(); - attribute(att_id)->Resize(num_points_); + pa->SetIdentityMapping(); + pa->Resize(num_points_); } if (num_attribute_values > 0) { - attribute(att_id)->Reset(num_attribute_values); + pa->Reset(num_attribute_values); } - return att_id; + return pa; } void PointCloud::SetAttribute(int att_id, std::unique_ptr<PointAttribute> pa) { @@ -148,7 +157,7 @@ void PointCloud::DeleteAttribute(int att_id) { } } -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED void PointCloud::DeduplicatePointIds() { // Hashing function for a single vertex. auto point_hash = [this](PointIndex p) { @@ -214,7 +223,9 @@ void PointCloud::ApplyPointIdDeduplication( attribute(a)->SetExplicitMapping(num_unique_points); } } +#endif +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED bool PointCloud::DeduplicateAttributeValues() { // Go over all attributes and create mapping between duplicate entries. if (num_points() == 0) diff --git a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h index 0ea057dcf54..e15206f17c4 100644 --- a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h +++ b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud.h @@ -89,10 +89,17 @@ class PointCloud { // PointAttribute::SetPointMapEntry() method. |num_attribute_values| can be // used to specify the number of attribute values that are going to be // stored in the newly created attribute. Returns attribute id of the newly - // created attribute. + // created attribute or -1 in case of failure. int AddAttribute(const GeometryAttribute &att, bool identity_mapping, AttributeValueIndex::ValueType num_attribute_values); + // Creates and returns a new attribute or nullptr in case of failure. This + // method is similar to AddAttribute(), except that it returns the new + // attribute instead of adding it to the point cloud. + std::unique_ptr<PointAttribute> CreateAttribute( + const GeometryAttribute &att, bool identity_mapping, + AttributeValueIndex::ValueType num_attribute_values) const; + // Assigns an attribute id to a given PointAttribute. If an attribute with // the same attribute id already exists, it is deleted. virtual void SetAttribute(int att_id, std::unique_ptr<PointAttribute> pa); @@ -101,11 +108,13 @@ class PointCloud { // attribute ids of all subsequent attributes. virtual void DeleteAttribute(int att_id); -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED // Deduplicates all attribute values (all attribute entries with the same // value are merged into a single entry). virtual bool DeduplicateAttributeValues(); +#endif +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED // Removes duplicate point ids (two point ids are duplicate when all of their // attributes are mapped to the same entry ids). virtual void DeduplicatePointIds(); @@ -173,7 +182,7 @@ class PointCloud { void set_num_points(PointIndex::ValueType num) { num_points_ = num; } protected: -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED // Applies id mapping of deduplicated points (called by DeduplicatePointIds). virtual void ApplyPointIdDeduplication( const IndexTypeVector<PointIndex, PointIndex> &id_map, diff --git a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc index 455d9a931db..a0381631cfd 100644 --- a/extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc +++ b/extern/draco/dracoenc/src/draco/point_cloud/point_cloud_builder.cc @@ -61,12 +61,14 @@ void PointCloudBuilder::SetAttributeValuesForAllPoints( std::unique_ptr<PointCloud> PointCloudBuilder::Finalize( bool deduplicate_points) { -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED if (deduplicate_points) { +#ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED point_cloud_->DeduplicateAttributeValues(); +#endif +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED point_cloud_->DeduplicatePointIds(); - } #endif + } return std::move(point_cloud_); } diff --git a/extern/draco/dracoenc/src/draco/tools/draco_decoder.cc b/extern/draco/dracoenc/src/draco/tools/draco_decoder.cc index d96575223d7..5b06e8caa3b 100644 --- a/extern/draco/dracoenc/src/draco/tools/draco_decoder.cc +++ b/extern/draco/dracoenc/src/draco/tools/draco_decoder.cc @@ -134,7 +134,7 @@ int main(int argc, char **argv) { } // Save the decoded geometry into a file. - // TODO(ostava): Currently only .ply and .obj are supported. + // TODO(fgalligan): Change extension code to look for '.'. const std::string extension = draco::parser::ToLower( options.output.size() >= 4 ? options.output.substr(options.output.size() - 4) @@ -167,7 +167,9 @@ int main(int argc, char **argv) { } } } else { - printf("Invalid extension of the output file. Use either .ply or .obj\n"); + printf( + "Invalid extension of the output file. Use either .ply, .obj, or " + ".gltf\n"); return -1; } printf("Decoded geometry saved to %s (%" PRId64 " ms to decode)\n", diff --git a/extern/draco/dracoenc/src/draco/tools/draco_encoder.cc b/extern/draco/dracoenc/src/draco/tools/draco_encoder.cc index 05458fbbdf6..e44d0939048 100644 --- a/extern/draco/dracoenc/src/draco/tools/draco_encoder.cc +++ b/extern/draco/dracoenc/src/draco/tools/draco_encoder.cc @@ -316,7 +316,7 @@ int main(int argc, char **argv) { pc->GetNamedAttributeId(draco::GeometryAttribute::GENERIC, 0)); } } -#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED +#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED // If any attribute has been deleted, run deduplication of point indices again // as some points can be possibly combined. if (options.tex_coords_deleted || options.normals_deleted || diff --git a/extern/draco/src/draco-compressor.cpp b/extern/draco/src/draco-compressor.cpp index 3262a2c4d4d..4ae528888fe 100644 --- a/extern/draco/src/draco-compressor.cpp +++ b/extern/draco/src/draco-compressor.cpp @@ -13,234 +13,147 @@ */ /** - * Implemententation for the Draco exporter from the C++ side. - * - * The python side uses the CTypes libary to open the DLL, load function - * pointers add pass the data to the compressor as raw bytes. - * - * The compressor intercepts the regular GLTF exporter after data has been - * gathered and right before the data is converted to a JSON representation, - * which is going to be written out. - * - * The original uncompressed data is removed and replaces an extension, - * pointing to the newly created buffer containing the compressed data. - * * @author Jim Eckerlein <eckerlein@ux3d.io> - * @date 2019-01-15 + * @date 2019-11-29 */ -#include <iostream> -#include <fstream> +#include "draco-compressor.h" + #include <memory> -#include <sstream> +#include <vector> #include "draco/mesh/mesh.h" -#include "draco/point_cloud/point_cloud.h" -#include "draco/core/vector_d.h" -#include "draco/io/mesh_io.h" +#include "draco/core/encoder_buffer.h" #include "draco/compression/encode.h" -#if defined(_MSC_VER) -#define DLL_EXPORT(retType) extern "C" __declspec(dllexport) retType __cdecl -#else -#define DLL_EXPORT(retType) extern "C" retType -#endif - -const char *logTag = "DRACO-COMPRESSOR"; - /** - * This tuple is opaquely exposed to Python through a pointer. - * It encapsulates the complete current compressor state. - * - * A single instance is only intended to compress a single primitive. + * Prefix used for logging messages. */ -struct DracoCompressor { +const char *logTag = "DRACO-COMPRESSOR"; - /** - * All positions, normals and texture coordinates are appended to this mesh. - */ +struct DracoCompressor { draco::Mesh mesh; - /** - * One data buffer per attribute. - */ + // One data buffer per attribute. std::vector<std::unique_ptr<draco::DataBuffer>> buffers; - /** - * The buffer the mesh is compressed into. - */ + // The buffer the mesh is compressed into. draco::EncoderBuffer encoderBuffer; - /** - * The id Draco assigns to the position attribute. - * Required to be reported in the GLTF file. - */ - uint32_t positionAttributeId = (uint32_t) -1; - - /** - * The id Draco assigns to the normal attribute. - * Required to be reported in the GLTF file. - */ - uint32_t normalAttributeId = (uint32_t) -1; - - /** - * The ids Draco assigns to the texture coordinate attributes. - * Required to be reported in the GLTF file. - */ - std::vector<uint32_t> texCoordAttributeIds; - - /** - * Level of compression [0-10]. - * Higher values mean slower encoding. - */ + // Level of compression [0-10]. + // Higher values mean slower encoding. uint32_t compressionLevel = 7; - uint32_t quantizationBitsPosition = 14; - uint32_t quantizationBitsNormal = 10; - uint32_t quantizationBitsTexCoord = 12; + struct { + uint32_t positions = 14; + uint32_t normals = 10; + uint32_t uvs = 12; + uint32_t generic = 12; + } quantization; }; -draco::GeometryAttribute createAttribute( - draco::GeometryAttribute::Type type, - draco::DataBuffer &buffer, - uint8_t components -) { - draco::GeometryAttribute attribute; - attribute.Init( - type, - &buffer, - components, - draco::DataType::DT_FLOAT32, - false, - sizeof(float) * components, - 0 - ); - return attribute; -} - -DLL_EXPORT(DracoCompressor *) createCompressor() { +DracoCompressor *create_compressor() { return new DracoCompressor; } -DLL_EXPORT(void) setCompressionLevel( - DracoCompressor *compressor, - uint32_t compressionLevel +void set_compression_level( + DracoCompressor *const compressor, + uint32_t const compressionLevel ) { compressor->compressionLevel = compressionLevel; } -DLL_EXPORT(void) setPositionQuantizationBits( - DracoCompressor *compressor, - uint32_t quantizationBitsPosition +void set_position_quantization( + DracoCompressor *const compressor, + uint32_t const quantizationBitsPosition ) { - compressor->quantizationBitsPosition = quantizationBitsPosition; + compressor->quantization.positions = quantizationBitsPosition; } -DLL_EXPORT(void) setNormalQuantizationBits( - DracoCompressor *compressor, - uint32_t quantizationBitsNormal +void set_normal_quantization( + DracoCompressor *const compressor, + uint32_t const quantizationBitsNormal ) { - compressor->quantizationBitsNormal = quantizationBitsNormal; + compressor->quantization.normals = quantizationBitsNormal; } -DLL_EXPORT(void) setTexCoordQuantizationBits( - DracoCompressor *compressor, - uint32_t quantizationBitsTexCoord +void set_uv_quantization( + DracoCompressor *const compressor, + uint32_t const quantizationBitsTexCoord ) { - compressor->quantizationBitsTexCoord = quantizationBitsTexCoord; + compressor->quantization.uvs = quantizationBitsTexCoord; } -DLL_EXPORT(bool) compress( - DracoCompressor *compressor +void set_generic_quantization( + DracoCompressor *const compressor, + uint32_t const bits ) { - printf("%s: Compressing primitive:\n", logTag); - printf("%s: Compression level [0-10]: %d\n", logTag, compressor->compressionLevel); - printf("%s: Position quantization bits: %d\n", logTag, compressor->quantizationBitsPosition); - printf("%s: Normal quantization bits: %d\n", logTag, compressor->quantizationBitsNormal); - printf("%s: Position quantization bits: %d\n", logTag, compressor->quantizationBitsTexCoord); + compressor->quantization.generic = bits; +} +bool compress( + DracoCompressor *const compressor +) { draco::Encoder encoder; - encoder.SetSpeedOptions(10 - compressor->compressionLevel, 10 - compressor->compressionLevel); - encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, compressor->quantizationBitsPosition); - encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, compressor->quantizationBitsNormal); - encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, compressor->quantizationBitsTexCoord); - - draco::Status result = encoder.EncodeMeshToBuffer(compressor->mesh, &compressor->encoderBuffer); + encoder.SetSpeedOptions(10 - (int)compressor->compressionLevel, 10 - (int)compressor->compressionLevel); + encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, compressor->quantization.positions); + encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL, compressor->quantization.normals); + encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD, compressor->quantization.uvs); + encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC, compressor->quantization.generic); - if(!result.ok()) { - printf("%s: Could not compress mesh: %s\n", logTag, result.error_msg()); - return false; - } - else { - return true; - } + return encoder.EncodeMeshToBuffer(compressor->mesh, &compressor->encoderBuffer).ok(); } -/** - * Returns the size of the compressed data in bytes. - */ -DLL_EXPORT(uint64_t) compressedSize( - DracoCompressor *compressor +bool compress_morphed( + DracoCompressor *const compressor ) { - return compressor->encoderBuffer.size(); -} + draco::Encoder encoder; -/** - * Copies the compressed mesh into the given byte buffer. - * @param[o_data] A Python `bytes` object. - * - */ -DLL_EXPORT(void) copyToBytes( - DracoCompressor *compressor, - uint8_t *o_data -) { - memcpy(o_data, compressor->encoderBuffer.data(), compressedSize(compressor)); -} + encoder.SetSpeedOptions(10 - (int)compressor->compressionLevel, 10 - (int)compressor->compressionLevel); -DLL_EXPORT(uint32_t) getPositionAttributeId( - DracoCompressor *compressor -) { - return compressor->positionAttributeId; -} + // For some reason, `EncodeMeshToBuffer` crashes when not disabling prediction or when enabling quantization + // for attributes other position. + encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION, compressor->quantization.positions); + encoder.SetAttributePredictionScheme(draco::GeometryAttribute::POSITION, draco::PREDICTION_NONE); + encoder.SetAttributePredictionScheme(draco::GeometryAttribute::NORMAL, draco::PREDICTION_NONE); + encoder.SetAttributePredictionScheme(draco::GeometryAttribute::TEX_COORD, draco::PREDICTION_NONE); + encoder.SetAttributePredictionScheme(draco::GeometryAttribute::GENERIC, draco::PREDICTION_NONE); -DLL_EXPORT(uint32_t) getNormalAttributeId( - DracoCompressor *compressor -) { - return compressor->normalAttributeId; + // Enforce triangle order preservation. + encoder.SetEncodingMethod(draco::MESH_SEQUENTIAL_ENCODING); + + return encoder.EncodeMeshToBuffer(compressor->mesh, &compressor->encoderBuffer).ok(); } -DLL_EXPORT(uint32_t) getTexCoordAttributeIdCount( - DracoCompressor *compressor +uint64_t get_compressed_size( + DracoCompressor const *const compressor ) { - return (uint32_t) compressor->texCoordAttributeIds.size(); + return compressor->encoderBuffer.size(); } -DLL_EXPORT(uint32_t) getTexCoordAttributeId( - DracoCompressor *compressor, - uint32_t index +void copy_to_bytes( + DracoCompressor const *const compressor, + uint8_t *const o_data ) { - return compressor->texCoordAttributeIds[index]; + memcpy(o_data, compressor->encoderBuffer.data(), compressor->encoderBuffer.size()); } -/** - * Releases all memory allocated by the compressor. - */ -DLL_EXPORT(void) disposeCompressor( - DracoCompressor *compressor +void destroy_compressor( + DracoCompressor *const compressor ) { delete compressor; } template<class T> -void setFaces( - draco::Mesh &mesh, - int numIndices, - T *indices +void set_faces_impl( + draco::Mesh &mesh, + int const index_count, + T const *const indices ) { - mesh.SetNumFaces((size_t) numIndices / 3); + mesh.SetNumFaces((size_t) index_count / 3); - for (int i = 0; i < numIndices; i += 3) + for (int i = 0; i < index_count; i += 3) { const auto a = draco::PointIndex(indices[i]); const auto b = draco::PointIndex(indices[i + 1]); @@ -249,97 +162,116 @@ void setFaces( } } -DLL_EXPORT(void) setFaces( - DracoCompressor *compressor, - uint32_t numIndices, - uint32_t bytesPerIndex, - void *indices +void set_faces( + DracoCompressor *const compressor, + uint32_t const index_count, + uint32_t const index_byte_length, + uint8_t const *const indices ) { - switch (bytesPerIndex) + switch (index_byte_length) { case 1: { - setFaces(compressor->mesh, numIndices, (uint8_t *) indices); + set_faces_impl(compressor->mesh, index_count, (uint8_t *) indices); break; } case 2: { - setFaces(compressor->mesh, numIndices, (uint16_t *) indices); + set_faces_impl(compressor->mesh, index_count, (uint16_t *) indices); break; } case 4: { - setFaces(compressor->mesh, numIndices, (uint32_t *) indices); + set_faces_impl(compressor->mesh, index_count, (uint32_t *) indices); break; } default: { - printf("%s: Unsupported index size %d\n", logTag, bytesPerIndex); + printf("%s: Unsupported index size %d\n", logTag, index_byte_length); break; } } } -void addFloatAttribute( - DracoCompressor *compressor, - draco::GeometryAttribute::Type type, - uint32_t count, - uint8_t componentCount, - float *source +uint32_t add_attribute_to_mesh( + DracoCompressor *const compressor, + draco::GeometryAttribute::Type const semantics, + draco::DataType const data_type, + uint32_t const count, + uint8_t const component_count, + uint8_t const component_size, + uint8_t const *const data ) { auto buffer = std::make_unique<draco::DataBuffer>(); - const auto attribute = createAttribute(type, *buffer, componentCount); + draco::GeometryAttribute attribute; - const auto id = (const uint32_t) compressor->mesh.AddAttribute(attribute, false, count); - compressor->mesh.attribute(id)->SetIdentityMapping(); + attribute.Init( + semantics, + &*buffer, + component_count, + data_type, + false, + component_size * component_count, + 0 + ); - switch (type) - { - case draco::GeometryAttribute::POSITION: - compressor->positionAttributeId = id; - break; - case draco::GeometryAttribute::NORMAL: - compressor->normalAttributeId = id; - break; - case draco::GeometryAttribute::TEX_COORD: - compressor->texCoordAttributeIds.push_back(id); - break; - default: - break; - } + auto const id = (uint32_t)compressor->mesh.AddAttribute(attribute, true, count); for (uint32_t i = 0; i < count; i++) { compressor->mesh.attribute(id)->SetAttributeValue( - draco::AttributeValueIndex(i), - source + i * componentCount + draco::AttributeValueIndex(i), + data + i * component_count * component_size ); } compressor->buffers.emplace_back(std::move(buffer)); + + return id; +} + +uint32_t add_positions_f32( + DracoCompressor *const compressor, + uint32_t const count, + uint8_t const *const data +) { + return add_attribute_to_mesh(compressor, draco::GeometryAttribute::POSITION, + draco::DT_FLOAT32, count, 3, sizeof(float), data); +} + +uint32_t add_normals_f32( + DracoCompressor *const compressor, + uint32_t const count, + uint8_t const *const data +) { + return add_attribute_to_mesh(compressor, draco::GeometryAttribute::NORMAL, + draco::DT_FLOAT32, count, 3, sizeof(float), data); } -DLL_EXPORT(void) addPositionAttribute( - DracoCompressor *compressor, - uint32_t count, - float *source +uint32_t add_uvs_f32( + DracoCompressor *const compressor, + uint32_t const count, + uint8_t const *const data ) { - addFloatAttribute(compressor, draco::GeometryAttribute::POSITION, count, 3, source); + return add_attribute_to_mesh(compressor, draco::GeometryAttribute::TEX_COORD, + draco::DT_FLOAT32, count, 2, sizeof(float), data); } -DLL_EXPORT(void) addNormalAttribute( - DracoCompressor *compressor, - uint32_t count, - float *source +uint32_t add_joints_u16( + DracoCompressor *compressor, + uint32_t const count, + uint8_t const *const data ) { - addFloatAttribute(compressor, draco::GeometryAttribute::NORMAL, count, 3, source); + return add_attribute_to_mesh(compressor, draco::GeometryAttribute::GENERIC, + draco::DT_UINT16, count, 4, sizeof(uint16_t), data); } -DLL_EXPORT(void) addTexCoordAttribute( - DracoCompressor *compressor, - uint32_t count, - float *source +uint32_t add_weights_f32( + DracoCompressor *compressor, + uint32_t const count, + uint8_t const *const data ) { - addFloatAttribute(compressor, draco::GeometryAttribute::TEX_COORD, count, 2, source); + return add_attribute_to_mesh(compressor, draco::GeometryAttribute::GENERIC, + draco::DT_FLOAT32, count, 4, sizeof(float), data); } diff --git a/extern/draco/src/draco-compressor.h b/extern/draco/src/draco-compressor.h new file mode 100644 index 00000000000..fb6168a61af --- /dev/null +++ b/extern/draco/src/draco-compressor.h @@ -0,0 +1,173 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * C++ library for the Draco compression feature inside the glTF-Blender-IO project. + * + * The python side uses the CTypes library to open the DLL, load function + * pointers add pass the data to the compressor as raw bytes. + * + * The compressor intercepts the regular glTF exporter after data has been + * gathered and right before the data is converted to a JSON representation, + * which is going to be written out. + * + * The original uncompressed data is removed and replaces an extension, + * pointing to the newly created buffer containing the compressed data. + * + * @author Jim Eckerlein <eckerlein@ux3d.io> + * @date 2019-11-29 + */ + +#include <cstdint> + +#if defined(_MSC_VER) +#define DLL_EXPORT(retType) extern "C" __declspec(dllexport) retType __cdecl +#else +#define DLL_EXPORT(retType) extern "C" retType +#endif + +/** + * This tuple is opaquely exposed to Python through a pointer. + * It encapsulates the complete current compressor state. + * + * A single instance is only intended to compress a single primitive. + */ +struct DracoCompressor; + +DLL_EXPORT(DracoCompressor *) +create_compressor (); + +DLL_EXPORT(void) +set_compression_level ( + DracoCompressor *compressor, + uint32_t compressionLevel +); + +DLL_EXPORT(void) +set_position_quantization ( + DracoCompressor *compressor, + uint32_t quantizationBitsPosition +); + +DLL_EXPORT(void) +set_normal_quantization ( + DracoCompressor *compressor, + uint32_t quantizationBitsNormal +); + +DLL_EXPORT(void) +set_uv_quantization ( + DracoCompressor *compressor, + uint32_t quantizationBitsTexCoord +); + +DLL_EXPORT(void) +set_generic_quantization ( + DracoCompressor *compressor, + uint32_t bits +); + +/// Compresses a mesh. +/// Use `compress_morphed` when compressing primitives which have morph targets. +DLL_EXPORT(bool) +compress ( + DracoCompressor *compressor +); + +/// Compresses the mesh. +/// Use this instead of `compress`, because this procedure takes into account that mesh triangles must not be reordered. +DLL_EXPORT(bool) +compress_morphed ( + DracoCompressor *compressor +); + +/** + * Returns the size of the compressed data in bytes. + */ +DLL_EXPORT(uint64_t) +get_compressed_size ( + DracoCompressor const *compressor +); + +/** + * Copies the compressed mesh into the given byte buffer. + * + * @param[o_data] A Python `bytes` object. + */ +DLL_EXPORT(void) +copy_to_bytes ( + DracoCompressor const *compressor, + uint8_t *o_data +); + +/** + * Releases all memory allocated by the compressor. + */ +DLL_EXPORT(void) +destroy_compressor ( + DracoCompressor *compressor +); + +DLL_EXPORT(void) +set_faces ( + DracoCompressor *compressor, + uint32_t index_count, + uint32_t index_byte_length, + uint8_t const *indices +); + +/// Adds a `float` position attribute to the current mesh. +/// Returns the id Draco has assigned to this attribute. +DLL_EXPORT(uint32_t) +add_positions_f32 ( + DracoCompressor *compressor, + uint32_t count, + uint8_t const *data +); + +/// Adds a `float` normal attribute to the current mesh. +/// Returns the id Draco has assigned to this attribute. +DLL_EXPORT(uint32_t) +add_normals_f32 ( + DracoCompressor *compressor, + uint32_t count, + uint8_t const *data +); + +/// Adds a `float` texture coordinate attribute to the current mesh. +/// Returns the id Draco has assigned to this attribute. +DLL_EXPORT(uint32_t) +add_uvs_f32 ( + DracoCompressor *compressor, + uint32_t count, + uint8_t const *data +); + +/// Adds a `unsigned short` joint attribute to the current mesh. +/// Returns the id Draco has assigned to this attribute. +DLL_EXPORT(uint32_t) +add_joints_u16 ( + DracoCompressor *compressor, + uint32_t count, + uint8_t const *data +); + +/// Adds a `float` weight attribute to the current mesh. +/// Returns the id Draco has assigned to this attribute. +DLL_EXPORT(uint32_t) +add_weights_f32 ( + DracoCompressor *compressor, + uint32_t count, + uint8_t const *data +); |