Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/draco/dracoenc/src/draco/attributes')
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.cc86
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.h60
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc173
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.h78
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/attribute_transform.cc44
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/attribute_transform.h46
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/attribute_transform_data.h71
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/attribute_transform_type.h30
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/geometry_attribute.cc91
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/geometry_attribute.h304
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/geometry_indices.h54
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/point_attribute.cc205
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/point_attribute.h186
-rw-r--r--extern/draco/dracoenc/src/draco/attributes/point_attribute_test.cc129
14 files changed, 1557 insertions, 0 deletions
diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.cc b/extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.cc
new file mode 100644
index 00000000000..e1180a48dda
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.cc
@@ -0,0 +1,86 @@
+// 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.
+//
+
+#include "draco/attributes/attribute_octahedron_transform.h"
+
+#include "draco/attributes/attribute_transform_type.h"
+#include "draco/compression/attributes/normal_compression_utils.h"
+
+namespace draco {
+
+bool AttributeOctahedronTransform::InitFromAttribute(
+ const PointAttribute &attribute) {
+ const AttributeTransformData *const transform_data =
+ attribute.GetAttributeTransformData();
+ if (!transform_data ||
+ transform_data->transform_type() != ATTRIBUTE_OCTAHEDRON_TRANSFORM)
+ return false; // Wrong transform type.
+ quantization_bits_ = transform_data->GetParameterValue<int32_t>(0);
+ return true;
+}
+
+void AttributeOctahedronTransform::CopyToAttributeTransformData(
+ AttributeTransformData *out_data) const {
+ out_data->set_transform_type(ATTRIBUTE_OCTAHEDRON_TRANSFORM);
+ out_data->AppendParameterValue(quantization_bits_);
+}
+
+void AttributeOctahedronTransform::SetParameters(int quantization_bits) {
+ quantization_bits_ = quantization_bits;
+}
+
+bool AttributeOctahedronTransform::EncodeParameters(
+ EncoderBuffer *encoder_buffer) const {
+ if (is_initialized()) {
+ encoder_buffer->Encode(static_cast<uint8_t>(quantization_bits_));
+ return true;
+ }
+ return false;
+}
+
+std::unique_ptr<PointAttribute>
+AttributeOctahedronTransform::GeneratePortableAttribute(
+ const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
+ int num_points) const {
+ DRACO_DCHECK(is_initialized());
+
+ // Allocate portable attribute.
+ const int num_entries = static_cast<int>(point_ids.size());
+ std::unique_ptr<PointAttribute> portable_attribute =
+ InitPortableAttribute(num_entries, 2, num_points, attribute, true);
+
+ // Quantize all values in the order given by point_ids into portable
+ // attribute.
+ int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
+ portable_attribute->GetAddress(AttributeValueIndex(0)));
+ float att_val[3];
+ int32_t dst_index = 0;
+ OctahedronToolBox converter;
+ if (!converter.SetQuantizationBits(quantization_bits_))
+ return nullptr;
+ for (uint32_t i = 0; i < point_ids.size(); ++i) {
+ const AttributeValueIndex att_val_id = attribute.mapped_index(point_ids[i]);
+ attribute.GetValue(att_val_id, att_val);
+ // Encode the vector into a s and t octahedral coordinates.
+ int32_t s, t;
+ converter.FloatVectorToQuantizedOctahedralCoords(att_val, &s, &t);
+ portable_attribute_data[dst_index++] = s;
+ portable_attribute_data[dst_index++] = t;
+ }
+
+ return portable_attribute;
+}
+
+} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.h b/extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.h
new file mode 100644
index 00000000000..6e4e74284f0
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/attribute_octahedron_transform.h
@@ -0,0 +1,60 @@
+// 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_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_
+#define DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_
+
+#include "draco/attributes/attribute_transform.h"
+#include "draco/attributes/point_attribute.h"
+#include "draco/core/encoder_buffer.h"
+
+namespace draco {
+
+// Attribute transform for attributes transformed to octahedral coordinates.
+class AttributeOctahedronTransform : public AttributeTransform {
+ public:
+ AttributeOctahedronTransform() : quantization_bits_(-1) {}
+
+ // Return attribute transform type.
+ AttributeTransformType Type() const override {
+ return ATTRIBUTE_OCTAHEDRON_TRANSFORM;
+ }
+ // Try to init transform from attribute.
+ bool InitFromAttribute(const PointAttribute &attribute) override;
+ // Copy parameter values into the provided AttributeTransformData instance.
+ void CopyToAttributeTransformData(
+ AttributeTransformData *out_data) const override;
+
+ // Set number of quantization bits.
+ void SetParameters(int quantization_bits);
+
+ // Encode relevant parameters into buffer.
+ bool EncodeParameters(EncoderBuffer *encoder_buffer) const;
+
+ bool is_initialized() const { return quantization_bits_ != -1; }
+ int32_t quantization_bits() const { return quantization_bits_; }
+
+ // Create portable attribute.
+ std::unique_ptr<PointAttribute> GeneratePortableAttribute(
+ const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
+ int num_points) const;
+
+ private:
+ int32_t quantization_bits_;
+};
+
+} // namespace draco
+
+#endif // DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_
diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc b/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc
new file mode 100644
index 00000000000..41193f1452f
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.cc
@@ -0,0 +1,173 @@
+
+// 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.
+//
+#include "draco/attributes/attribute_quantization_transform.h"
+
+#include "draco/attributes/attribute_transform_type.h"
+#include "draco/core/quantization_utils.h"
+
+namespace draco {
+
+bool AttributeQuantizationTransform::InitFromAttribute(
+ const PointAttribute &attribute) {
+ const AttributeTransformData *const transform_data =
+ attribute.GetAttributeTransformData();
+ if (!transform_data ||
+ transform_data->transform_type() != ATTRIBUTE_QUANTIZATION_TRANSFORM)
+ return false; // Wrong transform type.
+ int32_t byte_offset = 0;
+ quantization_bits_ = transform_data->GetParameterValue<int32_t>(byte_offset);
+ byte_offset += 4;
+ min_values_.resize(attribute.num_components());
+ for (int i = 0; i < attribute.num_components(); ++i) {
+ min_values_[i] = transform_data->GetParameterValue<float>(byte_offset);
+ byte_offset += 4;
+ }
+ range_ = transform_data->GetParameterValue<float>(byte_offset);
+ return true;
+}
+
+// Copy parameter values into the provided AttributeTransformData instance.
+void AttributeQuantizationTransform::CopyToAttributeTransformData(
+ AttributeTransformData *out_data) const {
+ out_data->set_transform_type(ATTRIBUTE_QUANTIZATION_TRANSFORM);
+ out_data->AppendParameterValue(quantization_bits_);
+ for (int i = 0; i < min_values_.size(); ++i) {
+ out_data->AppendParameterValue(min_values_[i]);
+ }
+ out_data->AppendParameterValue(range_);
+}
+
+void AttributeQuantizationTransform::SetParameters(int quantization_bits,
+ const float *min_values,
+ int num_components,
+ float range) {
+ quantization_bits_ = quantization_bits;
+ min_values_.assign(min_values, min_values + num_components);
+ range_ = range;
+}
+
+bool AttributeQuantizationTransform::ComputeParameters(
+ const PointAttribute &attribute, const int quantization_bits) {
+ if (quantization_bits_ != -1) {
+ return false; // already initialized.
+ }
+ quantization_bits_ = quantization_bits;
+
+ const int num_components = attribute.num_components();
+ range_ = 0.f;
+ min_values_ = std::vector<float>(num_components, 0.f);
+ const std::unique_ptr<float[]> max_values(new float[num_components]);
+ const std::unique_ptr<float[]> att_val(new float[num_components]);
+ // Compute minimum values and max value difference.
+ attribute.GetValue(AttributeValueIndex(0), att_val.get());
+ attribute.GetValue(AttributeValueIndex(0), min_values_.data());
+ attribute.GetValue(AttributeValueIndex(0), max_values.get());
+
+ for (AttributeValueIndex i(1); i < static_cast<uint32_t>(attribute.size());
+ ++i) {
+ attribute.GetValue(i, att_val.get());
+ for (int c = 0; c < num_components; ++c) {
+ if (min_values_[c] > att_val[c])
+ min_values_[c] = att_val[c];
+ if (max_values[c] < att_val[c])
+ max_values[c] = att_val[c];
+ }
+ }
+ for (int c = 0; c < num_components; ++c) {
+ const float dif = max_values[c] - min_values_[c];
+ if (dif > range_)
+ range_ = dif;
+ }
+
+ return true;
+}
+
+bool AttributeQuantizationTransform::EncodeParameters(
+ EncoderBuffer *encoder_buffer) const {
+ if (is_initialized()) {
+ encoder_buffer->Encode(min_values_.data(),
+ sizeof(float) * min_values_.size());
+ encoder_buffer->Encode(range_);
+ encoder_buffer->Encode(static_cast<uint8_t>(quantization_bits_));
+ return true;
+ }
+ return false;
+}
+
+std::unique_ptr<PointAttribute>
+AttributeQuantizationTransform::GeneratePortableAttribute(
+ const PointAttribute &attribute, int num_points) const {
+ DRACO_DCHECK(is_initialized());
+
+ // Allocate portable attribute.
+ const int num_entries = num_points;
+ const int num_components = attribute.num_components();
+ std::unique_ptr<PointAttribute> portable_attribute =
+ InitPortableAttribute(num_entries, num_components, 0, attribute, true);
+
+ // Quantize all values using the order given by point_ids.
+ int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
+ portable_attribute->GetAddress(AttributeValueIndex(0)));
+ const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
+ Quantizer quantizer;
+ quantizer.Init(range(), max_quantized_value);
+ int32_t dst_index = 0;
+ const std::unique_ptr<float[]> att_val(new float[num_components]);
+ for (PointIndex i(0); i < num_points; ++i) {
+ const AttributeValueIndex att_val_id = attribute.mapped_index(i);
+ attribute.GetValue(att_val_id, att_val.get());
+ for (int c = 0; c < num_components; ++c) {
+ const float value = (att_val[c] - min_values()[c]);
+ const int32_t q_val = quantizer.QuantizeFloat(value);
+ portable_attribute_data[dst_index++] = q_val;
+ }
+ }
+ return portable_attribute;
+}
+
+std::unique_ptr<PointAttribute>
+AttributeQuantizationTransform::GeneratePortableAttribute(
+ const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
+ int num_points) const {
+ DRACO_DCHECK(is_initialized());
+
+ // Allocate portable attribute.
+ const int num_entries = static_cast<int>(point_ids.size());
+ const int num_components = attribute.num_components();
+ std::unique_ptr<PointAttribute> portable_attribute = InitPortableAttribute(
+ num_entries, num_components, num_points, attribute, true);
+
+ // Quantize all values using the order given by point_ids.
+ int32_t *const portable_attribute_data = reinterpret_cast<int32_t *>(
+ portable_attribute->GetAddress(AttributeValueIndex(0)));
+ const uint32_t max_quantized_value = (1 << (quantization_bits_)) - 1;
+ Quantizer quantizer;
+ quantizer.Init(range(), max_quantized_value);
+ int32_t dst_index = 0;
+ const std::unique_ptr<float[]> att_val(new float[num_components]);
+ for (uint32_t i = 0; i < point_ids.size(); ++i) {
+ const AttributeValueIndex att_val_id = attribute.mapped_index(point_ids[i]);
+ attribute.GetValue(att_val_id, att_val.get());
+ for (int c = 0; c < num_components; ++c) {
+ const float value = (att_val[c] - min_values()[c]);
+ const int32_t q_val = quantizer.QuantizeFloat(value);
+ portable_attribute_data[dst_index++] = q_val;
+ }
+ }
+ return portable_attribute;
+}
+
+} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.h b/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.h
new file mode 100644
index 00000000000..934856f2db7
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/attribute_quantization_transform.h
@@ -0,0 +1,78 @@
+// 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_ATTRIBUTES_ATTRIBUTE_QUANTIZATION_TRANSFORM_H_
+#define DRACO_ATTRIBUTES_ATTRIBUTE_QUANTIZATION_TRANSFORM_H_
+
+#include <vector>
+
+#include "draco/attributes/attribute_transform.h"
+#include "draco/attributes/point_attribute.h"
+#include "draco/core/encoder_buffer.h"
+
+namespace draco {
+
+// Attribute transform for quantized attributes.
+class AttributeQuantizationTransform : public AttributeTransform {
+ public:
+ AttributeQuantizationTransform() : quantization_bits_(-1), range_(0.f) {}
+ // Return attribute transform type.
+ AttributeTransformType Type() const override {
+ return ATTRIBUTE_QUANTIZATION_TRANSFORM;
+ }
+ // Try to init transform from attribute.
+ bool InitFromAttribute(const PointAttribute &attribute) override;
+ // Copy parameter values into the provided AttributeTransformData instance.
+ void CopyToAttributeTransformData(
+ AttributeTransformData *out_data) const override;
+
+ void SetParameters(int quantization_bits, const float *min_values,
+ int num_components, float range);
+
+ bool ComputeParameters(const PointAttribute &attribute,
+ const int quantization_bits);
+
+ // Encode relevant parameters into buffer.
+ bool EncodeParameters(EncoderBuffer *encoder_buffer) const;
+
+ int32_t quantization_bits() const { return quantization_bits_; }
+ float min_value(int axis) const { return min_values_[axis]; }
+ const std::vector<float> &min_values() const { return min_values_; }
+ float range() const { return range_; }
+ bool is_initialized() const { return quantization_bits_ != -1; }
+
+ // Create portable attribute using 1:1 mapping between points in the input and
+ // output attribute.
+ std::unique_ptr<PointAttribute> GeneratePortableAttribute(
+ const PointAttribute &attribute, int num_points) const;
+
+ // Create portable attribute using custom mapping between input and output
+ // points.
+ std::unique_ptr<PointAttribute> GeneratePortableAttribute(
+ const PointAttribute &attribute, const std::vector<PointIndex> &point_ids,
+ int num_points) const;
+
+ private:
+ int32_t quantization_bits_;
+
+ // Minimal dequantized value for each component of the attribute.
+ std::vector<float> min_values_;
+
+ // Bounds of the dequantized attribute (max delta over all components).
+ float range_;
+};
+
+} // namespace draco
+
+#endif // DRACO_COMPRESSION_ATTRIBUTES_ATTRIBUTE_DEQUANTIZATION_TRANSFORM_H_
diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_transform.cc b/extern/draco/dracoenc/src/draco/attributes/attribute_transform.cc
new file mode 100644
index 00000000000..55af630ac07
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/attribute_transform.cc
@@ -0,0 +1,44 @@
+// 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.
+//
+#include "draco/attributes/attribute_transform.h"
+
+namespace draco {
+
+bool AttributeTransform::TransferToAttribute(PointAttribute *attribute) const {
+ std::unique_ptr<AttributeTransformData> transform_data(
+ new AttributeTransformData());
+ this->CopyToAttributeTransformData(transform_data.get());
+ attribute->SetAttributeTransformData(std::move(transform_data));
+ return true;
+}
+
+std::unique_ptr<PointAttribute> AttributeTransform::InitPortableAttribute(
+ int num_entries, int num_components, int num_points,
+ const PointAttribute &attribute, bool is_unsigned) const {
+ const DataType dt = is_unsigned ? DT_UINT32 : DT_INT32;
+ GeometryAttribute va;
+ va.Init(attribute.attribute_type(), nullptr, num_components, dt, false,
+ num_components * DataTypeLength(dt), 0);
+ std::unique_ptr<PointAttribute> portable_attribute(new PointAttribute(va));
+ portable_attribute->Reset(num_entries);
+ if (num_points) {
+ portable_attribute->SetExplicitMapping(num_points);
+ } else {
+ portable_attribute->SetIdentityMapping();
+ }
+ return portable_attribute;
+}
+
+} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_transform.h b/extern/draco/dracoenc/src/draco/attributes/attribute_transform.h
new file mode 100644
index 00000000000..d746fbf6eea
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/attribute_transform.h
@@ -0,0 +1,46 @@
+// 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_ATTRIBUTES_ATTRIBUTE_TRANSFORM_H_
+#define DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_H_
+
+#include "draco/attributes/attribute_transform_data.h"
+#include "draco/attributes/point_attribute.h"
+
+namespace draco {
+
+// Virtual base class for various attribute transforms, enforcing common
+// interface where possible.
+class AttributeTransform {
+ public:
+ virtual ~AttributeTransform() = default;
+
+ // Return attribute transform type.
+ virtual AttributeTransformType Type() const = 0;
+ // Try to init transform from attribute.
+ virtual bool InitFromAttribute(const PointAttribute &attribute) = 0;
+ // Copy parameter values into the provided AttributeTransformData instance.
+ virtual void CopyToAttributeTransformData(
+ AttributeTransformData *out_data) const = 0;
+ bool TransferToAttribute(PointAttribute *attribute) const;
+
+ protected:
+ std::unique_ptr<PointAttribute> InitPortableAttribute(
+ int num_entries, int num_components, int num_points,
+ const PointAttribute &attribute, bool is_unsigned) const;
+};
+
+} // namespace draco
+
+#endif // DRACO_ATTRIBUTES_ATTRIBUTE_OCTAHEDRON_TRANSFORM_H_
diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_transform_data.h b/extern/draco/dracoenc/src/draco/attributes/attribute_transform_data.h
new file mode 100644
index 00000000000..96ed073200d
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/attribute_transform_data.h
@@ -0,0 +1,71 @@
+// 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_ATTRIBUTES_ATTRIBUTE_TRANSFORM_DATA_H_
+#define DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_DATA_H_
+
+#include <memory>
+
+#include "draco/attributes/attribute_transform_type.h"
+#include "draco/core/data_buffer.h"
+
+namespace draco {
+
+// Class for holding parameter values for an attribute transform of a
+// PointAttribute. This can be for example quantization data for an attribute
+// that holds quantized values. This class provides only a basic storage for
+// attribute transform parameters and it should be accessed only through wrapper
+// classes for a specific transform (e.g. AttributeQuantizationTransform).
+class AttributeTransformData {
+ public:
+ AttributeTransformData() : transform_type_(ATTRIBUTE_INVALID_TRANSFORM) {}
+ AttributeTransformData(const AttributeTransformData &data) = default;
+
+ // Returns the type of the attribute transform that is described by the class.
+ AttributeTransformType transform_type() const { return transform_type_; }
+ void set_transform_type(AttributeTransformType type) {
+ transform_type_ = type;
+ }
+
+ // Returns a parameter value on a given |byte_offset|.
+ template <typename DataTypeT>
+ DataTypeT GetParameterValue(int byte_offset) const {
+ DataTypeT out_data;
+ buffer_.Read(byte_offset, &out_data, sizeof(DataTypeT));
+ return out_data;
+ }
+
+ // Sets a parameter value on a given |byte_offset|.
+ template <typename DataTypeT>
+ void SetParameterValue(int byte_offset, const DataTypeT &in_data) {
+ if (byte_offset + sizeof(DataTypeT) > buffer_.data_size()) {
+ buffer_.Resize(byte_offset + sizeof(DataTypeT));
+ }
+ buffer_.Write(byte_offset, &in_data, sizeof(DataTypeT));
+ }
+
+ // Sets a parameter value at the end of the |buffer_|.
+ template <typename DataTypeT>
+ void AppendParameterValue(const DataTypeT &in_data) {
+ SetParameterValue(static_cast<int>(buffer_.data_size()), in_data);
+ }
+
+ private:
+ AttributeTransformType transform_type_;
+ DataBuffer buffer_;
+};
+
+} // namespace draco
+
+#endif // DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_DATA_H_
diff --git a/extern/draco/dracoenc/src/draco/attributes/attribute_transform_type.h b/extern/draco/dracoenc/src/draco/attributes/attribute_transform_type.h
new file mode 100644
index 00000000000..51ce6f333b4
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/attribute_transform_type.h
@@ -0,0 +1,30 @@
+// 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_ATTRIBUTES_ATTRIBUTE_TRANSFORM_TYPE_H_
+#define DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_TYPE_H_
+
+namespace draco {
+
+// List of all currently supported attribute transforms.
+enum AttributeTransformType {
+ ATTRIBUTE_INVALID_TRANSFORM = -1,
+ ATTRIBUTE_NO_TRANSFORM = 0,
+ ATTRIBUTE_QUANTIZATION_TRANSFORM = 1,
+ ATTRIBUTE_OCTAHEDRON_TRANSFORM = 2,
+};
+
+} // namespace draco
+
+#endif // DRACO_ATTRIBUTES_ATTRIBUTE_TRANSFORM_TYPE_H_
diff --git a/extern/draco/dracoenc/src/draco/attributes/geometry_attribute.cc b/extern/draco/dracoenc/src/draco/attributes/geometry_attribute.cc
new file mode 100644
index 00000000000..914a85d9dc2
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/geometry_attribute.cc
@@ -0,0 +1,91 @@
+// Copyright 2016 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.
+//
+#include "draco/attributes/geometry_attribute.h"
+
+using std::array;
+
+namespace draco {
+
+GeometryAttribute::GeometryAttribute()
+ : buffer_(nullptr),
+ num_components_(1),
+ data_type_(DT_FLOAT32),
+ byte_stride_(0),
+ byte_offset_(0),
+ attribute_type_(INVALID),
+ unique_id_(0) {}
+
+void GeometryAttribute::Init(GeometryAttribute::Type attribute_type,
+ DataBuffer *buffer, int8_t num_components,
+ DataType data_type, bool normalized,
+ int64_t byte_stride, int64_t byte_offset) {
+ buffer_ = buffer;
+ if (buffer) {
+ buffer_descriptor_.buffer_id = buffer->buffer_id();
+ buffer_descriptor_.buffer_update_count = buffer->update_count();
+ }
+ num_components_ = num_components;
+ data_type_ = data_type;
+ normalized_ = normalized;
+ byte_stride_ = byte_stride;
+ byte_offset_ = byte_offset;
+ attribute_type_ = attribute_type;
+}
+
+bool GeometryAttribute::CopyFrom(const GeometryAttribute &src_att) {
+ if (buffer_ == nullptr || src_att.buffer_ == nullptr)
+ return false;
+ buffer_->Update(src_att.buffer_->data(), src_att.buffer_->data_size());
+ num_components_ = src_att.num_components_;
+ data_type_ = src_att.data_type_;
+ normalized_ = src_att.normalized_;
+ byte_stride_ = src_att.byte_stride_;
+ byte_offset_ = src_att.byte_offset_;
+ attribute_type_ = src_att.attribute_type_;
+ buffer_descriptor_ = src_att.buffer_descriptor_;
+ return true;
+}
+
+bool GeometryAttribute::operator==(const GeometryAttribute &va) const {
+ if (attribute_type_ != va.attribute_type_)
+ return false;
+ // It's OK to compare just the buffer descriptors here. We don't need to
+ // compare the buffers themselves.
+ if (buffer_descriptor_.buffer_id != va.buffer_descriptor_.buffer_id)
+ return false;
+ if (buffer_descriptor_.buffer_update_count !=
+ va.buffer_descriptor_.buffer_update_count)
+ return false;
+ if (num_components_ != va.num_components_)
+ return false;
+ if (data_type_ != va.data_type_)
+ return false;
+ if (byte_stride_ != va.byte_stride_)
+ return false;
+ if (byte_offset_ != va.byte_offset_)
+ return false;
+ return true;
+}
+
+void GeometryAttribute::ResetBuffer(DataBuffer *buffer, int64_t byte_stride,
+ int64_t byte_offset) {
+ buffer_ = buffer;
+ buffer_descriptor_.buffer_id = buffer->buffer_id();
+ buffer_descriptor_.buffer_update_count = buffer->update_count();
+ byte_stride_ = byte_stride;
+ byte_offset_ = byte_offset;
+}
+
+} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/attributes/geometry_attribute.h b/extern/draco/dracoenc/src/draco/attributes/geometry_attribute.h
new file mode 100644
index 00000000000..7be40fe2f65
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/geometry_attribute.h
@@ -0,0 +1,304 @@
+// Copyright 2016 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_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_
+#define DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_
+
+#include <array>
+#include <limits>
+
+#include "draco/attributes/geometry_indices.h"
+#include "draco/core/data_buffer.h"
+#include "draco/core/hash_utils.h"
+
+namespace draco {
+
+// The class provides access to a specific attribute which is stored in a
+// DataBuffer, such as normals or coordinates. However, the GeometryAttribute
+// class does not own the buffer and the buffer itself may store other data
+// unrelated to this attribute (such as data for other attributes in which case
+// we can have multiple GeometryAttributes accessing one buffer). Typically,
+// all attributes for a point (or corner, face) are stored in one block, which
+// is advantageous in terms of memory access. The length of the entire block is
+// given by the byte_stride, the position where the attribute starts is given by
+// the byte_offset, the actual number of bytes that the attribute occupies is
+// given by the data_type and the number of components.
+class GeometryAttribute {
+ public:
+ // Supported attribute types.
+ enum Type {
+ INVALID = -1,
+ // Named attributes start here. The difference between named and generic
+ // attributes is that for named attributes we know their purpose and we
+ // can apply some special methods when dealing with them (e.g. during
+ // encoding).
+ POSITION = 0,
+ NORMAL,
+ COLOR,
+ TEX_COORD,
+ // A special id used to mark attributes that are not assigned to any known
+ // predefined use case. Such attributes are often used for a shader specific
+ // data.
+ GENERIC,
+ // Total number of different attribute types.
+ // Always keep behind all named attributes.
+ NAMED_ATTRIBUTES_COUNT,
+ };
+
+ GeometryAttribute();
+ // Initializes and enables the attribute.
+ void Init(Type attribute_type, DataBuffer *buffer, int8_t num_components,
+ DataType data_type, bool normalized, int64_t byte_stride,
+ int64_t byte_offset);
+ bool IsValid() const { return buffer_ != nullptr; }
+
+ // Copies data from the source attribute to the this attribute.
+ // This attribute must have a valid buffer allocated otherwise the operation
+ // is going to fail and return false.
+ bool CopyFrom(const GeometryAttribute &src_att);
+
+ // Function for getting a attribute value with a specific format.
+ // Unsafe. Caller must ensure the accessed memory is valid.
+ // T is the attribute data type.
+ // att_components_t is the number of attribute components.
+ template <typename T, int att_components_t>
+ std::array<T, att_components_t> GetValue(
+ AttributeValueIndex att_index) const {
+ // Byte address of the attribute index.
+ const int64_t byte_pos = byte_offset_ + byte_stride_ * att_index.value();
+ std::array<T, att_components_t> out;
+ buffer_->Read(byte_pos, &(out[0]), sizeof(out));
+ return out;
+ }
+
+ // Function for getting a attribute value with a specific format.
+ // T is the attribute data type.
+ // att_components_t is the number of attribute components.
+ template <typename T, int att_components_t>
+ bool GetValue(AttributeValueIndex att_index,
+ std::array<T, att_components_t> *out) const {
+ // Byte address of the attribute index.
+ const int64_t byte_pos = byte_offset_ + byte_stride_ * att_index.value();
+ // Check we are not reading past end of data.
+ if (byte_pos + sizeof(*out) > buffer_->data_size())
+ return false;
+ buffer_->Read(byte_pos, &((*out)[0]), sizeof(*out));
+ return true;
+ }
+
+ // Returns the byte position of the attribute entry in the data buffer.
+ inline int64_t GetBytePos(AttributeValueIndex att_index) const {
+ return byte_offset_ + byte_stride_ * att_index.value();
+ }
+
+ inline const uint8_t *GetAddress(AttributeValueIndex att_index) const {
+ const int64_t byte_pos = GetBytePos(att_index);
+ return buffer_->data() + byte_pos;
+ }
+ inline uint8_t *GetAddress(AttributeValueIndex att_index) {
+ const int64_t byte_pos = GetBytePos(att_index);
+ return buffer_->data() + byte_pos;
+ }
+
+ // Fills out_data with the raw value of the requested attribute entry.
+ // out_data must be at least byte_stride_ long.
+ void GetValue(AttributeValueIndex att_index, void *out_data) const {
+ const int64_t byte_pos = byte_offset_ + byte_stride_ * att_index.value();
+ buffer_->Read(byte_pos, out_data, byte_stride_);
+ }
+
+ // DEPRECATED: Use
+ // ConvertValue(AttributeValueIndex att_id,
+ // int out_num_components,
+ // OutT *out_val);
+ //
+ // Function for conversion of a attribute to a specific output format.
+ // OutT is the desired data type of the attribute.
+ // out_att_components_t is the number of components of the output format.
+ // Returns false when the conversion failed.
+ template <typename OutT, int out_att_components_t>
+ bool ConvertValue(AttributeValueIndex att_id, OutT *out_val) const {
+ return ConvertValue(att_id, out_att_components_t, out_val);
+ }
+
+ // Function for conversion of a attribute to a specific output format.
+ // |out_val| needs to be able to store |out_num_components| values.
+ // OutT is the desired data type of the attribute.
+ // Returns false when the conversion failed.
+ template <typename OutT>
+ bool ConvertValue(AttributeValueIndex att_id, int8_t out_num_components,
+ OutT *out_val) const {
+ if (out_val == nullptr)
+ return false;
+ switch (data_type_) {
+ case DT_INT8:
+ return ConvertTypedValue<int8_t, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_UINT8:
+ return ConvertTypedValue<uint8_t, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_INT16:
+ return ConvertTypedValue<int16_t, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_UINT16:
+ return ConvertTypedValue<uint16_t, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_INT32:
+ return ConvertTypedValue<int32_t, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_UINT32:
+ return ConvertTypedValue<uint32_t, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_INT64:
+ return ConvertTypedValue<int64_t, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_UINT64:
+ return ConvertTypedValue<uint64_t, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_FLOAT32:
+ return ConvertTypedValue<float, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_FLOAT64:
+ return ConvertTypedValue<double, OutT>(att_id, out_num_components,
+ out_val);
+ case DT_BOOL:
+ return ConvertTypedValue<bool, OutT>(att_id, out_num_components,
+ out_val);
+ default:
+ // Wrong attribute type.
+ return false;
+ }
+ }
+
+ // Function for conversion of a attribute to a specific output format.
+ // The |out_value| must be able to store all components of a single attribute
+ // entry.
+ // OutT is the desired data type of the attribute.
+ // Returns false when the conversion failed.
+ template <typename OutT>
+ bool ConvertValue(AttributeValueIndex att_index, OutT *out_value) const {
+ return ConvertValue<OutT>(att_index, num_components_, out_value);
+ }
+
+ bool operator==(const GeometryAttribute &va) const;
+
+ // Returns the type of the attribute indicating the nature of the attribute.
+ Type attribute_type() const { return attribute_type_; }
+ void set_attribute_type(Type type) { attribute_type_ = type; }
+ // Returns the data type that is stored in the attribute.
+ DataType data_type() const { return data_type_; }
+ // Returns the number of components that are stored for each entry.
+ // For position attribute this is usually three (x,y,z),
+ // while texture coordinates have two components (u,v).
+ int8_t num_components() const { return num_components_; }
+ // Indicates whether the data type should be normalized before interpretation,
+ // that is, it should be divided by the max value of the data type.
+ bool normalized() const { return normalized_; }
+ // The buffer storing the entire data of the attribute.
+ const DataBuffer *buffer() const { return buffer_; }
+ // Returns the number of bytes between two attribute entries, this is, at
+ // least size of the data types times number of components.
+ int64_t byte_stride() const { return byte_stride_; }
+ // The offset where the attribute starts within the block of size byte_stride.
+ int64_t byte_offset() const { return byte_offset_; }
+ void set_byte_offset(int64_t byte_offset) { byte_offset_ = byte_offset; }
+ DataBufferDescriptor buffer_descriptor() const { return buffer_descriptor_; }
+ uint32_t unique_id() const { return unique_id_; }
+ void set_unique_id(uint32_t id) { unique_id_ = id; }
+
+ protected:
+ // Sets a new internal storage for the attribute.
+ void ResetBuffer(DataBuffer *buffer, int64_t byte_stride,
+ int64_t byte_offset);
+
+ private:
+ // Function for conversion of an attribute to a specific output format given a
+ // format of the stored attribute.
+ // T is the stored attribute data type.
+ // OutT is the desired data type of the attribute.
+ template <typename T, typename OutT>
+ bool ConvertTypedValue(AttributeValueIndex att_id, int8_t out_num_components,
+ OutT *out_value) const {
+ const uint8_t *src_address = GetAddress(att_id);
+
+ // Convert all components available in both the original and output formats.
+ for (int i = 0; i < std::min(num_components_, out_num_components); ++i) {
+ const T in_value = *reinterpret_cast<const T *>(src_address);
+ out_value[i] = static_cast<OutT>(in_value);
+ // When converting integer to floating point, normalize the value if
+ // necessary.
+ if (std::is_integral<T>::value && std::is_floating_point<OutT>::value &&
+ normalized_) {
+ out_value[i] /= static_cast<OutT>(std::numeric_limits<T>::max());
+ }
+ // TODO(ostava): Add handling of normalized attributes when converting
+ // between different integer representations. If the attribute is
+ // normalized, integer values should be converted as if they represent 0-1
+ // range. E.g. when we convert uint16 to uint8, the range <0, 2^16 - 1>
+ // should be converted to range <0, 2^8 - 1>.
+ src_address += sizeof(T);
+ }
+ // Fill empty data for unused output components if needed.
+ for (int i = num_components_; i < out_num_components; ++i) {
+ out_value[i] = static_cast<OutT>(0);
+ }
+ return true;
+ }
+
+ DataBuffer *buffer_;
+ // The buffer descriptor is stored at the time the buffer is attached to this
+ // attribute. The purpose is to detect if any changes happened to the buffer
+ // since the time it was attached.
+ DataBufferDescriptor buffer_descriptor_;
+ int8_t num_components_;
+ DataType data_type_;
+ bool normalized_;
+ int64_t byte_stride_;
+ int64_t byte_offset_;
+
+ Type attribute_type_;
+
+ // Unique id of this attribute. No two attributes could have the same unique
+ // id. It is used to identify each attribute, especially when there are
+ // multiple attribute of the same type in a point cloud.
+ uint32_t unique_id_;
+
+ friend struct GeometryAttributeHasher;
+};
+
+// Hashing support
+
+// Function object for using Attribute as a hash key.
+struct GeometryAttributeHasher {
+ size_t operator()(const GeometryAttribute &va) const {
+ size_t hash = HashCombine(va.buffer_descriptor_.buffer_id,
+ va.buffer_descriptor_.buffer_update_count);
+ hash = HashCombine(va.num_components_, hash);
+ hash = HashCombine((int8_t)va.data_type_, hash);
+ hash = HashCombine((int8_t)va.attribute_type_, hash);
+ hash = HashCombine(va.byte_stride_, hash);
+ return HashCombine(va.byte_offset_, hash);
+ }
+};
+
+// Function object for using GeometryAttribute::Type as a hash key.
+struct GeometryAttributeTypeHasher {
+ size_t operator()(const GeometryAttribute::Type &at) const {
+ return static_cast<size_t>(at);
+ }
+};
+
+} // namespace draco
+
+#endif // DRACO_ATTRIBUTES_GEOMETRY_ATTRIBUTE_H_
diff --git a/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h b/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h
new file mode 100644
index 00000000000..5244056f0aa
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/geometry_indices.h
@@ -0,0 +1,54 @@
+// Copyright 2016 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_ATTRIBUTES_GEOMETRY_INDICES_H_
+#define DRACO_ATTRIBUTES_GEOMETRY_INDICES_H_
+
+#include <inttypes.h>
+
+#include <limits>
+
+#include "draco/core/draco_index_type.h"
+
+namespace draco {
+
+// Index of an attribute value entry stored in a GeometryAttribute.
+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);
+// Corner index that identifies a corner in a Mesh or CornerTable.
+DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, CornerIndex);
+// Face index for Mesh and CornerTable.
+DEFINE_NEW_DRACO_INDEX_TYPE(uint32_t, FaceIndex);
+
+// Constants denoting invalid indices.
+static constexpr AttributeValueIndex kInvalidAttributeValueIndex(
+ std::numeric_limits<uint32_t>::max());
+static constexpr PointIndex kInvalidPointIndex(
+ std::numeric_limits<uint32_t>::max());
+static constexpr VertexIndex kInvalidVertexIndex(
+ std::numeric_limits<uint32_t>::max());
+static constexpr CornerIndex kInvalidCornerIndex(
+ std::numeric_limits<uint32_t>::max());
+static constexpr FaceIndex kInvalidFaceIndex(
+ std::numeric_limits<uint32_t>::max());
+
+// TODO(ostava): Add strongly typed indices for attribute id and unique
+// attribute id.
+
+} // namespace draco
+
+#endif // DRACO_ATTRIBUTES_GEOMETRY_INDICES_H_
diff --git a/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc b/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc
new file mode 100644
index 00000000000..4428f332b93
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/point_attribute.cc
@@ -0,0 +1,205 @@
+// Copyright 2016 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.
+//
+#include "draco/attributes/point_attribute.h"
+
+#include <unordered_map>
+
+using std::unordered_map;
+
+// Shortcut for typed conditionals.
+template <bool B, class T, class F>
+using conditional_t = typename std::conditional<B, T, F>::type;
+
+namespace draco {
+
+PointAttribute::PointAttribute()
+ : num_unique_entries_(0), identity_mapping_(false) {}
+
+PointAttribute::PointAttribute(const GeometryAttribute &att)
+ : GeometryAttribute(att),
+ num_unique_entries_(0),
+ identity_mapping_(false) {}
+
+void PointAttribute::CopyFrom(const PointAttribute &src_att) {
+ if (buffer() == nullptr) {
+ // If the destination attribute doesn't have a valid buffer, create it.
+ attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer());
+ ResetBuffer(attribute_buffer_.get(), 0, 0);
+ }
+ if (!GeometryAttribute::CopyFrom(src_att))
+ return;
+ identity_mapping_ = src_att.identity_mapping_;
+ num_unique_entries_ = src_att.num_unique_entries_;
+ indices_map_ = src_att.indices_map_;
+ if (src_att.attribute_transform_data_) {
+ attribute_transform_data_ = std::unique_ptr<AttributeTransformData>(
+ new AttributeTransformData(*src_att.attribute_transform_data_.get()));
+ } else {
+ attribute_transform_data_ = nullptr;
+ }
+}
+
+bool PointAttribute::Reset(size_t num_attribute_values) {
+ if (attribute_buffer_ == nullptr) {
+ attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer());
+ }
+ const int64_t entry_size = DataTypeLength(data_type()) * num_components();
+ if (!attribute_buffer_->Update(nullptr, num_attribute_values * entry_size))
+ return false;
+ // Assign the new buffer to the parent attribute.
+ ResetBuffer(attribute_buffer_.get(), entry_size, 0);
+ num_unique_entries_ = static_cast<uint32_t>(num_attribute_values);
+ return true;
+}
+
+#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+AttributeValueIndex::ValueType PointAttribute::DeduplicateValues(
+ const GeometryAttribute &in_att) {
+ return DeduplicateValues(in_att, AttributeValueIndex(0));
+}
+
+AttributeValueIndex::ValueType PointAttribute::DeduplicateValues(
+ const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) {
+ AttributeValueIndex::ValueType unique_vals = 0;
+ switch (in_att.data_type()) {
+ // Currently we support only float, uint8, and uint16 arguments.
+ case DT_FLOAT32:
+ unique_vals = DeduplicateTypedValues<float>(in_att, in_att_offset);
+ break;
+ case DT_INT8:
+ unique_vals = DeduplicateTypedValues<int8_t>(in_att, in_att_offset);
+ break;
+ case DT_UINT8:
+ case DT_BOOL:
+ unique_vals = DeduplicateTypedValues<uint8_t>(in_att, in_att_offset);
+ break;
+ case DT_UINT16:
+ unique_vals = DeduplicateTypedValues<uint16_t>(in_att, in_att_offset);
+ break;
+ case DT_INT16:
+ unique_vals = DeduplicateTypedValues<int16_t>(in_att, in_att_offset);
+ break;
+ case DT_UINT32:
+ unique_vals = DeduplicateTypedValues<uint32_t>(in_att, in_att_offset);
+ break;
+ case DT_INT32:
+ unique_vals = DeduplicateTypedValues<int32_t>(in_att, in_att_offset);
+ break;
+ default:
+ return -1; // Unsupported data type.
+ }
+ if (unique_vals == 0)
+ return -1; // Unexpected error.
+ return unique_vals;
+}
+
+// Helper function for calling UnifyDuplicateAttributes<T,num_components_t>
+// with the correct template arguments.
+// Returns the number of unique attribute values.
+template <typename T>
+AttributeValueIndex::ValueType PointAttribute::DeduplicateTypedValues(
+ const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) {
+ // Select the correct method to call based on the number of attribute
+ // components.
+ switch (in_att.num_components()) {
+ case 1:
+ return DeduplicateFormattedValues<T, 1>(in_att, in_att_offset);
+ case 2:
+ return DeduplicateFormattedValues<T, 2>(in_att, in_att_offset);
+ case 3:
+ return DeduplicateFormattedValues<T, 3>(in_att, in_att_offset);
+ case 4:
+ return DeduplicateFormattedValues<T, 4>(in_att, in_att_offset);
+ default:
+ return 0;
+ }
+}
+
+template <typename T, int num_components_t>
+AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues(
+ const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) {
+ // We want to detect duplicates using a hash map but we cannot hash floating
+ // point numbers directly so bit-copy floats to the same sized integers and
+ // hash them.
+
+ // First we need to determine which int type to use (1, 2, 4 or 8 bytes).
+ // Note, this is done at compile time using std::conditional struct.
+ // Conditional is in form <bool-expression, true, false>. If bool-expression
+ // is true the "true" branch is used and vice versa. All at compile time.
+ typedef conditional_t<sizeof(T) == 1, uint8_t,
+ conditional_t<sizeof(T) == 2, uint16_t,
+ conditional_t<sizeof(T) == 4, uint32_t,
+ /*else*/ uint64_t>>>
+ HashType;
+
+ AttributeValueIndex unique_vals(0);
+ typedef std::array<T, num_components_t> AttributeValue;
+ typedef std::array<HashType, num_components_t> AttributeHashableValue;
+ // Hash map storing index of the first attribute with a given value.
+ unordered_map<AttributeHashableValue, AttributeValueIndex,
+ HashArray<AttributeHashableValue>>
+ value_to_index_map;
+ AttributeValue att_value;
+ AttributeHashableValue hashable_value;
+ IndexTypeVector<AttributeValueIndex, AttributeValueIndex> value_map(
+ num_unique_entries_);
+ for (AttributeValueIndex i(0); i < num_unique_entries_; ++i) {
+ const AttributeValueIndex att_pos = i + in_att_offset;
+ att_value = in_att.GetValue<T, num_components_t>(att_pos);
+ // Convert the value to hashable type. Bit-copy real attributes to integers.
+ memcpy(&(hashable_value[0]), &(att_value[0]), sizeof(att_value));
+
+ // Check if the given attribute value has been used before already.
+ auto it = value_to_index_map.find(hashable_value);
+ if (it != value_to_index_map.end()) {
+ // Duplicated value found. Update index mapping.
+ value_map[i] = it->second;
+ } else {
+ // New unique value.
+ // Update the hash map with a new entry pointing to the latest unique
+ // vertex index.
+ value_to_index_map.insert(
+ std::pair<AttributeHashableValue, AttributeValueIndex>(hashable_value,
+ unique_vals));
+ // Add the unique value to the mesh builder.
+ SetAttributeValue(unique_vals, &att_value);
+ // Update index mapping.
+ value_map[i] = unique_vals;
+
+ ++unique_vals;
+ }
+ }
+ if (unique_vals == num_unique_entries_)
+ return unique_vals.value(); // Nothing has changed.
+ if (is_mapping_identity()) {
+ // Change identity mapping to the explicit one.
+ // The number of points is equal to the number of old unique values.
+ SetExplicitMapping(num_unique_entries_);
+ // Update the explicit map.
+ for (uint32_t i = 0; i < num_unique_entries_; ++i) {
+ SetPointMapEntry(PointIndex(i), value_map[AttributeValueIndex(i)]);
+ }
+ } else {
+ // Update point to value map using the mapping between old and new values.
+ for (PointIndex i(0); i < static_cast<uint32_t>(indices_map_.size()); ++i) {
+ SetPointMapEntry(i, value_map[indices_map_[i]]);
+ }
+ }
+ num_unique_entries_ = unique_vals.value();
+ return num_unique_entries_;
+}
+#endif
+
+} // namespace draco
diff --git a/extern/draco/dracoenc/src/draco/attributes/point_attribute.h b/extern/draco/dracoenc/src/draco/attributes/point_attribute.h
new file mode 100644
index 00000000000..dffde50356d
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/point_attribute.h
@@ -0,0 +1,186 @@
+// Copyright 2016 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_ATTRIBUTES_POINT_ATTRIBUTE_H_
+#define DRACO_ATTRIBUTES_POINT_ATTRIBUTE_H_
+
+#include <memory>
+
+#include "draco/draco_features.h"
+
+#include "draco/attributes/attribute_transform_data.h"
+#include "draco/attributes/geometry_attribute.h"
+#include "draco/core/draco_index_type_vector.h"
+#include "draco/core/hash_utils.h"
+#include "draco/core/macros.h"
+
+namespace draco {
+
+// Class for storing point specific data about each attribute. In general,
+// multiple points stored in a point cloud can share the same attribute value
+// and this class provides the necessary mapping between point ids and attribute
+// value ids.
+class PointAttribute : public GeometryAttribute {
+ public:
+ PointAttribute();
+ explicit PointAttribute(const GeometryAttribute &att);
+
+ // Make sure the move constructor is defined (needed for better performance
+ // when new attributes are added to PointCloud).
+ PointAttribute(PointAttribute &&attribute) = default;
+ PointAttribute &operator=(PointAttribute &&attribute) = default;
+
+ // Copies attribute data from the provided |src_att| attribute.
+ void CopyFrom(const PointAttribute &src_att);
+
+ // Prepares the attribute storage for the specified number of entries.
+ bool Reset(size_t num_attribute_values);
+
+ size_t size() const { return num_unique_entries_; }
+ AttributeValueIndex mapped_index(PointIndex point_index) const {
+ if (identity_mapping_)
+ return AttributeValueIndex(point_index.value());
+ return indices_map_[point_index];
+ }
+ DataBuffer *buffer() const { return attribute_buffer_.get(); }
+ bool is_mapping_identity() const { return identity_mapping_; }
+ size_t indices_map_size() const {
+ if (is_mapping_identity())
+ return 0;
+ return indices_map_.size();
+ }
+
+ const uint8_t *GetAddressOfMappedIndex(PointIndex point_index) const {
+ return GetAddress(mapped_index(point_index));
+ }
+
+ // Sets the new number of unique attribute entries for the attribute.
+ void Resize(size_t new_num_unique_entries) {
+ num_unique_entries_ = static_cast<uint32_t>(new_num_unique_entries);
+ }
+
+ // Functions for setting the type of mapping between point indices and
+ // attribute entry ids.
+ // This function sets the mapping to implicit, where point indices are equal
+ // to attribute entry indices.
+ void SetIdentityMapping() {
+ identity_mapping_ = true;
+ indices_map_.clear();
+ }
+ // This function sets the mapping to be explicitly using the indices_map_
+ // array that needs to be initialized by the caller.
+ void SetExplicitMapping(size_t num_points) {
+ identity_mapping_ = false;
+ indices_map_.resize(num_points, kInvalidAttributeValueIndex);
+ }
+
+ // Set an explicit map entry for a specific point index.
+ void SetPointMapEntry(PointIndex point_index,
+ AttributeValueIndex entry_index) {
+ DRACO_DCHECK(!identity_mapping_);
+ indices_map_[point_index] = entry_index;
+ }
+
+ // Sets a value of an attribute entry. The input value must be allocated to
+ // cover all components of a single attribute entry.
+ void SetAttributeValue(AttributeValueIndex entry_index, const void *value) {
+ const int64_t byte_pos = entry_index.value() * byte_stride();
+ buffer()->Write(byte_pos, value, byte_stride());
+ }
+
+ // Same as GeometryAttribute::GetValue(), but using point id as the input.
+ // Mapping to attribute value index is performed automatically.
+ void GetMappedValue(PointIndex point_index, void *out_data) const {
+ return GetValue(mapped_index(point_index), out_data);
+ }
+
+#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+ // Deduplicate |in_att| values into |this| attribute. |in_att| can be equal
+ // to |this|.
+ // Returns -1 if the deduplication failed.
+ AttributeValueIndex::ValueType DeduplicateValues(
+ const GeometryAttribute &in_att);
+
+ // Same as above but the values read from |in_att| are sampled with the
+ // provided offset |in_att_offset|.
+ AttributeValueIndex::ValueType DeduplicateValues(
+ const GeometryAttribute &in_att, AttributeValueIndex in_att_offset);
+#endif
+
+ // Set attribute transform data for the attribute. The data is used to store
+ // the type and parameters of the transform that is applied on the attribute
+ // data (optional).
+ void SetAttributeTransformData(
+ std::unique_ptr<AttributeTransformData> transform_data) {
+ attribute_transform_data_ = std::move(transform_data);
+ }
+ const AttributeTransformData *GetAttributeTransformData() const {
+ return attribute_transform_data_.get();
+ }
+
+ private:
+#ifdef DRACO_ATTRIBUTE_DEDUPLICATION_SUPPORTED
+ template <typename T>
+ AttributeValueIndex::ValueType DeduplicateTypedValues(
+ const GeometryAttribute &in_att, AttributeValueIndex in_att_offset);
+ template <typename T, int COMPONENTS_COUNT>
+ AttributeValueIndex::ValueType DeduplicateFormattedValues(
+ const GeometryAttribute &in_att, AttributeValueIndex in_att_offset);
+#endif
+
+ // Data storage for attribute values. GeometryAttribute itself doesn't own its
+ // buffer so we need to allocate it here.
+ std::unique_ptr<DataBuffer> attribute_buffer_;
+
+ // Mapping between point ids and attribute value ids.
+ IndexTypeVector<PointIndex, AttributeValueIndex> indices_map_;
+ AttributeValueIndex::ValueType num_unique_entries_;
+ // Flag when the mapping between point ids and attribute values is identity.
+ bool identity_mapping_;
+
+ // If an attribute contains transformed data (e.g. quantized), we can specify
+ // the attribute transform here and use it to transform the attribute back to
+ // its original format.
+ std::unique_ptr<AttributeTransformData> attribute_transform_data_;
+
+ friend struct PointAttributeHasher;
+};
+
+// Hash functor for the PointAttribute class.
+struct PointAttributeHasher {
+ size_t operator()(const PointAttribute &attribute) const {
+ GeometryAttributeHasher base_hasher;
+ size_t hash = base_hasher(attribute);
+ hash = HashCombine(attribute.identity_mapping_, hash);
+ hash = HashCombine(attribute.num_unique_entries_, hash);
+ hash = HashCombine(attribute.indices_map_.size(), hash);
+ if (attribute.indices_map_.size() > 0) {
+ const uint64_t indices_hash = FingerprintString(
+ reinterpret_cast<const char *>(attribute.indices_map_.data()),
+ attribute.indices_map_.size());
+ hash = HashCombine(indices_hash, hash);
+ }
+ if (attribute.attribute_buffer_ != nullptr) {
+ const uint64_t buffer_hash = FingerprintString(
+ reinterpret_cast<const char *>(attribute.attribute_buffer_->data()),
+ attribute.attribute_buffer_->data_size());
+ hash = HashCombine(buffer_hash, hash);
+ }
+ return hash;
+ }
+};
+
+} // namespace draco
+
+#endif // DRACO_ATTRIBUTES_POINT_ATTRIBUTE_H_
diff --git a/extern/draco/dracoenc/src/draco/attributes/point_attribute_test.cc b/extern/draco/dracoenc/src/draco/attributes/point_attribute_test.cc
new file mode 100644
index 00000000000..183003abea4
--- /dev/null
+++ b/extern/draco/dracoenc/src/draco/attributes/point_attribute_test.cc
@@ -0,0 +1,129 @@
+// 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.
+//
+#include "draco/attributes/point_attribute.h"
+
+#include "draco/core/draco_test_base.h"
+
+namespace {
+
+class PointAttributeTest : public ::testing::Test {
+ protected:
+ PointAttributeTest() {}
+};
+
+TEST_F(PointAttributeTest, TestCopy) {
+ // This test verifies that PointAttribute can copy data from another point
+ // attribute.
+ draco::GeometryAttribute pos_att;
+ pos_att.Init(draco::GeometryAttribute::POSITION, nullptr, 1, draco::DT_INT32,
+ false, 4, 0);
+ draco::PointAttribute pa(pos_att);
+ pa.SetIdentityMapping();
+ pa.Reset(10);
+ for (int32_t i = 0; i < 10; ++i) {
+ pa.SetAttributeValue(draco::AttributeValueIndex(i), &i);
+ }
+
+ draco::PointAttribute other_pa;
+ other_pa.CopyFrom(pa);
+
+ draco::PointAttributeHasher hasher;
+ ASSERT_EQ(hasher(pa), hasher(other_pa));
+
+ // The hash function does not actually compute the hash from attribute values,
+ // so ensure the data got copied correctly as well.
+ for (int32_t i = 0; i < 10; ++i) {
+ int32_t data;
+ other_pa.GetValue(draco::AttributeValueIndex(i), &data);
+ ASSERT_EQ(data, i);
+ }
+}
+
+TEST_F(PointAttributeTest, TestGetValueFloat) {
+ draco::GeometryAttribute pos_att;
+ pos_att.Init(draco::GeometryAttribute::POSITION, nullptr, 3,
+ draco::DT_FLOAT32, false, 4, 0);
+ draco::PointAttribute pa(pos_att);
+ pa.SetIdentityMapping();
+ pa.Reset(5);
+ float points[3];
+ for (int32_t i = 0; i < 5; ++i) {
+ points[0] = i * 3.0;
+ points[1] = (i * 3.0) + 1.0;
+ points[2] = (i * 3.0) + 2.0;
+ pa.SetAttributeValue(draco::AttributeValueIndex(i), &points);
+ }
+
+ for (int32_t i = 0; i < 5; ++i) {
+ pa.GetValue(draco::AttributeValueIndex(i), &points);
+ ASSERT_FLOAT_EQ(points[0], i * 3.0);
+ ASSERT_FLOAT_EQ(points[1], (i * 3.0) + 1.0);
+ ASSERT_FLOAT_EQ(points[2], (i * 3.0) + 2.0);
+ }
+}
+
+TEST_F(PointAttributeTest, TestGetArray) {
+ draco::GeometryAttribute pos_att;
+ pos_att.Init(draco::GeometryAttribute::POSITION, nullptr, 3,
+ draco::DT_FLOAT32, false, 4, 0);
+ draco::PointAttribute pa(pos_att);
+ pa.SetIdentityMapping();
+ pa.Reset(5);
+ float points[3];
+ for (int32_t i = 0; i < 5; ++i) {
+ points[0] = i * 3.0;
+ points[1] = (i * 3.0) + 1.0;
+ points[2] = (i * 3.0) + 2.0;
+ pa.SetAttributeValue(draco::AttributeValueIndex(i), &points);
+ }
+
+ for (int32_t i = 0; i < 5; ++i) {
+ std::array<float, 3> att_value;
+ att_value = pa.GetValue<float, 3>(draco::AttributeValueIndex(i));
+ ASSERT_FLOAT_EQ(att_value[0], i * 3.0);
+ ASSERT_FLOAT_EQ(att_value[1], (i * 3.0) + 1.0);
+ ASSERT_FLOAT_EQ(att_value[2], (i * 3.0) + 2.0);
+ }
+ for (int32_t i = 0; i < 5; ++i) {
+ std::array<float, 3> att_value;
+ EXPECT_TRUE(
+ (pa.GetValue<float, 3>(draco::AttributeValueIndex(i), &att_value)));
+ ASSERT_FLOAT_EQ(att_value[0], i * 3.0);
+ ASSERT_FLOAT_EQ(att_value[1], (i * 3.0) + 1.0);
+ ASSERT_FLOAT_EQ(att_value[2], (i * 3.0) + 2.0);
+ }
+}
+
+TEST_F(PointAttributeTest, TestArrayReadError) {
+ draco::GeometryAttribute pos_att;
+ pos_att.Init(draco::GeometryAttribute::POSITION, nullptr, 3,
+ draco::DT_FLOAT32, false, 4, 0);
+ draco::PointAttribute pa(pos_att);
+ pa.SetIdentityMapping();
+ pa.Reset(5);
+ float points[3];
+ for (int32_t i = 0; i < 5; ++i) {
+ points[0] = i * 3.0;
+ points[1] = (i * 3.0) + 1.0;
+ points[2] = (i * 3.0) + 2.0;
+ pa.SetAttributeValue(draco::AttributeValueIndex(i), &points);
+ }
+
+ std::array<float, 3> att_value;
+ EXPECT_FALSE(
+ (pa.GetValue<float, 3>(draco::AttributeValueIndex(5), &att_value)));
+}
+
+} // namespace