diff options
Diffstat (limited to 'extern/draco/dracoenc/src/draco/attributes/point_attribute.cc')
-rw-r--r-- | extern/draco/dracoenc/src/draco/attributes/point_attribute.cc | 205 |
1 files changed, 205 insertions, 0 deletions
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 |