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

point_attribute.cc « attributes « draco « src « draco « draco « extern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b28f860c15d080c1b083647d88c8e57954abcd62 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
// 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::Init(Type attribute_type, int8_t num_components,
                          DataType data_type, bool normalized,
                          size_t num_attribute_values) {
  attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer());
  GeometryAttribute::Init(attribute_type, attribute_buffer_.get(),
                          num_components, data_type, normalized,
                          DataTypeLength(data_type) * num_components, 0);
  Reset(num_attribute_values);
  SetIdentityMapping();
}

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_));
  } 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;
}

void PointAttribute::Resize(size_t new_num_unique_entries) {
  num_unique_entries_ = static_cast<uint32_t>(new_num_unique_entries);
  attribute_buffer_->Resize(new_num_unique_entries * byte_stride());
}

#ifdef DRACO_ATTRIBUTE_VALUES_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