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

BKE_attribute_access.hh « blenkernel « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: c4a704ef3855bbb957ca57ab578f24988eaf0239 (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
/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#pragma once

#include <mutex>

#include "FN_cpp_type.hh"
#include "FN_spans.hh"

#include "BKE_attribute.h"

#include "BLI_color.hh"
#include "BLI_float3.hh"

struct Mesh;

namespace blender::bke {

using fn::CPPType;

const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
CustomDataType cpp_type_to_custom_data_type(const CPPType &type);

/**
 * This class offers an indirection for reading an attribute.
 * This is useful for the following reasons:
 * - Blender does not store all attributes the same way.
 *   The simplest case are custom data layers with primitive types.
 *   A bit more complex are mesh attributes like the position of vertices,
 *   which are embedded into the MVert struct.
 *   Even more complex to access are vertex weights.
 * - Sometimes attributes are stored on one domain, but we want to access
 *   the attribute on a different domain. Therefore, we have to interpolate
 *   between the domains.
 */
class ReadAttribute {
 protected:
  const AttributeDomain domain_;
  const CPPType &cpp_type_;
  const CustomDataType custom_data_type_;
  const int64_t size_;

  /* Protects the span below, so that no two threads initialize it at the same time. */
  mutable std::mutex span_mutex_;
  /* When it is not null, it points to the attribute array or a temporary array that contains all
   * the attribute values. */
  mutable void *array_buffer_ = nullptr;
  /* Is true when the buffer above is owned by the attribute accessor. */
  mutable bool array_is_temporary_ = false;

 public:
  ReadAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
      : domain_(domain),
        cpp_type_(cpp_type),
        custom_data_type_(cpp_type_to_custom_data_type(cpp_type)),
        size_(size)
  {
  }

  virtual ~ReadAttribute();

  AttributeDomain domain() const
  {
    return domain_;
  }

  const CPPType &cpp_type() const
  {
    return cpp_type_;
  }

  CustomDataType custom_data_type() const
  {
    return custom_data_type_;
  }

  int64_t size() const
  {
    return size_;
  }

  void get(const int64_t index, void *r_value) const
  {
    BLI_assert(index < size_);
    this->get_internal(index, r_value);
  }

  /* Get a span that contains all attribute values. */
  fn::GSpan get_span() const;

 protected:
  /* r_value is expected to be uninitialized. */
  virtual void get_internal(const int64_t index, void *r_value) const = 0;

  virtual void initialize_span() const;
};

/**
 * This exists for similar reasons as the ReadAttribute class, except that
 * it does not deal with interpolation between domains.
 */
class WriteAttribute {
 protected:
  const AttributeDomain domain_;
  const CPPType &cpp_type_;
  const CustomDataType custom_data_type_;
  const int64_t size_;

  /* When not null, this points either to the attribute array or to a temporary array. */
  void *array_buffer_ = nullptr;
  /* True, when the buffer points to a temporary array. */
  bool array_is_temporary_ = false;
  /* This helps to protect agains forgetting to apply changes done to the array. */
  bool array_should_be_applied_ = false;

 public:
  WriteAttribute(AttributeDomain domain, const CPPType &cpp_type, const int64_t size)
      : domain_(domain),
        cpp_type_(cpp_type),
        custom_data_type_(cpp_type_to_custom_data_type(cpp_type)),
        size_(size)
  {
  }

  virtual ~WriteAttribute();

  AttributeDomain domain() const
  {
    return domain_;
  }

  const CPPType &cpp_type() const
  {
    return cpp_type_;
  }

  CustomDataType custom_data_type() const
  {
    return custom_data_type_;
  }

  int64_t size() const
  {
    return size_;
  }

  void get(const int64_t index, void *r_value) const
  {
    BLI_assert(index < size_);
    this->get_internal(index, r_value);
  }

  void set(const int64_t index, const void *value)
  {
    BLI_assert(index < size_);
    this->set_internal(index, value);
  }

  /* Get a span that new attribute values can be written into. When all values have been changed,
   * #apply_span has to be called. The span might not contain the original attribute values. */
  fn::GMutableSpan get_span();
  /* Write the changes to the span into the actual attribute, if they aren't already. */
  void apply_span();

 protected:
  virtual void get_internal(const int64_t index, void *r_value) const = 0;
  virtual void set_internal(const int64_t index, const void *value) = 0;

  virtual void initialize_span();
  virtual void apply_span_if_necessary();
};

using ReadAttributePtr = std::unique_ptr<ReadAttribute>;
using WriteAttributePtr = std::unique_ptr<WriteAttribute>;

/* This provides type safe access to an attribute. */
template<typename T> class TypedReadAttribute {
 private:
  ReadAttributePtr attribute_;

 public:
  TypedReadAttribute(ReadAttributePtr attribute) : attribute_(std::move(attribute))
  {
    BLI_assert(attribute_);
    BLI_assert(attribute_->cpp_type().is<T>());
  }

  int64_t size() const
  {
    return attribute_->size();
  }

  T operator[](const int64_t index) const
  {
    BLI_assert(index < attribute_->size());
    T value;
    value.~T();
    attribute_->get(index, &value);
    return value;
  }

  /* Get a span to that contains all attribute values for faster and more convenient access. */
  Span<T> get_span() const
  {
    return attribute_->get_span().template typed<T>();
  }
};

/* This provides type safe access to an attribute. */
template<typename T> class TypedWriteAttribute {
 private:
  WriteAttributePtr attribute_;

 public:
  TypedWriteAttribute(WriteAttributePtr attribute) : attribute_(std::move(attribute))
  {
    BLI_assert(attribute_);
    BLI_assert(attribute_->cpp_type().is<T>());
  }

  int64_t size() const
  {
    return attribute_->size();
  }

  T operator[](const int64_t index) const
  {
    BLI_assert(index < attribute_->size());
    T value;
    value.~T();
    attribute_->get(index, &value);
    return value;
  }

  void set(const int64_t index, const T &value)
  {
    attribute_->set(index, &value);
  }

  /* Get a span that new values can be written into. Once all values have been updated #apply_span
   * has to be called. The span might *not* contain the initial attribute values, so one should
   * generally only write to the span. */
  MutableSpan<T> get_span()
  {
    return attribute_->get_span().typed<T>();
  }

  /* Write back all changes to the actual attribute, if necessary. */
  void apply_span()
  {
    attribute_->apply_span();
  }
};

using FloatReadAttribute = TypedReadAttribute<float>;
using Float3ReadAttribute = TypedReadAttribute<float3>;
using Color4fReadAttribute = TypedReadAttribute<Color4f>;
using FloatWriteAttribute = TypedWriteAttribute<float>;
using Float3WriteAttribute = TypedWriteAttribute<float3>;
using Color4fWriteAttribute = TypedWriteAttribute<Color4f>;

}  // namespace blender::bke