/* * 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 #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; 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; using WriteAttributePtr = std::unique_ptr; /* This provides type safe access to an attribute. */ template class TypedReadAttribute { private: ReadAttributePtr attribute_; public: TypedReadAttribute(ReadAttributePtr attribute) : attribute_(std::move(attribute)) { BLI_assert(attribute_); BLI_assert(attribute_->cpp_type().is()); } 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 get_span() const { return attribute_->get_span().template typed(); } }; /* This provides type safe access to an attribute. */ template class TypedWriteAttribute { private: WriteAttributePtr attribute_; public: TypedWriteAttribute(WriteAttributePtr attribute) : attribute_(std::move(attribute)) { BLI_assert(attribute_); BLI_assert(attribute_->cpp_type().is()); } 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 get_span() { return attribute_->get_span().typed(); } /* Write back all changes to the actual attribute, if necessary. */ void apply_span() { attribute_->apply_span(); } }; using FloatReadAttribute = TypedReadAttribute; using Float3ReadAttribute = TypedReadAttribute; using FloatWriteAttribute = TypedWriteAttribute; using Float3WriteAttribute = TypedWriteAttribute; const CPPType *custom_data_type_to_cpp_type(const CustomDataType type); CustomDataType cpp_type_to_custom_data_type(const CPPType &type); } // namespace blender::bke