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

geometry_attribute.h « attributes « draco « src « draco « draco « extern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: b94ba8e22dd8b640b8491ec992e7f2309a315525 (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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
// 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_);
  }

  // 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());
  }

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

  // Utility function. Returns |attribute_type| as std::string.
  static std::string TypeToString(Type attribute_type) {
    switch (attribute_type) {
      case INVALID:
        return "INVALID";
      case POSITION:
        return "POSITION";
      case NORMAL:
        return "NORMAL";
      case COLOR:
        return "COLOR";
      case TEX_COORD:
        return "TEX_COORD";
      case GENERIC:
        return "GENERIC";
      default:
        return "UNKNOWN";
    }
  }

  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(static_cast<int8_t>(va.data_type_), hash);
    hash = HashCombine(static_cast<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_