/src/draco/src/draco/attributes/point_attribute.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2016 The Draco Authors. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | // |
15 | | #include "draco/attributes/point_attribute.h" |
16 | | |
17 | | #include <tuple> |
18 | | #include <unordered_map> |
19 | | using std::unordered_map; |
20 | | |
21 | | // Shortcut for typed conditionals. |
22 | | template <bool B, class T, class F> |
23 | | using conditional_t = typename std::conditional<B, T, F>::type; |
24 | | |
25 | | namespace draco { |
26 | | |
27 | | PointAttribute::PointAttribute() |
28 | 0 | : num_unique_entries_(0), identity_mapping_(false) {} |
29 | | |
30 | | PointAttribute::PointAttribute(const GeometryAttribute &att) |
31 | | : GeometryAttribute(att), |
32 | | num_unique_entries_(0), |
33 | 66.8k | identity_mapping_(false) {} |
34 | | |
35 | | void PointAttribute::Init(Type attribute_type, int8_t num_components, |
36 | | DataType data_type, bool normalized, |
37 | 0 | size_t num_attribute_values) { |
38 | 0 | attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer()); |
39 | 0 | GeometryAttribute::Init(attribute_type, attribute_buffer_.get(), |
40 | 0 | num_components, data_type, normalized, |
41 | 0 | DataTypeLength(data_type) * num_components, 0); |
42 | 0 | Reset(num_attribute_values); |
43 | 0 | SetIdentityMapping(); |
44 | 0 | } |
45 | | |
46 | 69 | void PointAttribute::CopyFrom(const PointAttribute &src_att) { |
47 | 69 | if (buffer() == nullptr) { |
48 | | // If the destination attribute doesn't have a valid buffer, create it. |
49 | 0 | attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer()); |
50 | 0 | ResetBuffer(attribute_buffer_.get(), 0, 0); |
51 | 0 | } |
52 | 69 | if (!GeometryAttribute::CopyFrom(src_att)) { |
53 | 0 | return; |
54 | 0 | } |
55 | 69 | identity_mapping_ = src_att.identity_mapping_; |
56 | 69 | num_unique_entries_ = src_att.num_unique_entries_; |
57 | 69 | indices_map_ = src_att.indices_map_; |
58 | 69 | if (src_att.attribute_transform_data_) { |
59 | 4 | attribute_transform_data_ = std::unique_ptr<AttributeTransformData>( |
60 | 4 | new AttributeTransformData(*src_att.attribute_transform_data_)); |
61 | 65 | } else { |
62 | 65 | attribute_transform_data_ = nullptr; |
63 | 65 | } |
64 | 69 | } |
65 | | |
66 | 4.10k | bool PointAttribute::Reset(size_t num_attribute_values) { |
67 | 4.10k | if (attribute_buffer_ == nullptr) { |
68 | 4.10k | attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer()); |
69 | 4.10k | } |
70 | 4.10k | const int64_t entry_size = DataTypeLength(data_type()) * num_components(); |
71 | 4.10k | if (!attribute_buffer_->Update(nullptr, num_attribute_values * entry_size)) { |
72 | 0 | return false; |
73 | 0 | } |
74 | | // Assign the new buffer to the parent attribute. |
75 | 4.10k | ResetBuffer(attribute_buffer_.get(), entry_size, 0); |
76 | 4.10k | num_unique_entries_ = static_cast<uint32_t>(num_attribute_values); |
77 | 4.10k | return true; |
78 | 4.10k | } |
79 | | |
80 | 0 | void PointAttribute::Resize(size_t new_num_unique_entries) { |
81 | 0 | num_unique_entries_ = static_cast<uint32_t>(new_num_unique_entries); |
82 | 0 | attribute_buffer_->Resize(new_num_unique_entries * byte_stride()); |
83 | 0 | } |
84 | | |
85 | | #ifdef DRACO_ATTRIBUTE_VALUES_DEDUPLICATION_SUPPORTED |
86 | | AttributeValueIndex::ValueType PointAttribute::DeduplicateValues( |
87 | 0 | const GeometryAttribute &in_att) { |
88 | 0 | return DeduplicateValues(in_att, AttributeValueIndex(0)); |
89 | 0 | } |
90 | | |
91 | | AttributeValueIndex::ValueType PointAttribute::DeduplicateValues( |
92 | 0 | const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) { |
93 | 0 | AttributeValueIndex::ValueType unique_vals = 0; |
94 | 0 | switch (in_att.data_type()) { |
95 | | // Currently we support only float, uint8, and uint16 arguments. |
96 | 0 | case DT_FLOAT32: |
97 | 0 | unique_vals = DeduplicateTypedValues<float>(in_att, in_att_offset); |
98 | 0 | break; |
99 | 0 | case DT_INT8: |
100 | 0 | unique_vals = DeduplicateTypedValues<int8_t>(in_att, in_att_offset); |
101 | 0 | break; |
102 | 0 | case DT_UINT8: |
103 | 0 | case DT_BOOL: |
104 | 0 | unique_vals = DeduplicateTypedValues<uint8_t>(in_att, in_att_offset); |
105 | 0 | break; |
106 | 0 | case DT_UINT16: |
107 | 0 | unique_vals = DeduplicateTypedValues<uint16_t>(in_att, in_att_offset); |
108 | 0 | break; |
109 | 0 | case DT_INT16: |
110 | 0 | unique_vals = DeduplicateTypedValues<int16_t>(in_att, in_att_offset); |
111 | 0 | break; |
112 | 0 | case DT_UINT32: |
113 | 0 | unique_vals = DeduplicateTypedValues<uint32_t>(in_att, in_att_offset); |
114 | 0 | break; |
115 | 0 | case DT_INT32: |
116 | 0 | unique_vals = DeduplicateTypedValues<int32_t>(in_att, in_att_offset); |
117 | 0 | break; |
118 | 0 | default: |
119 | 0 | return -1; // Unsupported data type. |
120 | 0 | } |
121 | 0 | if (unique_vals == 0) { |
122 | 0 | return -1; // Unexpected error. |
123 | 0 | } |
124 | 0 | return unique_vals; |
125 | 0 | } |
126 | | |
127 | | // Helper function for calling UnifyDuplicateAttributes<T,num_components_t> |
128 | | // with the correct template arguments. |
129 | | // Returns the number of unique attribute values. |
130 | | template <typename T> |
131 | | AttributeValueIndex::ValueType PointAttribute::DeduplicateTypedValues( |
132 | 0 | const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) { |
133 | | // Select the correct method to call based on the number of attribute |
134 | | // components. |
135 | 0 | switch (in_att.num_components()) { |
136 | 0 | case 1: |
137 | 0 | return DeduplicateFormattedValues<T, 1>(in_att, in_att_offset); |
138 | 0 | case 2: |
139 | 0 | return DeduplicateFormattedValues<T, 2>(in_att, in_att_offset); |
140 | 0 | case 3: |
141 | 0 | return DeduplicateFormattedValues<T, 3>(in_att, in_att_offset); |
142 | 0 | case 4: |
143 | 0 | return DeduplicateFormattedValues<T, 4>(in_att, in_att_offset); |
144 | 0 | default: |
145 | 0 | return 0; |
146 | 0 | } |
147 | 0 | } Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<float>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<signed char>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<unsigned char>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<unsigned short>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<short>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<unsigned int>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateTypedValues<int>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) |
148 | | |
149 | | template <typename T, int num_components_t> |
150 | | AttributeValueIndex::ValueType PointAttribute::DeduplicateFormattedValues( |
151 | 0 | const GeometryAttribute &in_att, AttributeValueIndex in_att_offset) { |
152 | | // We want to detect duplicates using a hash map but we cannot hash floating |
153 | | // point numbers directly so bit-copy floats to the same sized integers and |
154 | | // hash them. |
155 | | |
156 | | // First we need to determine which int type to use (1, 2, 4 or 8 bytes). |
157 | | // Note, this is done at compile time using std::conditional struct. |
158 | | // Conditional is in form <bool-expression, true, false>. If bool-expression |
159 | | // is true the "true" branch is used and vice versa. All at compile time. |
160 | 0 | typedef conditional_t<sizeof(T) == 1, uint8_t, |
161 | 0 | conditional_t<sizeof(T) == 2, uint16_t, |
162 | 0 | conditional_t<sizeof(T) == 4, uint32_t, |
163 | 0 | /*else*/ uint64_t>>> |
164 | 0 | HashType; |
165 | |
|
166 | 0 | AttributeValueIndex unique_vals(0); |
167 | 0 | typedef std::array<T, num_components_t> AttributeValue; |
168 | 0 | typedef std::array<HashType, num_components_t> AttributeHashableValue; |
169 | 0 | typedef unordered_map<AttributeHashableValue, AttributeValueIndex, |
170 | 0 | HashArray<AttributeHashableValue>> |
171 | 0 | ValueToIndexMap; |
172 | | |
173 | | // Hash map storing index of the first attribute with a given value. |
174 | 0 | ValueToIndexMap value_to_index_map; |
175 | 0 | AttributeValue att_value; |
176 | 0 | AttributeHashableValue hashable_value; |
177 | 0 | IndexTypeVector<AttributeValueIndex, AttributeValueIndex> value_map( |
178 | 0 | num_unique_entries_); |
179 | 0 | for (AttributeValueIndex i(0); i < num_unique_entries_; ++i) { |
180 | 0 | const AttributeValueIndex att_pos = i + in_att_offset; |
181 | 0 | att_value = in_att.GetValue<T, num_components_t>(att_pos); |
182 | | // Convert the value to hashable type. Bit-copy real attributes to integers. |
183 | 0 | memcpy(&(hashable_value[0]), &(att_value[0]), sizeof(att_value)); |
184 | |
|
185 | 0 | typename ValueToIndexMap::iterator it; |
186 | 0 | bool inserted; |
187 | 0 | std::tie(it, inserted) = value_to_index_map.insert( |
188 | 0 | std::pair<AttributeHashableValue, AttributeValueIndex>(hashable_value, |
189 | 0 | unique_vals)); |
190 | | |
191 | | // Try to update the hash map with a new entry pointing to the latest unique |
192 | | // vertex index. |
193 | 0 | if (!inserted) { |
194 | | // Duplicated value found. Update index mapping. |
195 | 0 | value_map[i] = it->second; |
196 | 0 | } else { |
197 | | // New unique value. |
198 | 0 | SetAttributeValue(unique_vals, &att_value); |
199 | | // Update index mapping. |
200 | 0 | value_map[i] = unique_vals; |
201 | |
|
202 | 0 | ++unique_vals; |
203 | 0 | } |
204 | 0 | } |
205 | 0 | if (unique_vals == num_unique_entries_) { |
206 | 0 | return unique_vals.value(); // Nothing has changed. |
207 | 0 | } |
208 | 0 | if (is_mapping_identity()) { |
209 | | // Change identity mapping to the explicit one. |
210 | | // The number of points is equal to the number of old unique values. |
211 | 0 | SetExplicitMapping(num_unique_entries_); |
212 | | // Update the explicit map. |
213 | 0 | for (uint32_t i = 0; i < num_unique_entries_; ++i) { |
214 | 0 | SetPointMapEntry(PointIndex(i), value_map[AttributeValueIndex(i)]); |
215 | 0 | } |
216 | 0 | } else { |
217 | | // Update point to value map using the mapping between old and new values. |
218 | 0 | for (PointIndex i(0); i < static_cast<uint32_t>(indices_map_.size()); ++i) { |
219 | 0 | SetPointMapEntry(i, value_map[indices_map_[i]]); |
220 | 0 | } |
221 | 0 | } |
222 | 0 | num_unique_entries_ = unique_vals.value(); |
223 | 0 | return num_unique_entries_; |
224 | 0 | } Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<float, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<float, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<float, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<float, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<signed char, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<signed char, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<signed char, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<signed char, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned char, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned char, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned char, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned char, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned short, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned short, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned short, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned short, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<short, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<short, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<short, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<short, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned int, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned int, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned int, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<unsigned int, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<int, 1>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<int, 2>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<int, 3>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) Unexecuted instantiation: unsigned int draco::PointAttribute::DeduplicateFormattedValues<int, 4>(draco::GeometryAttribute const&, draco::IndexType<unsigned int, draco::AttributeValueIndex_tag_type_>) |
225 | | #endif |
226 | | |
227 | | #ifdef DRACO_TRANSCODER_SUPPORTED |
228 | | void PointAttribute::RemoveUnusedValues() { |
229 | | if (is_mapping_identity()) { |
230 | | return; // For identity mapping, all values are always used. |
231 | | } |
232 | | // For explicit mapping we need to check if any point is mapped to a value. |
233 | | // If not we can delete the value. |
234 | | IndexTypeVector<AttributeValueIndex, bool> is_value_used(size(), false); |
235 | | int num_used_values = 0; |
236 | | for (PointIndex pi(0); pi < indices_map_.size(); ++pi) { |
237 | | const AttributeValueIndex avi = indices_map_[pi]; |
238 | | if (!is_value_used[avi]) { |
239 | | is_value_used[avi] = true; |
240 | | num_used_values++; |
241 | | } |
242 | | } |
243 | | if (num_used_values == size()) { |
244 | | return; // All values are used. |
245 | | } |
246 | | |
247 | | // Remap the values and update the point to value mapping. |
248 | | IndexTypeVector<AttributeValueIndex, AttributeValueIndex> |
249 | | old_to_new_value_map(size(), kInvalidAttributeValueIndex); |
250 | | AttributeValueIndex new_avi(0); |
251 | | for (AttributeValueIndex avi(0); avi < size(); ++avi) { |
252 | | if (!is_value_used[avi]) { |
253 | | continue; |
254 | | } |
255 | | if (avi != new_avi) { |
256 | | SetAttributeValue(new_avi, GetAddress(avi)); |
257 | | } |
258 | | old_to_new_value_map[avi] = new_avi++; |
259 | | } |
260 | | |
261 | | // Remap all points to the new attribute values. |
262 | | for (PointIndex pi(0); pi < indices_map_.size(); ++pi) { |
263 | | indices_map_[pi] = old_to_new_value_map[indices_map_[pi]]; |
264 | | } |
265 | | |
266 | | num_unique_entries_ = num_used_values; |
267 | | } |
268 | | #endif |
269 | | |
270 | | } // namespace draco |