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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/BKE_attribute_access.hh')
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh255
1 files changed, 255 insertions, 0 deletions
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
new file mode 100644
index 00000000000..e58fba36342
--- /dev/null
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -0,0 +1,255 @@
+/*
+ * 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_float3.hh"
+
+struct Mesh;
+
+namespace blender::bke {
+
+using fn::CPPType;
+
+/**
+ * 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 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), size_(size)
+ {
+ }
+
+ virtual ~ReadAttribute();
+
+ AttributeDomain domain() const
+ {
+ return domain_;
+ }
+
+ const CPPType &cpp_type() const
+ {
+ return cpp_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 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), size_(size)
+ {
+ }
+
+ virtual ~WriteAttribute();
+
+ AttributeDomain domain() const
+ {
+ return domain_;
+ }
+
+ const CPPType &cpp_type() const
+ {
+ return cpp_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 FloatWriteAttribute = TypedWriteAttribute<float>;
+using Float3WriteAttribute = TypedWriteAttribute<float3>;
+
+const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
+CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
+
+} // namespace blender::bke