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')
-rw-r--r--source/blender/blenkernel/BKE_attribute_access.hh307
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh32
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_context.h19
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh186
-rw-r--r--source/blender/blenkernel/BKE_mesh_sample.hh55
-rw-r--r--source/blender/blenkernel/BKE_node.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/appdir.c2
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc606
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh219
-rw-r--r--source/blender/blenkernel/intern/blender.c2
-rw-r--r--source/blender/blenkernel/intern/context.c51
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc395
-rw-r--r--source/blender/blenkernel/intern/geometry_component_pointcloud.cc59
-rw-r--r--source/blender/blenkernel/intern/geometry_set_instances.cc15
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.c26
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.cc158
-rw-r--r--source/blender/blenkernel/intern/node.cc1
-rw-r--r--source/blender/blenkernel/intern/object.c2
-rw-r--r--source/blender/blenkernel/intern/volume.cc74
-rw-r--r--source/blender/blenlib/BLI_map.hh80
-rw-r--r--source/blender/blenlib/BLI_map_slots.hh12
-rw-r--r--source/blender/blenlib/BLI_span.hh4
-rw-r--r--source/blender/blenlib/BLI_stack.hh5
-rw-r--r--source/blender/blenlib/BLI_vector.hh22
-rw-r--r--source/blender/blenlib/BLI_virtual_array.hh384
-rw-r--r--source/blender/blenlib/tests/BLI_map_test.cc9
-rw-r--r--source/blender/blenlib/tests/BLI_stack_cxx_test.cc9
-rw-r--r--source/blender/blenlib/tests/BLI_vector_test.cc9
-rw-r--r--source/blender/blenlib/tests/BLI_virtual_array_test.cc133
-rw-r--r--source/blender/blenloader/CMakeLists.txt1
-rw-r--r--source/blender/blenloader/intern/readfile.c2
-rw-r--r--source/blender/blenloader/intern/readfile.h2
-rw-r--r--source/blender/blenloader/intern/versioning_290.c13
-rw-r--r--source/blender/blenloader/intern/versioning_300.c80
-rw-r--r--source/blender/draw/intern/draw_cache_impl_gpencil.c9
-rw-r--r--source/blender/editors/curve/editcurve.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c2
-rw-r--r--source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c90
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c48
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c73
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h1
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c26
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c1
-rw-r--r--source/blender/editors/include/ED_gizmo_library.h5
-rw-r--r--source/blender/editors/include/ED_keyframing.h1
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h17
-rw-r--r--source/blender/editors/include/UI_interface.h16
-rw-r--r--source/blender/editors/interface/interface_handlers.c6
-rw-r--r--source/blender/editors/interface/interface_intern.h15
-rw-r--r--source/blender/editors/interface/interface_region_tooltip.c8
-rw-r--r--source/blender/editors/io/io_alembic.c23
-rw-r--r--source/blender/editors/io/io_collada.c16
-rw-r--r--source/blender/editors/io/io_gpencil_export.c18
-rw-r--r--source/blender/editors/io/io_gpencil_import.c8
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c49
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c34
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c31
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c2
-rw-r--r--source/blender/editors/object/object_add.c21
-rw-r--r--source/blender/editors/screen/screendump.c6
-rw-r--r--source/blender/editors/space_image/image_ops.c66
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c18
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc2
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc43
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_placement.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c2
-rw-r--r--source/blender/editors/transform/transform_snap.c6
-rw-r--r--source/blender/editors/transform/transform_snap_object.c667
-rw-r--r--source/blender/functions/FN_generic_span.hh20
-rw-r--r--source/blender/functions/FN_generic_vector_array.hh6
-rw-r--r--source/blender/functions/FN_generic_virtual_array.hh683
-rw-r--r--source/blender/functions/FN_generic_virtual_vector_array.hh16
-rw-r--r--source/blender/functions/FN_multi_function_params.hh10
-rw-r--r--source/blender/functions/intern/generic_vector_array.cc6
-rw-r--r--source/blender/functions/intern/generic_virtual_array.cc216
-rw-r--r--source/blender/functions/intern/generic_virtual_vector_array.cc26
-rw-r--r--source/blender/functions/intern/multi_function_network_evaluation.cc28
-rw-r--r--source/blender/functions/tests/FN_multi_function_network_test.cc2
-rw-r--r--source/blender/makesdna/DNA_node_types.h5
-rw-r--r--source/blender/makesdna/DNA_space_types.h2
-rw-r--r--source/blender/makesrna/intern/rna_ID.c30
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c50
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/nodes/CMakeLists.txt1
-rw-r--r--source/blender/nodes/NOD_geometry.h1
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh52
-rw-r--r--source/blender/nodes/NOD_static_types.h1
-rw-r--r--source/blender/nodes/NOD_type_conversions.hh4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc30
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc21
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc87
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc29
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc24
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc77
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc63
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc65
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc34
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc145
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc11
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc170
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_instance.cc8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc26
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_scale.cc12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_separate.cc18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_translate.cc19
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc163
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc50
-rw-r--r--source/blender/nodes/intern/type_conversions.cc112
-rw-r--r--source/blender/python/gpu/gpu_py_buffer.c176
-rw-r--r--source/blender/python/intern/CMakeLists.txt2
-rw-r--r--source/blender/python/intern/bpy_interface.c11
-rw-r--r--source/blender/python/intern/bpy_operator.c8
-rw-r--r--source/blender/python/intern/bpy_rna_operator.c150
-rw-r--r--source/blender/python/intern/bpy_rna_operator.h31
-rw-r--r--source/blender/python/intern/bpy_rna_types_capi.c18
-rw-r--r--source/blender/windowmanager/WM_types.h10
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c4
-rw-r--r--source/blender/windowmanager/intern/wm_files.c66
-rw-r--r--source/blender/windowmanager/wm_files.h1
134 files changed, 4596 insertions, 2755 deletions
diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh
index 120b4e08b9c..f6a6de04b70 100644
--- a/source/blender/blenkernel/BKE_attribute_access.hh
+++ b/source/blender/blenkernel/BKE_attribute_access.hh
@@ -20,6 +20,7 @@
#include "FN_cpp_type.hh"
#include "FN_generic_span.hh"
+#include "FN_generic_virtual_array.hh"
#include "BKE_attribute.h"
@@ -30,6 +31,10 @@
namespace blender::bke {
using fn::CPPType;
+using fn::GVArray;
+using fn::GVArrayPtr;
+using fn::GVMutableArray;
+using fn::GVMutableArrayPtr;
const CPPType *custom_data_type_to_cpp_type(const CustomDataType type);
CustomDataType cpp_type_to_custom_data_type(const CPPType &type);
@@ -37,113 +42,93 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_
AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains);
/**
- * 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.
+ * Used when looking up a "plain attribute" based on a name for reading from it.
*/
-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;
+struct ReadAttributeLookup {
+ /* The virtual array that is used to read from this attribute. */
+ GVArrayPtr varray;
+ /* Domain the attribute lives on in the geometry. */
+ AttributeDomain domain;
- 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)
+ /* Convenience function to check if the attribute has been found. */
+ operator bool() const
{
+ return this->varray.get() != nullptr;
}
+};
- virtual ~ReadAttribute();
+/**
+ * Used when looking up a "plain attribute" based on a name for reading from it and writing to it.
+ */
+struct WriteAttributeLookup {
+ /* The virtual array that is used to read from and write to the attribute. */
+ GVMutableArrayPtr varray;
+ /* Domain the attributes lives on in the geometry. */
+ AttributeDomain domain;
- AttributeDomain domain() const
+ /* Convenience function to check if the attribute has been found. */
+ operator bool() const
{
- return domain_;
+ return this->varray.get() != nullptr;
}
+};
- const CPPType &cpp_type() const
- {
- return cpp_type_;
- }
+/**
+ * An output attribute allows writing to an attribute (and optionally reading as well). It adds
+ * some convenience features on top of `GVMutableArray` that are very commonly used.
+ *
+ * Supported convenience features:
+ * - Implicit type conversion when writing to builtin attributes.
+ * - Supports simple access to a span containing the attribute values (that avoids the use of
+ * VMutableArray_Span in many cases).
+ * - An output attribute can live side by side with an existing attribute with a different domain
+ * or data type. The old attribute will only be overwritten when the #save function is called.
+ */
+class OutputAttribute {
+ public:
+ using SaveFn = std::function<void(OutputAttribute &)>;
- CustomDataType custom_data_type() const
+ private:
+ GVMutableArrayPtr varray_;
+ AttributeDomain domain_;
+ SaveFn save_;
+ std::optional<fn::GVMutableArray_GSpan> optional_span_varray_;
+ bool ignore_old_values_ = false;
+
+ public:
+ OutputAttribute() = default;
+
+ OutputAttribute(GVMutableArrayPtr varray,
+ AttributeDomain domain,
+ SaveFn save,
+ const bool ignore_old_values)
+ : varray_(std::move(varray)),
+ domain_(domain),
+ save_(std::move(save)),
+ ignore_old_values_(ignore_old_values)
{
- return custom_data_type_;
}
- int64_t size() const
+ operator bool() const
{
- return size_;
+ return varray_.get() != nullptr;
}
- void get(const int64_t index, void *r_value) const
+ GVMutableArray &operator*()
{
- BLI_assert(index < size_);
- this->get_internal(index, r_value);
+ return *varray_;
}
- /* Get a span that contains all attribute values. */
- fn::GSpan get_span() const;
-
- template<typename T> Span<T> get_span() const
+ GVMutableArray *operator->()
{
- return this->get_span().typed<T>();
+ return varray_.get();
}
- 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 against 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)
+ GVMutableArray &varray()
{
+ return *varray_;
}
- virtual ~WriteAttribute();
-
AttributeDomain domain() const
{
return domain_;
@@ -151,168 +136,94 @@ class WriteAttribute {
const CPPType &cpp_type() const
{
- return cpp_type_;
+ return varray_->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);
+ return cpp_type_to_custom_data_type(this->cpp_type());
}
- void set(const int64_t index, const void *value)
+ fn::GMutableSpan as_span()
{
- BLI_assert(index < size_);
- this->set_internal(index, value);
+ if (!optional_span_varray_.has_value()) {
+ const bool materialize_old_values = !ignore_old_values_;
+ optional_span_varray_.emplace(*varray_, materialize_old_values);
+ }
+ fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_;
+ return span_varray;
}
- /* Get a span that new attribute values can be written into. When all values have been changed,
- * #apply_span has to be called. */
- fn::GMutableSpan get_span();
- /* The span returned by this method might not contain the current attribute values. */
- fn::GMutableSpan get_span_for_write_only();
- /* Write the changes to the span into the actual attribute, if they aren't already. */
- void apply_span();
-
- template<typename T> MutableSpan<T> get_span()
+ template<typename T> MutableSpan<T> as_span()
{
- return this->get_span().typed<T>();
+ return this->as_span().typed<T>();
}
- template<typename T> MutableSpan<T> get_span_for_write_only()
- {
- return this->get_span_for_write_only().typed<T>();
- }
-
- 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(const bool write_only);
- virtual void apply_span_if_necessary();
+ void save();
};
-using ReadAttributePtr = std::unique_ptr<ReadAttribute>;
-using WriteAttributePtr = std::unique_ptr<WriteAttribute>;
-
-/* This provides type safe access to an attribute.
- * The underlying ReadAttribute is owned optionally. */
-template<typename T> class TypedReadAttribute {
+/**
+ * Same as OutputAttribute, but should be used when the data type is known at compile time.
+ */
+template<typename T> class OutputAttribute_Typed {
private:
- std::unique_ptr<const ReadAttribute> owned_attribute_;
- const ReadAttribute *attribute_;
+ OutputAttribute attribute_;
+ std::optional<fn::GVMutableArray_Typed<T>> optional_varray_;
+ VMutableArray<T> *varray_ = nullptr;
public:
- TypedReadAttribute(ReadAttributePtr attribute) : TypedReadAttribute(*attribute)
+ OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute))
{
- owned_attribute_ = std::move(attribute);
- BLI_assert(owned_attribute_);
+ if (attribute_) {
+ optional_varray_.emplace(attribute_.varray());
+ varray_ = &**optional_varray_;
+ }
}
- TypedReadAttribute(const ReadAttribute &attribute) : attribute_(&attribute)
+ operator bool() const
{
- BLI_assert(attribute_->cpp_type().is<T>());
+ return varray_ != nullptr;
}
- int64_t size() const
+ VMutableArray<T> &operator*()
{
- return attribute_->size();
+ return *varray_;
}
- T operator[](const int64_t index) const
+ VMutableArray<T> *operator->()
{
- BLI_assert(index < attribute_->size());
- T value;
- value.~T();
- attribute_->get(index, &value);
- return value;
+ return varray_;
}
- /* Get a span to that contains all attribute values for faster and more convenient access. */
- Span<T> get_span() const
+ VMutableArray<T> &varray()
{
- return attribute_->get_span().template typed<T>();
+ return *varray_;
}
-};
-/* This provides type safe access to an attribute.
- * The underlying WriteAttribute is owned optionally. */
-template<typename T> class TypedWriteAttribute {
- private:
- std::unique_ptr<WriteAttribute> owned_attribute_;
- WriteAttribute *attribute_;
-
- public:
- TypedWriteAttribute(WriteAttributePtr attribute) : TypedWriteAttribute(*attribute)
- {
- owned_attribute_ = std::move(attribute);
- BLI_assert(owned_attribute_);
- }
-
- TypedWriteAttribute(WriteAttribute &attribute) : attribute_(&attribute)
- {
- BLI_assert(attribute_->cpp_type().is<T>());
- }
-
- int64_t size() const
+ AttributeDomain domain() const
{
- return attribute_->size();
+ return attribute_.domain();
}
- T operator[](const int64_t index) const
+ const CPPType &cpp_type() const
{
- BLI_assert(index < attribute_->size());
- T value;
- value.~T();
- attribute_->get(index, &value);
- return value;
+ return CPPType::get<T>();
}
- void set(const int64_t index, const T &value)
+ CustomDataType custom_data_type() const
{
- attribute_->set(index, &value);
+ return cpp_type_to_custom_data_type(this->cpp_type());
}
- /* Get a span that new values can be written into. Once all values have been updated #apply_span
- * has to be called. */
- MutableSpan<T> get_span()
+ MutableSpan<T> as_span()
{
- return attribute_->get_span().typed<T>();
- }
- /* The span returned by this method might not contain the current attribute values. */
- MutableSpan<T> get_span_for_write_only()
- {
- return attribute_->get_span_for_write_only().typed<T>();
+ return attribute_.as_span<T>();
}
- /* Write back all changes to the actual attribute, if necessary. */
- void apply_span()
+ void save()
{
- attribute_->apply_span();
+ attribute_.save();
}
};
-using BooleanReadAttribute = TypedReadAttribute<bool>;
-using FloatReadAttribute = TypedReadAttribute<float>;
-using Float2ReadAttribute = TypedReadAttribute<float2>;
-using Float3ReadAttribute = TypedReadAttribute<float3>;
-using Int32ReadAttribute = TypedReadAttribute<int>;
-using Color4fReadAttribute = TypedReadAttribute<Color4f>;
-using BooleanWriteAttribute = TypedWriteAttribute<bool>;
-using FloatWriteAttribute = TypedWriteAttribute<float>;
-using Float2WriteAttribute = TypedWriteAttribute<float2>;
-using Float3WriteAttribute = TypedWriteAttribute<float3>;
-using Int32WriteAttribute = TypedWriteAttribute<int>;
-using Color4fWriteAttribute = TypedWriteAttribute<Color4f>;
-
} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index 16fc0db60fb..65ac5b5bfa8 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -21,13 +21,17 @@
#include "DNA_customdata_types.h"
+#include "FN_cpp_type.hh"
+
namespace blender::attribute_math {
+using fn::CPPType;
+
/**
* Utility function that simplifies calling a templated function based on a custom data type.
*/
template<typename Func>
-void convert_to_static_type(const CustomDataType data_type, const Func &func)
+inline void convert_to_static_type(const CustomDataType data_type, const Func &func)
{
switch (data_type) {
case CD_PROP_FLOAT:
@@ -54,6 +58,32 @@ void convert_to_static_type(const CustomDataType data_type, const Func &func)
}
}
+template<typename Func>
+inline void convert_to_static_type(const fn::CPPType &cpp_type, const Func &func)
+{
+ if (cpp_type.is<float>()) {
+ func(float());
+ }
+ else if (cpp_type.is<float2>()) {
+ func(float2());
+ }
+ else if (cpp_type.is<float3>()) {
+ func(float3());
+ }
+ else if (cpp_type.is<int>()) {
+ func(int());
+ }
+ else if (cpp_type.is<bool>()) {
+ func(bool());
+ }
+ else if (cpp_type.is<Color4f>()) {
+ func(Color4f());
+ }
+ else {
+ BLI_assert_unreachable();
+ }
+}
+
/* -------------------------------------------------------------------- */
/** \name Mix three values of the same type.
*
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 08aea043fc7..61489aa7494 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -31,15 +31,15 @@ extern "C" {
*/
/* Blender major and minor version. */
-#define BLENDER_VERSION 293
+#define BLENDER_VERSION 300
/* Blender patch version for bugfix releases. */
#define BLENDER_VERSION_PATCH 0
/** Blender release cycle stage: alpha/beta/rc/release. */
-#define BLENDER_VERSION_CYCLE beta
+#define BLENDER_VERSION_CYCLE alpha
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 19
+#define BLENDER_FILE_SUBVERSION 0
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index 3d30188e517..50aa6027840 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -206,8 +206,25 @@ void CTX_wm_area_set(bContext *C, struct ScrArea *area);
void CTX_wm_region_set(bContext *C, struct ARegion *region);
void CTX_wm_menu_set(bContext *C, struct ARegion *menu);
void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup);
-const char *CTX_wm_operator_poll_msg_get(struct bContext *C);
+
+/**
+ * Values to create the message that describes the reason poll failed.
+ *
+ * \note This must be called in the same context as the poll function that created it.
+ */
+struct bContextPollMsgDyn_Params {
+ /** The result is allocated . */
+ char *(*get_fn)(bContext *C, void *user_data);
+ /** Optionally free the user-data. */
+ void (*free_fn)(bContext *C, void *user_data);
+ void *user_data;
+};
+
+const char *CTX_wm_operator_poll_msg_get(struct bContext *C, bool *r_free);
void CTX_wm_operator_poll_msg_set(struct bContext *C, const char *msg);
+void CTX_wm_operator_poll_msg_set_dynamic(bContext *C,
+ const struct bContextPollMsgDyn_Params *params);
+void CTX_wm_operator_poll_msg_clear(struct bContext *C);
/* Data Context
*
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index d94b2e7902b..38f692fee0e 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -56,60 +56,6 @@ class ComponentAttributeProviders;
class GeometryComponent;
/**
- * An #OutputAttributePtr wraps a #WriteAttributePtr that might not be stored in its final
- * destination yet. Therefore, once the attribute has been filled with data, the #save method has
- * to be called, to store the attribute where it belongs (possibly by replacing an existing
- * attribute with the same name).
- *
- * This is useful for example in the Attribute Color Ramp node, when the same attribute name is
- * used as input and output. Typically the input is a float attribute, and the output is a color.
- * Those two attributes cannot exist at the same time, due to a name collision. To handle this
- * situation well, first the output colors have to be computed before the input floats are deleted.
- * Therefore, the outputs have to be written to a temporary buffer that replaces the existing
- * attribute once all computations are done.
- */
-class OutputAttributePtr {
- private:
- blender::bke::WriteAttributePtr attribute_;
-
- public:
- OutputAttributePtr() = default;
- OutputAttributePtr(blender::bke::WriteAttributePtr attribute);
- OutputAttributePtr(GeometryComponent &component,
- AttributeDomain domain,
- std::string name,
- CustomDataType data_type);
-
- ~OutputAttributePtr();
-
- /* Returns false, when this wrapper is empty. */
- operator bool() const
- {
- return static_cast<bool>(attribute_);
- }
-
- /* Get a reference to the underlying #WriteAttribute. */
- blender::bke::WriteAttribute &get()
- {
- BLI_assert(attribute_);
- return *attribute_;
- }
-
- blender::bke::WriteAttribute &operator*()
- {
- return *attribute_;
- }
-
- blender::bke::WriteAttribute *operator->()
- {
- return attribute_.get();
- }
-
- void save();
- void apply_span_and_save();
-};
-
-/**
* Contains information about an attribute in a geometry component.
* More information can be added in the future. E.g. whether the attribute is builtin and how it is
* stored (uv map, vertex group, ...).
@@ -161,21 +107,25 @@ class GeometryComponent {
/* Can only be used with supported domain types. */
virtual int attribute_domain_size(const AttributeDomain domain) const;
+ bool attribute_is_builtin(const blender::StringRef attribute_name) const;
+
/* Get read-only access to the highest priority attribute with the given name.
* Returns null if the attribute does not exist. */
- blender::bke::ReadAttributePtr attribute_try_get_for_read(
+ blender::bke::ReadAttributeLookup attribute_try_get_for_read(
const blender::StringRef attribute_name) const;
/* Get read and write access to the highest priority attribute with the given name.
* Returns null if the attribute does not exist. */
- blender::bke::WriteAttributePtr attribute_try_get_for_write(
+ blender::bke::WriteAttributeLookup attribute_try_get_for_write(
const blender::StringRef attribute_name);
/* Get a read-only attribute for the domain based on the given attribute. This can be used to
* interpolate from one domain to another.
* Returns null if the interpolation is not implemented. */
- virtual blender::bke::ReadAttributePtr attribute_try_adapt_domain(
- blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const;
+ virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
+ std::unique_ptr<blender::fn::GVArray> varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const;
/* Returns true when the attribute has been deleted. */
bool attribute_try_delete(const blender::StringRef attribute_name);
@@ -185,80 +135,100 @@ class GeometryComponent {
const AttributeDomain domain,
const CustomDataType data_type);
+ /* Try to create the builtin attribute with the given name. No data type or domain has to be
+ * provided, because those are fixed for builtin attributes. */
+ bool attribute_try_create_builtin(const blender::StringRef attribute_name);
+
blender::Set<std::string> attribute_names() const;
bool attribute_foreach(const AttributeForeachCallback callback) const;
virtual bool is_empty() const;
- /* Get a read-only attribute for the given domain and data type.
- * Returns null when it does not exist. */
- blender::bke::ReadAttributePtr attribute_try_get_for_read(
+ /* Get a virtual array to read the data of an attribute on the given domain and data type.
+ * Returns null when the attribute does not exist or cannot be converted to the requested domain
+ * and data type. */
+ std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type) const;
- /* Get a read-only attribute interpolated to the input domain, leaving the data type unchanged.
- * Returns null when the attribute does not exist. */
- blender::bke::ReadAttributePtr attribute_try_get_for_read(
+ /* Get a virtual array to read the data of an attribute on the given domain. The data type is
+ * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the
+ * requested domain. */
+ std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read(
const blender::StringRef attribute_name, const AttributeDomain domain) const;
- /* Get a read-only attribute for the given domain and data type.
- * Returns a constant attribute based on the default value if the attribute does not exist.
- * Never returns null. */
- blender::bke::ReadAttributePtr attribute_get_for_read(const blender::StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value) const;
+ /* Get a virtual array to read data of an attribute with the given data type. The domain is
+ * left unchanged. Returns null when the attribute does not exist or cannot be converted to the
+ * requested data type. */
+ blender::bke::ReadAttributeLookup attribute_try_get_for_read(
+ const blender::StringRef attribute_name, const CustomDataType data_type) const;
- /* Get a typed read-only attribute for the given domain and type. */
- template<typename T>
- blender::bke::TypedReadAttribute<T> attribute_get_for_read(
+ /* Get a virtual array to read the data of an attribute. If that is not possible, the returned
+ * virtual array will contain a default value. This never returns null. */
+ std::unique_ptr<blender::fn::GVArray> attribute_get_for_read(
const blender::StringRef attribute_name,
const AttributeDomain domain,
- const T &default_value) const
+ const CustomDataType data_type,
+ const void *default_value = nullptr) const;
+
+ /* Should be used instead of the method above when the requested data type is known at compile
+ * time for better type safety. */
+ template<typename T>
+ blender::fn::GVArray_Typed<T> attribute_get_for_read(const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const T &default_value) const
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_get_for_read(attribute_name, domain, type, &default_value);
+ std::unique_ptr varray = this->attribute_get_for_read(
+ attribute_name, domain, type, &default_value);
+ return blender::fn::GVArray_Typed<T>(std::move(varray));
}
- /* Get a read-only dummy attribute that always returns the same value. */
- blender::bke::ReadAttributePtr attribute_get_constant_for_read(const AttributeDomain domain,
- const CustomDataType data_type,
- const void *value) const;
+ /**
+ * Returns an "output attribute", which is essentially a mutable virtual array with some commonly
+ * used convince features. The returned output attribute might be empty if requested attribute
+ * cannot exist on the geometry.
+ *
+ * The included convenience features are:
+ * - Implicit type conversion when writing to builtin attributes.
+ * - If the attribute name exists already, but has a different type/domain, a temporary attribute
+ * is created that will overwrite the existing attribute in the end.
+ */
+ blender::bke::OutputAttribute attribute_try_get_for_output(
+ const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const void *default_value = nullptr);
- /* Create a read-only dummy attribute that always returns the same value.
- * The given value is converted to the correct type if necessary. */
- blender::bke::ReadAttributePtr attribute_get_constant_for_read_converted(
+ /* Same as attribute_try_get_for_output, but should be used when the original values in the
+ * attributes are not read, i.e. the attribute is used only for output. Since values are not read
+ * from this attribute, no default value is necessary. */
+ blender::bke::OutputAttribute attribute_try_get_for_output_only(
+ const blender::StringRef attribute_name,
const AttributeDomain domain,
- const CustomDataType in_data_type,
- const CustomDataType out_data_type,
- const void *value) const;
+ const CustomDataType data_type);
- /* Get a read-only dummy attribute that always returns the same value. */
+ /* Statically typed method corresponding to the equally named generic one. */
template<typename T>
- blender::bke::TypedReadAttribute<T> attribute_get_constant_for_read(const AttributeDomain domain,
- const T &value) const
+ blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output(
+ const blender::StringRef attribute_name, const AttributeDomain domain, const T default_value)
{
const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
- const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
- return this->attribute_get_constant_for_read(domain, type, &value);
+ const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ return this->attribute_try_get_for_output(attribute_name, domain, data_type, &default_value);
}
- /**
- * If an attribute with the given params exist, it is returned.
- * If no attribute with the given name exists, create it and
- * fill it with the default value if it is provided.
- * If an attribute with the given name but different domain or type exists, a temporary attribute
- * is created that has to be saved after the output has been computed. This avoids deleting
- * another attribute, before a computation is finished.
- *
- * This might return no attribute when the attribute cannot exist on the component.
- */
- OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value = nullptr);
+ /* Statically typed method corresponding to the equally named generic one. */
+ template<typename T>
+ blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only(
+ const blender::StringRef attribute_name, const AttributeDomain domain)
+ {
+ const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>();
+ const CustomDataType data_type = blender::bke::cpp_type_to_custom_data_type(cpp_type);
+ return this->attribute_try_get_for_output_only(attribute_name, domain, data_type);
+ }
private:
virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const;
@@ -377,8 +347,10 @@ class MeshComponent : public GeometryComponent {
Mesh *get_for_write();
int attribute_domain_size(const AttributeDomain domain) const final;
- blender::bke::ReadAttributePtr attribute_try_adapt_domain(
- blender::bke::ReadAttributePtr attribute, const AttributeDomain new_domain) const final;
+ std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain(
+ std::unique_ptr<blender::fn::GVArray> varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const final;
bool is_empty() const final;
diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh
new file mode 100644
index 00000000000..f504650e349
--- /dev/null
+++ b/source/blender/blenkernel/BKE_mesh_sample.hh
@@ -0,0 +1,55 @@
+/*
+ * 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
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "FN_generic_virtual_array.hh"
+
+#include "BLI_float3.hh"
+
+#include "BKE_attribute.h"
+
+struct Mesh;
+
+namespace blender::bke::mesh_surface_sample {
+
+using fn::CPPType;
+using fn::GMutableSpan;
+using fn::GSpan;
+using fn::GVArray;
+
+void sample_point_attribute(const Mesh &mesh,
+ Span<int> looptri_indices,
+ Span<float3> bary_coords,
+ const GVArray &data_in,
+ GMutableSpan data_out);
+
+void sample_corner_attribute(const Mesh &mesh,
+ Span<int> looptri_indices,
+ Span<float3> bary_coords,
+ const GVArray &data_in,
+ GMutableSpan data_out);
+
+void sample_face_attribute(const Mesh &mesh,
+ Span<int> looptri_indices,
+ const GVArray &data_in,
+ GMutableSpan data_out);
+
+} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index d6c4ad037e2..2a33c4819e3 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1413,6 +1413,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_ATTRIBUTE_MAP_RANGE 1040
#define GEO_NODE_ATTRIBUTE_CLAMP 1041
#define GEO_NODE_BOUNDING_BOX 1042
+#define GEO_NODE_SWITCH 1043
/** \} */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 59e2c74ead1..adf321da8f0 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -190,6 +190,7 @@ set(SRC
intern/mesh_remap.c
intern/mesh_remesh_voxel.c
intern/mesh_runtime.c
+ intern/mesh_sample.cc
intern/mesh_tangent.c
intern/mesh_validate.c
intern/mesh_validate.cc
@@ -379,6 +380,7 @@ set(SRC
BKE_mesh_remap.h
BKE_mesh_remesh_voxel.h
BKE_mesh_runtime.h
+ BKE_mesh_sample.hh
BKE_mesh_tangent.h
BKE_mesh_types.h
BKE_mesh_wrapper.h
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 1075a46e72b..bcfd34ab42f 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -137,7 +137,7 @@ static char *blender_version_decimal(const int version)
{
static char version_str[5];
BLI_assert(version < 1000);
- BLI_snprintf(version_str, sizeof(version_str), "%d.%02d", version / 100, version % 100);
+ BLI_snprintf(version_str, sizeof(version_str), "%d.%d", version / 100, version % 100);
return version_str;
}
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index ac582fc30e7..3b2ee126d91 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -44,196 +44,10 @@ using blender::float3;
using blender::Set;
using blender::StringRef;
using blender::StringRefNull;
-using blender::bke::ReadAttributePtr;
-using blender::bke::WriteAttributePtr;
using blender::fn::GMutableSpan;
namespace blender::bke {
-/* -------------------------------------------------------------------- */
-/** \name Attribute Accessor implementations
- * \{ */
-
-ReadAttribute::~ReadAttribute()
-{
- if (array_is_temporary_ && array_buffer_ != nullptr) {
- cpp_type_.destruct_n(array_buffer_, size_);
- MEM_freeN(array_buffer_);
- }
-}
-
-fn::GSpan ReadAttribute::get_span() const
-{
- if (size_ == 0) {
- return fn::GSpan(cpp_type_);
- }
- if (array_buffer_ == nullptr) {
- std::lock_guard lock{span_mutex_};
- if (array_buffer_ == nullptr) {
- this->initialize_span();
- }
- }
- return fn::GSpan(cpp_type_, array_buffer_, size_);
-}
-
-void ReadAttribute::initialize_span() const
-{
- const int element_size = cpp_type_.size();
- array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
- array_is_temporary_ = true;
- for (const int i : IndexRange(size_)) {
- this->get_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
- }
-}
-
-WriteAttribute::~WriteAttribute()
-{
- if (array_should_be_applied_) {
- CLOG_ERROR(&LOG, "Forgot to call apply_span.");
- }
- if (array_is_temporary_ && array_buffer_ != nullptr) {
- cpp_type_.destruct_n(array_buffer_, size_);
- MEM_freeN(array_buffer_);
- }
-}
-
-/**
- * Get a mutable span that can be modified. When all modifications to the attribute are done,
- * #apply_span should be called. */
-fn::GMutableSpan WriteAttribute::get_span()
-{
- if (size_ == 0) {
- return fn::GMutableSpan(cpp_type_);
- }
- if (array_buffer_ == nullptr) {
- this->initialize_span(false);
- }
- array_should_be_applied_ = true;
- return fn::GMutableSpan(cpp_type_, array_buffer_, size_);
-}
-
-fn::GMutableSpan WriteAttribute::get_span_for_write_only()
-{
- if (size_ == 0) {
- return fn::GMutableSpan(cpp_type_);
- }
- if (array_buffer_ == nullptr) {
- this->initialize_span(true);
- }
- array_should_be_applied_ = true;
- return fn::GMutableSpan(cpp_type_, array_buffer_, size_);
-}
-
-void WriteAttribute::initialize_span(const bool write_only)
-{
- const int element_size = cpp_type_.size();
- array_buffer_ = MEM_mallocN_aligned(element_size * size_, cpp_type_.alignment(), __func__);
- array_is_temporary_ = true;
- if (write_only) {
- /* This does nothing for trivial types, but is necessary for general correctness. */
- cpp_type_.construct_default_n(array_buffer_, size_);
- }
- else {
- for (const int i : IndexRange(size_)) {
- this->get(i, POINTER_OFFSET(array_buffer_, i * element_size));
- }
- }
-}
-
-void WriteAttribute::apply_span()
-{
- this->apply_span_if_necessary();
- array_should_be_applied_ = false;
-}
-
-void WriteAttribute::apply_span_if_necessary()
-{
- /* Only works when the span has been initialized beforehand. */
- BLI_assert(array_buffer_ != nullptr);
-
- const int element_size = cpp_type_.size();
- for (const int i : IndexRange(size_)) {
- this->set_internal(i, POINTER_OFFSET(array_buffer_, i * element_size));
- }
-}
-
-/* This is used by the #OutputAttributePtr class. */
-class TemporaryWriteAttribute final : public WriteAttribute {
- public:
- GMutableSpan data;
- GeometryComponent &component;
- std::string final_name;
-
- TemporaryWriteAttribute(AttributeDomain domain,
- GMutableSpan data,
- GeometryComponent &component,
- std::string final_name)
- : WriteAttribute(domain, data.type(), data.size()),
- data(data),
- component(component),
- final_name(std::move(final_name))
- {
- }
-
- ~TemporaryWriteAttribute() override
- {
- if (data.data() != nullptr) {
- cpp_type_.destruct_n(data.data(), data.size());
- MEM_freeN(data.data());
- }
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- data.type().copy_to_uninitialized(data[index], r_value);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- data.type().copy_to_initialized(value, data[index]);
- }
-
- void initialize_span(const bool UNUSED(write_only)) override
- {
- array_buffer_ = data.data();
- array_is_temporary_ = false;
- }
-
- void apply_span_if_necessary() override
- {
- /* Do nothing, because the span contains the attribute itself already. */
- }
-};
-
-class ConvertedReadAttribute final : public ReadAttribute {
- private:
- const CPPType &from_type_;
- const CPPType &to_type_;
- ReadAttributePtr base_attribute_;
- void (*convert_)(const void *src, void *dst);
-
- public:
- ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type)
- : ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()),
- from_type_(base_attribute->cpp_type()),
- to_type_(to_type),
- base_attribute_(std::move(base_attribute))
- {
- const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
- convert_ = conversions.get_conversion_functions(base_attribute_->cpp_type(), to_type)
- ->convert_single_to_uninitialized;
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
- base_attribute_->get(index, buffer);
- convert_(buffer, r_value);
- }
-};
-
-/** \} */
-
const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType type)
{
switch (type) {
@@ -368,7 +182,17 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains)
return highest_priority_domain;
}
-ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read(
+void OutputAttribute::save()
+{
+ if (optional_span_varray_.has_value()) {
+ optional_span_varray_->save();
+ }
+ if (save_) {
+ save_(*this);
+ }
+}
+
+GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read(
const GeometryComponent &component) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
@@ -384,7 +208,7 @@ ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read(
return as_read_attribute_(data, domain_size);
}
-WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write(
+GVMutableArrayPtr BuiltinCustomDataLayerProvider::try_get_for_write(
GeometryComponent &component) const
{
if (writable_ != Writable) {
@@ -463,7 +287,7 @@ bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component)
return data != nullptr;
}
-ReadAttributePtr CustomDataAttributeProvider::try_get_for_read(
+ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read(
const GeometryComponent &component, const StringRef attribute_name) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
@@ -496,7 +320,7 @@ ReadAttributePtr CustomDataAttributeProvider::try_get_for_read(
return {};
}
-WriteAttributePtr CustomDataAttributeProvider::try_get_for_write(
+WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write(
GeometryComponent &component, const StringRef attribute_name) const
{
CustomData *custom_data = custom_data_access_.get_custom_data(component);
@@ -595,7 +419,7 @@ bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &com
return true;
}
-ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read(
+ReadAttributeLookup NamedLegacyCustomDataProvider::try_get_for_read(
const GeometryComponent &component, const StringRef attribute_name) const
{
const CustomData *custom_data = custom_data_access_.get_const_custom_data(component);
@@ -606,14 +430,14 @@ ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read(
if (layer.type == stored_type_) {
if (layer.name == attribute_name) {
const int domain_size = component.attribute_domain_size(domain_);
- return as_read_attribute_(layer.data, domain_size);
+ return {as_read_attribute_(layer.data, domain_size), domain_};
}
}
}
return {};
}
-WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write(
+WriteAttributeLookup NamedLegacyCustomDataProvider::try_get_for_write(
GeometryComponent &component, const StringRef attribute_name) const
{
CustomData *custom_data = custom_data_access_.get_custom_data(component);
@@ -630,7 +454,7 @@ WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write(
if (data_old != data_new) {
custom_data_access_.update_custom_data_pointers(component);
}
- return as_write_attribute_(layer.data, domain_size);
+ return {as_write_attribute_(layer.data, domain_size), domain_};
}
}
}
@@ -708,7 +532,17 @@ int GeometryComponent::attribute_domain_size(const AttributeDomain UNUSED(domain
return 0;
}
-ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
+bool GeometryComponent::attribute_is_builtin(const blender::StringRef attribute_name) const
+{
+ using namespace blender::bke;
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return false;
+ }
+ return providers->builtin_attribute_providers().contains_as(attribute_name);
+}
+
+blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
const StringRef attribute_name) const
{
using namespace blender::bke;
@@ -719,11 +553,11 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
const BuiltinAttributeProvider *builtin_provider =
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
if (builtin_provider != nullptr) {
- return builtin_provider->try_get_for_read(*this);
+ return {builtin_provider->try_get_for_read(*this), builtin_provider->domain()};
}
for (const DynamicAttributesProvider *dynamic_provider :
providers->dynamic_attribute_providers()) {
- ReadAttributePtr attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
+ ReadAttributeLookup attribute = dynamic_provider->try_get_for_read(*this, attribute_name);
if (attribute) {
return attribute;
}
@@ -731,16 +565,19 @@ ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
return {};
}
-ReadAttributePtr GeometryComponent::attribute_try_adapt_domain(
- ReadAttributePtr attribute, const AttributeDomain new_domain) const
+std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain(
+ std::unique_ptr<blender::fn::GVArray> varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
{
- if (attribute && attribute->domain() == new_domain) {
- return attribute;
+ if (from_domain == to_domain) {
+ return varray;
}
return {};
}
-WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef attribute_name)
+blender::bke::WriteAttributeLookup GeometryComponent::attribute_try_get_for_write(
+ const StringRef attribute_name)
{
using namespace blender::bke;
const ComponentAttributeProviders *providers = this->get_attribute_providers();
@@ -750,11 +587,11 @@ WriteAttributePtr GeometryComponent::attribute_try_get_for_write(const StringRef
const BuiltinAttributeProvider *builtin_provider =
providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
if (builtin_provider != nullptr) {
- return builtin_provider->try_get_for_write(*this);
+ return {builtin_provider->try_get_for_write(*this), builtin_provider->domain()};
}
for (const DynamicAttributesProvider *dynamic_provider :
providers->dynamic_attribute_providers()) {
- WriteAttributePtr attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
+ WriteAttributeLookup attribute = dynamic_provider->try_get_for_write(*this, attribute_name);
if (attribute) {
return attribute;
}
@@ -814,6 +651,24 @@ bool GeometryComponent::attribute_try_create(const StringRef attribute_name,
return false;
}
+bool GeometryComponent::attribute_try_create_builtin(const blender::StringRef attribute_name)
+{
+ using namespace blender::bke;
+ if (attribute_name.is_empty()) {
+ return false;
+ }
+ const ComponentAttributeProviders *providers = this->get_attribute_providers();
+ if (providers == nullptr) {
+ return false;
+ }
+ const BuiltinAttributeProvider *builtin_provider =
+ providers->builtin_attribute_providers().lookup_default_as(attribute_name, nullptr);
+ if (builtin_provider == nullptr) {
+ return false;
+ }
+ return builtin_provider->try_create(*this);
+}
+
Set<std::string> GeometryComponent::attribute_names() const
{
Set<std::string> attributes;
@@ -867,264 +722,251 @@ bool GeometryComponent::attribute_foreach(const AttributeForeachCallback callbac
bool GeometryComponent::attribute_exists(const blender::StringRef attribute_name) const
{
- ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
+ blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
if (attribute) {
return true;
}
return false;
}
-static ReadAttributePtr try_adapt_data_type(ReadAttributePtr attribute,
- const blender::fn::CPPType &to_type)
+static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type(
+ std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type)
{
- const blender::fn::CPPType &from_type = attribute->cpp_type();
- if (from_type == to_type) {
- return attribute;
- }
-
const blender::nodes::DataTypeConversions &conversions =
blender::nodes::get_implicit_type_conversions();
- if (!conversions.is_convertible(from_type, to_type)) {
- return {};
- }
-
- return std::make_unique<blender::bke::ConvertedReadAttribute>(std::move(attribute), to_type);
+ return conversions.try_convert(std::move(varray), to_type);
}
-ReadAttributePtr GeometryComponent::attribute_try_get_for_read(
+std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read(
const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type) const
{
- ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
+ blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
if (!attribute) {
return {};
}
- if (domain != ATTR_DOMAIN_AUTO && attribute->domain() != domain) {
- attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
- if (!attribute) {
+ std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray);
+ if (domain != ATTR_DOMAIN_AUTO && attribute.domain != domain) {
+ varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain);
+ if (!varray) {
return {};
}
}
const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
- if (attribute->cpp_type() != *cpp_type) {
- attribute = try_adapt_data_type(std::move(attribute), *cpp_type);
- if (!attribute) {
+ if (varray->type() != *cpp_type) {
+ varray = try_adapt_data_type(std::move(varray), *cpp_type);
+ if (!varray) {
return {};
}
}
- return attribute;
+ return varray;
}
-ReadAttributePtr GeometryComponent::attribute_try_get_for_read(const StringRef attribute_name,
- const AttributeDomain domain) const
+std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read(
+ const StringRef attribute_name, const AttributeDomain domain) const
{
if (!this->attribute_domain_supported(domain)) {
return {};
}
- ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name);
+ blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
if (!attribute) {
return {};
}
- if (attribute->domain() != domain) {
- attribute = this->attribute_try_adapt_domain(std::move(attribute), domain);
- if (!attribute) {
- return {};
- }
+ if (attribute.domain != domain) {
+ return this->attribute_try_adapt_domain(std::move(attribute.varray), attribute.domain, domain);
}
- return attribute;
+ return std::move(attribute.varray);
}
-ReadAttributePtr GeometryComponent::attribute_get_for_read(const StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value) const
+blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read(
+ const blender::StringRef attribute_name, const CustomDataType data_type) const
{
- ReadAttributePtr attribute = this->attribute_try_get_for_read(attribute_name, domain, data_type);
- if (attribute) {
- return attribute;
+ blender::bke::ReadAttributeLookup attribute = this->attribute_try_get_for_read(attribute_name);
+ if (!attribute) {
+ return {};
}
- return this->attribute_get_constant_for_read(domain, data_type, default_value);
-}
-
-blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read(
- const AttributeDomain domain, const CustomDataType data_type, const void *value) const
-{
- BLI_assert(this->attribute_domain_supported(domain));
- const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
- if (value == nullptr) {
- value = cpp_type->default_value();
+ const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ BLI_assert(type != nullptr);
+ if (attribute.varray->type() == *type) {
+ return attribute;
}
- const int domain_size = this->attribute_domain_size(domain);
- return std::make_unique<blender::bke::ConstantReadAttribute>(
- domain, domain_size, *cpp_type, value);
+ const blender::nodes::DataTypeConversions &conversions =
+ blender::nodes::get_implicit_type_conversions();
+ return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain};
}
-blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_read_converted(
+std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read(
+ const StringRef attribute_name,
const AttributeDomain domain,
- const CustomDataType in_data_type,
- const CustomDataType out_data_type,
- const void *value) const
+ const CustomDataType data_type,
+ const void *default_value) const
{
- BLI_assert(this->attribute_domain_supported(domain));
- if (value == nullptr || in_data_type == out_data_type) {
- return this->attribute_get_constant_for_read(domain, out_data_type, value);
+ std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read(
+ attribute_name, domain, data_type);
+ if (varray) {
+ return varray;
+ }
+ const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type);
+ if (default_value == nullptr) {
+ default_value = type->default_value();
}
-
- const blender::fn::CPPType *in_cpp_type = blender::bke::custom_data_type_to_cpp_type(
- in_data_type);
- const blender::fn::CPPType *out_cpp_type = blender::bke::custom_data_type_to_cpp_type(
- out_data_type);
- BLI_assert(in_cpp_type != nullptr);
- BLI_assert(out_cpp_type != nullptr);
-
- const blender::nodes::DataTypeConversions &conversions =
- blender::nodes::get_implicit_type_conversions();
- BLI_assert(conversions.is_convertible(*in_cpp_type, *out_cpp_type));
-
- void *out_value = alloca(out_cpp_type->size());
- conversions.convert_to_uninitialized(*in_cpp_type, *out_cpp_type, value, out_value);
-
const int domain_size = this->attribute_domain_size(domain);
- blender::bke::ReadAttributePtr attribute = std::make_unique<blender::bke::ConstantReadAttribute>(
- domain, domain_size, *out_cpp_type, out_value);
-
- out_cpp_type->destruct(out_value);
- return attribute;
+ return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value);
}
-OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringRef attribute_name,
- const AttributeDomain domain,
- const CustomDataType data_type,
- const void *default_value)
-{
- const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
-
- WriteAttributePtr attribute = this->attribute_try_get_for_write(attribute_name);
+class GVMutableAttribute_For_OutputAttribute
+ : public blender::fn::GVMutableArray_For_GMutableSpan {
+ public:
+ GeometryComponent *component;
+ std::string final_name;
- /* If the attribute doesn't exist, make a new one with the correct type. */
- if (!attribute) {
- this->attribute_try_create(attribute_name, domain, data_type);
- attribute = this->attribute_try_get_for_write(attribute_name);
- if (attribute && default_value != nullptr) {
- void *data = attribute->get_span_for_write_only().data();
- cpp_type->fill_initialized(default_value, data, attribute->size());
- attribute->apply_span();
- }
- return OutputAttributePtr(std::move(attribute));
+ GVMutableAttribute_For_OutputAttribute(GMutableSpan data,
+ GeometryComponent &component,
+ std::string final_name)
+ : blender::fn::GVMutableArray_For_GMutableSpan(data),
+ component(&component),
+ final_name(std::move(final_name))
+ {
}
- /* If an existing attribute has a matching domain and type, just use that. */
- if (attribute->domain() == domain && attribute->cpp_type() == *cpp_type) {
- return OutputAttributePtr(std::move(attribute));
+ ~GVMutableAttribute_For_OutputAttribute() override
+ {
+ type_->destruct_n(data_, size_);
+ MEM_freeN(data_);
}
+};
- /* Otherwise create a temporary buffer to use before saving the new attribute. */
- return OutputAttributePtr(*this, domain, attribute_name, data_type);
-}
-
-/* Construct from an attribute that already exists in the geometry component. */
-OutputAttributePtr::OutputAttributePtr(WriteAttributePtr attribute)
- : attribute_(std::move(attribute))
+static void save_output_attribute(blender::bke::OutputAttribute &output_attribute)
{
-}
+ using namespace blender;
+ using namespace blender::fn;
+ using namespace blender::bke;
-/* Construct a temporary attribute that has to replace an existing one later on. */
-OutputAttributePtr::OutputAttributePtr(GeometryComponent &component,
- AttributeDomain domain,
- std::string final_name,
- CustomDataType data_type)
-{
- const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type);
- BLI_assert(cpp_type != nullptr);
+ GVMutableAttribute_For_OutputAttribute &varray =
+ dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray());
- const int domain_size = component.attribute_domain_size(domain);
- void *buffer = MEM_malloc_arrayN(domain_size, cpp_type->size(), __func__);
- GMutableSpan new_span{*cpp_type, buffer, domain_size};
+ GeometryComponent &component = *varray.component;
+ const StringRefNull name = varray.final_name;
+ const AttributeDomain domain = output_attribute.domain();
+ const CustomDataType data_type = output_attribute.custom_data_type();
+ const CPPType &cpp_type = output_attribute.cpp_type();
- /* Copy converted values from conflicting attribute, in case the value is read.
- * TODO: An optimization could be to not do this, when the caller says that the attribute will
- * only be written. */
- ReadAttributePtr src_attribute = component.attribute_get_for_read(
- final_name, domain, data_type, nullptr);
- for (const int i : blender::IndexRange(domain_size)) {
- src_attribute->get(i, new_span[i]);
+ component.attribute_try_delete(name);
+ if (!component.attribute_try_create(varray.final_name, domain, data_type)) {
+ CLOG_WARN(&LOG,
+ "Could not create the '%s' attribute with type '%s'.",
+ name.c_str(),
+ cpp_type.name().c_str());
+ return;
+ }
+ WriteAttributeLookup write_attribute = component.attribute_try_get_for_write(name);
+ BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer);
+ for (const int i : IndexRange(varray.size())) {
+ varray.get(i, buffer);
+ write_attribute.varray->set_by_relocate(i, buffer);
}
-
- attribute_ = std::make_unique<blender::bke::TemporaryWriteAttribute>(
- domain, new_span, component, std::move(final_name));
}
-/* Store the computed attribute. If it was stored from the beginning already, nothing is done. This
- * might delete another attribute with the same name. */
-void OutputAttributePtr::save()
+static blender::bke::OutputAttribute create_output_attribute(
+ GeometryComponent &component,
+ const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const bool ignore_old_values,
+ const void *default_value)
{
- if (!attribute_) {
- CLOG_WARN(&LOG, "Trying to save an attribute that does not exist anymore.");
- return;
- }
-
- blender::bke::TemporaryWriteAttribute *attribute =
- dynamic_cast<blender::bke::TemporaryWriteAttribute *>(attribute_.get());
+ using namespace blender;
+ using namespace blender::fn;
+ using namespace blender::bke;
- if (attribute == nullptr) {
- /* The attribute is saved already. */
- attribute_.reset();
- return;
+ if (attribute_name.is_empty()) {
+ return {};
}
- StringRefNull name = attribute->final_name;
- const blender::fn::CPPType &cpp_type = attribute->cpp_type();
-
- /* Delete an existing attribute with the same name if necessary. */
- attribute->component.attribute_try_delete(name);
+ const CPPType *cpp_type = custom_data_type_to_cpp_type(data_type);
+ BLI_assert(cpp_type != nullptr);
+ const nodes::DataTypeConversions &conversions = nodes::get_implicit_type_conversions();
- if (!attribute->component.attribute_try_create(
- name, attribute_->domain(), attribute_->custom_data_type())) {
- /* Cannot create the target attribute for some reason. */
- CLOG_WARN(&LOG,
- "Creating the '%s' attribute with type '%s' failed.",
- name.c_str(),
- cpp_type.name().c_str());
- attribute_.reset();
- return;
+ if (component.attribute_is_builtin(attribute_name)) {
+ WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
+ if (!attribute) {
+ component.attribute_try_create_builtin(attribute_name);
+ attribute = component.attribute_try_get_for_write(attribute_name);
+ if (!attribute) {
+ /* Builtin attribute does not exist and can't be created. */
+ return {};
+ }
+ }
+ if (attribute.domain != domain) {
+ /* Builtin attribute is on different domain. */
+ return {};
+ }
+ GVMutableArrayPtr varray = std::move(attribute.varray);
+ if (varray->type() == *cpp_type) {
+ /* Builtin attribute matches exactly. */
+ return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
+ }
+ /* Builtin attribute is on the same domain but has a different data type. */
+ varray = conversions.try_convert(std::move(varray), *cpp_type);
+ return OutputAttribute(std::move(varray), domain, {}, ignore_old_values);
}
- WriteAttributePtr new_attribute = attribute->component.attribute_try_get_for_write(name);
-
- GMutableSpan temp_span = attribute->data;
- GMutableSpan new_span = new_attribute->get_span_for_write_only();
- BLI_assert(temp_span.size() == new_span.size());
+ WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_name);
+ if (!attribute) {
+ component.attribute_try_create(attribute_name, domain, data_type);
+ attribute = component.attribute_try_get_for_write(attribute_name);
+ if (!attribute) {
+ /* Can't create the attribute. */
+ return {};
+ }
+ }
+ if (attribute.domain == domain && attribute.varray->type() == *cpp_type) {
+ /* Existing generic attribute matches exactly. */
+ return OutputAttribute(std::move(attribute.varray), domain, {}, ignore_old_values);
+ }
- /* Currently we copy over the attribute. In the future we want to reuse the buffer. */
- cpp_type.move_to_initialized_n(temp_span.data(), new_span.data(), new_span.size());
- new_attribute->apply_span();
+ const int domain_size = component.attribute_domain_size(domain);
+ /* Allocate a new array that lives next to the existing attribute. It will overwrite the existing
+ * attribute after processing is done. */
+ void *data = MEM_mallocN_aligned(
+ cpp_type->size() * domain_size, cpp_type->alignment(), __func__);
+ if (ignore_old_values) {
+ /* This does nothing for trivially constructible types, but is necessary for correctness. */
+ cpp_type->construct_default_n(data, domain);
+ }
+ else {
+ /* Fill the temporary array with values from the existing attribute. */
+ GVArrayPtr old_varray = component.attribute_get_for_read(
+ attribute_name, domain, data_type, default_value);
+ old_varray->materialize_to_uninitialized(IndexRange(domain_size), data);
+ }
+ GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>(
+ GMutableSpan{*cpp_type, data, domain_size}, component, attribute_name);
- attribute_.reset();
+ return OutputAttribute(std::move(varray), domain, save_output_attribute, true);
}
-OutputAttributePtr::~OutputAttributePtr()
+blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output(
+ const StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type,
+ const void *default_value)
{
- if (attribute_) {
- CLOG_ERROR(&LOG, "Forgot to call #save or #apply_span_and_save.");
- }
+ return create_output_attribute(*this, attribute_name, domain, data_type, false, default_value);
}
-/* Utility function to call #apply_span and #save in the right order. */
-void OutputAttributePtr::apply_span_and_save()
+blender::bke::OutputAttribute GeometryComponent::attribute_try_get_for_output_only(
+ const blender::StringRef attribute_name,
+ const AttributeDomain domain,
+ const CustomDataType data_type)
{
- BLI_assert(attribute_);
- attribute_->apply_span();
- this->save();
+ return create_output_attribute(*this, attribute_name, domain, data_type, true, nullptr);
}
-
-/** \} */
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index 806d10e9e89..7cf585dfbfc 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -24,166 +24,8 @@
namespace blender::bke {
-class ConstantReadAttribute final : public ReadAttribute {
- private:
- void *value_;
-
- public:
- ConstantReadAttribute(AttributeDomain domain,
- const int64_t size,
- const CPPType &type,
- const void *value)
- : ReadAttribute(domain, type, size)
- {
- value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
- type.copy_to_uninitialized(value, value_);
- }
-
- ~ConstantReadAttribute() override
- {
- this->cpp_type_.destruct(value_);
- MEM_freeN(value_);
- }
-
- void get_internal(const int64_t UNUSED(index), void *r_value) const override
- {
- this->cpp_type_.copy_to_uninitialized(value_, r_value);
- }
-
- void initialize_span() const override
- {
- const int element_size = cpp_type_.size();
- array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__);
- array_is_temporary_ = true;
- cpp_type_.fill_uninitialized(value_, array_buffer_, size_);
- }
-};
-
-template<typename T> class ArrayReadAttribute final : public ReadAttribute {
- private:
- Span<T> data_;
-
- public:
- ArrayReadAttribute(AttributeDomain domain, Span<T> data)
- : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void initialize_span() const override
- {
- /* The data will not be modified, so this const_cast is fine. */
- array_buffer_ = const_cast<T *>(data_.data());
- array_is_temporary_ = false;
- }
-};
-
-template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute {
- private:
- Array<T> data_;
-
- public:
- OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data)
- : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data))
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void initialize_span() const override
- {
- /* The data will not be modified, so this const_cast is fine. */
- array_buffer_ = const_cast<T *>(data_.data());
- array_is_temporary_ = false;
- }
-};
-
-template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
-class DerivedArrayReadAttribute final : public ReadAttribute {
- private:
- Span<StructT> data_;
-
- public:
- DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data)
- : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- const StructT &struct_value = data_[index];
- const ElemT value = GetFunc(struct_value);
- new (r_value) ElemT(value);
- }
-};
-
-template<typename T> class ArrayWriteAttribute final : public WriteAttribute {
- private:
- MutableSpan<T> data_;
-
- public:
- ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data)
- : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- new (r_value) T(data_[index]);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- data_[index] = *reinterpret_cast<const T *>(value);
- }
-
- void initialize_span(const bool UNUSED(write_only)) override
- {
- array_buffer_ = data_.data();
- array_is_temporary_ = false;
- }
-
- void apply_span_if_necessary() override
- {
- /* Do nothing, because the span contains the attribute itself already. */
- }
-};
-
-template<typename StructT,
- typename ElemT,
- ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, const ElemT &)>
-class DerivedArrayWriteAttribute final : public WriteAttribute {
- private:
- MutableSpan<StructT> data_;
-
- public:
- DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data)
- : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data)
- {
- }
-
- void get_internal(const int64_t index, void *r_value) const override
- {
- const StructT &struct_value = data_[index];
- const ElemT value = GetFunc(struct_value);
- new (r_value) ElemT(value);
- }
-
- void set_internal(const int64_t index, const void *value) override
- {
- StructT &struct_value = data_[index];
- const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value);
- SetFunc(struct_value, typed_value);
- }
-};
+using fn::GVArrayPtr;
+using fn::GVMutableArrayPtr;
/**
* Utility to group together multiple functions that are used to access custom data on geometry
@@ -244,8 +86,8 @@ class BuiltinAttributeProvider {
{
}
- virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0;
- virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0;
+ virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0;
+ virtual GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const = 0;
virtual bool try_delete(GeometryComponent &component) const = 0;
virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0;
virtual bool exists(const GeometryComponent &component) const = 0;
@@ -272,10 +114,10 @@ class BuiltinAttributeProvider {
*/
class DynamicAttributesProvider {
public:
- virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const = 0;
- virtual WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const = 0;
+ virtual ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const = 0;
+ virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const = 0;
virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0;
virtual bool try_create(GeometryComponent &UNUSED(component),
const StringRef UNUSED(attribute_name),
@@ -309,11 +151,11 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
{
}
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final;
+ ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final;
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final;
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final;
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
@@ -332,18 +174,21 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
private:
template<typename T>
- ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer,
- const int domain_size) const
+ ReadAttributeLookup layer_to_read_attribute(const CustomDataLayer &layer,
+ const int domain_size) const
{
- return std::make_unique<ArrayReadAttribute<T>>(
- domain_, Span(static_cast<const T *>(layer.data), domain_size));
+ return {std::make_unique<fn::GVArray_For_Span<T>>(
+ Span(static_cast<const T *>(layer.data), domain_size)),
+ domain_};
}
template<typename T>
- WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const
+ WriteAttributeLookup layer_to_write_attribute(CustomDataLayer &layer,
+ const int domain_size) const
{
- return std::make_unique<ArrayWriteAttribute<T>>(
- domain_, MutableSpan(static_cast<T *>(layer.data), domain_size));
+ return {std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
+ MutableSpan(static_cast<T *>(layer.data), domain_size)),
+ domain_};
}
bool type_is_supported(CustomDataType data_type) const
@@ -357,8 +202,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider {
*/
class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
private:
- using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
+ using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size);
+ using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size);
const AttributeDomain domain_;
const CustomDataType attribute_type_;
const CustomDataType stored_type_;
@@ -382,10 +227,10 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
{
}
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final;
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final;
+ ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final;
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final;
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final;
bool foreach_attribute(const GeometryComponent &component,
const AttributeForeachCallback callback) const final;
@@ -398,8 +243,8 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
* the #MVert struct, but is exposed as float3 attribute.
*/
class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size);
- using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size);
+ using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size);
+ using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size);
using UpdateOnRead = void (*)(const GeometryComponent &component);
using UpdateOnWrite = void (*)(GeometryComponent &component);
const CustomDataType stored_type_;
@@ -430,8 +275,8 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
{
}
- ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final;
- WriteAttributePtr try_get_for_write(GeometryComponent &component) const final;
+ GVArrayPtr try_get_for_read(const GeometryComponent &component) const final;
+ GVMutableArrayPtr try_get_for_write(GeometryComponent &component) const final;
bool try_delete(GeometryComponent &component) const final;
bool try_create(GeometryComponent &component) const final;
bool exists(const GeometryComponent &component) const final;
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index e8879cdda8f..e84b485c466 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -132,7 +132,7 @@ static void blender_version_init(void)
BLI_snprintf(blender_version_string,
ARRAY_SIZE(blender_version_string),
- "%d.%02d.%d%s",
+ "%d.%01d.%d%s",
BLENDER_VERSION / 100,
BLENDER_VERSION % 100,
BLENDER_VERSION_PATCH,
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index cbf7a4483c0..81830f5bb61 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -80,7 +80,17 @@ struct bContext {
struct ARegion *menu;
struct wmGizmoGroup *gizmo_group;
struct bContextStore *store;
- const char *operator_poll_msg; /* reason for poll failing */
+
+ /* Operator poll. */
+ /**
+ * Store the reason the poll function fails (static string, not allocated).
+ * For more advanced formatting use `operator_poll_msg_dyn_params`.
+ */
+ const char *operator_poll_msg;
+ /**
+ * Store values to dynamically to create the string (called when a tool-tip is shown).
+ */
+ struct bContextPollMsgDyn_Params operator_poll_msg_dyn_params;
} wm;
/* data context */
@@ -113,11 +123,16 @@ bContext *CTX_copy(const bContext *C)
{
bContext *newC = MEM_dupallocN((void *)C);
+ memset(&newC->wm.operator_poll_msg_dyn_params, 0, sizeof(newC->wm.operator_poll_msg_dyn_params));
+
return newC;
}
void CTX_free(bContext *C)
{
+ /* This may contain a dynamically allocated message, free. */
+ CTX_wm_operator_poll_msg_clear(C);
+
MEM_freeN(C);
}
@@ -1003,13 +1018,45 @@ void CTX_wm_gizmo_group_set(bContext *C, struct wmGizmoGroup *gzgroup)
C->wm.gizmo_group = gzgroup;
}
+void CTX_wm_operator_poll_msg_clear(bContext *C)
+{
+ struct bContextPollMsgDyn_Params *params = &C->wm.operator_poll_msg_dyn_params;
+ if (params->free_fn != NULL) {
+ params->free_fn(C, params->user_data);
+ }
+ params->get_fn = NULL;
+ params->free_fn = NULL;
+ params->user_data = NULL;
+
+ C->wm.operator_poll_msg = NULL;
+}
void CTX_wm_operator_poll_msg_set(bContext *C, const char *msg)
{
+ CTX_wm_operator_poll_msg_clear(C);
+
C->wm.operator_poll_msg = msg;
}
-const char *CTX_wm_operator_poll_msg_get(bContext *C)
+void CTX_wm_operator_poll_msg_set_dynamic(bContext *C,
+ const struct bContextPollMsgDyn_Params *params)
{
+ CTX_wm_operator_poll_msg_clear(C);
+
+ C->wm.operator_poll_msg_dyn_params = *params;
+}
+
+const char *CTX_wm_operator_poll_msg_get(bContext *C, bool *r_free)
+{
+ struct bContextPollMsgDyn_Params *params = &C->wm.operator_poll_msg_dyn_params;
+ if (params->get_fn != NULL) {
+ char *msg = params->get_fn(C, params->user_data);
+ if (msg != NULL) {
+ *r_free = true;
+ }
+ return msg;
+ }
+
+ *r_free = false;
return IFACE_(C->wm.operator_poll_msg);
}
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 150cc4589c8..e5accd98952 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -32,7 +32,7 @@
/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
-using blender::bke::ReadAttributePtr;
+using blender::fn::GVArray;
/* -------------------------------------------------------------------- */
/** \name Geometry Component Implementation
@@ -201,14 +201,14 @@ namespace blender::bke {
template<typename T>
static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
- const TypedReadAttribute<T> &attribute,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
attribute_math::DefaultMixer<T> mixer(r_values);
for (const int loop_index : IndexRange(mesh.totloop)) {
- const T value = attribute[loop_index];
+ const T value = old_values[loop_index];
const MLoop &loop = mesh.mloop[loop_index];
const int point_index = loop.v;
mixer.mix_in(point_index, value);
@@ -216,43 +216,40 @@ static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
/* We compute all interpolated values at once, because for this interpolation, one has to
* iterate over all loops anyway. */
Array<T> values(mesh.totvert);
- adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh,
- const TypedReadAttribute<T> &attribute,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
for (const int loop_index : IndexRange(mesh.totloop)) {
const int vertex_index = mesh.mloop[loop_index].v;
- r_values[loop_index] = attribute[vertex_index];
+ r_values[loop_index] = old_values[vertex_index];
}
}
-static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
/* It is not strictly necessary to compute the value for all corners here. Instead one could
@@ -260,11 +257,10 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
* when an algorithm only accesses very few of the corner values. However, for the algorithms
* we currently have, precomputing the array is fine. Also, it is easier to implement. */
Array<T> values(mesh.totloop);
- adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER,
- std::move(values));
+ adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
});
- return new_attribute;
+ return new_varray;
}
/**
@@ -274,7 +270,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
- Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
@@ -291,26 +287,24 @@ static void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_corner_to_face(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
- adapt_mesh_domain_corner_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
- Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
@@ -332,26 +326,24 @@ static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
- adapt_mesh_domain_corner_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
- Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
@@ -370,26 +362,24 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_face_to_point(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
- adapt_mesh_domain_face_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_face_to_point_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
@@ -401,26 +391,24 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh,
}
}
-static ReadAttributePtr adapt_mesh_domain_face_to_corner(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
- adapt_mesh_domain_face_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
@@ -437,21 +425,19 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
- adapt_mesh_domain_face_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
/**
@@ -461,7 +447,7 @@ static ReadAttributePtr adapt_mesh_domain_face_to_edge(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
@@ -478,21 +464,19 @@ static void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
- adapt_mesh_domain_point_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_point_to_face_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
/**
@@ -502,7 +486,7 @@ static ReadAttributePtr adapt_mesh_domain_point_to_face(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totedge);
@@ -517,26 +501,24 @@ static void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_point_to_edge(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totedge);
- adapt_mesh_domain_point_to_edge_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totloop);
@@ -558,26 +540,24 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totloop);
- adapt_mesh_domain_edge_to_corner_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
template<typename T>
static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totvert);
@@ -593,21 +573,19 @@ static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totvert);
- adapt_mesh_domain_edge_to_point_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
/**
@@ -617,7 +595,7 @@ static ReadAttributePtr adapt_mesh_domain_edge_to_point(const Mesh &mesh,
*/
template<typename T>
static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
- const Span<T> old_values,
+ const VArray<T> &old_values,
MutableSpan<T> r_values)
{
BLI_assert(r_values.size() == mesh.totpoly);
@@ -634,87 +612,86 @@ static void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh,
mixer.finalize();
}
-static ReadAttributePtr adapt_mesh_domain_edge_to_face(const Mesh &mesh,
- ReadAttributePtr attribute)
+static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr varray)
{
- ReadAttributePtr new_attribute;
- const CustomDataType data_type = attribute->custom_data_type();
+ GVArrayPtr new_varray;
+ const CustomDataType data_type = cpp_type_to_custom_data_type(varray->type());
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(mesh.totpoly);
- adapt_mesh_domain_edge_to_face_impl<T>(mesh, attribute->get_span<T>(), values);
- new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT,
- std::move(values));
+ adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray->typed<T>(), values);
+ new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values));
}
});
- return new_attribute;
+ return new_varray;
}
} // namespace blender::bke
-ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute,
- const AttributeDomain new_domain) const
+blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain(
+ blender::fn::GVArrayPtr varray,
+ const AttributeDomain from_domain,
+ const AttributeDomain to_domain) const
{
- if (!attribute) {
+ if (!varray) {
return {};
}
- if (attribute->size() == 0) {
+ if (varray->size() == 0) {
return {};
}
- const AttributeDomain old_domain = attribute->domain();
- if (old_domain == new_domain) {
- return attribute;
+ if (from_domain == to_domain) {
+ return varray;
}
- switch (old_domain) {
+ switch (from_domain) {
case ATTR_DOMAIN_CORNER: {
- switch (new_domain) {
+ switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(varray));
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(varray));
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(varray));
default:
break;
}
break;
}
case ATTR_DOMAIN_POINT: {
- switch (new_domain) {
+ switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(varray));
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(varray));
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(varray));
default:
break;
}
break;
}
case ATTR_DOMAIN_FACE: {
- switch (new_domain) {
+ switch (to_domain) {
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(varray));
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(varray));
case ATTR_DOMAIN_EDGE:
- return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(varray));
default:
break;
}
break;
}
case ATTR_DOMAIN_EDGE: {
- switch (new_domain) {
+ switch (to_domain) {
case ATTR_DOMAIN_CORNER:
- return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(varray));
case ATTR_DOMAIN_POINT:
- return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(varray));
case ATTR_DOMAIN_FACE:
- return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(attribute));
+ return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(varray));
default:
break;
}
@@ -743,25 +720,21 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com
namespace blender::bke {
-template<typename StructT,
- typename ElemT,
- ElemT (*GetFunc)(const StructT &),
- AttributeDomain Domain>
-static ReadAttributePtr make_derived_read_attribute(const void *data, const int domain_size)
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
+static GVArrayPtr make_derived_read_attribute(const void *data, const int domain_size)
{
- return std::make_unique<DerivedArrayReadAttribute<StructT, ElemT, GetFunc>>(
- Domain, Span<StructT>((const StructT *)data, domain_size));
+ return std::make_unique<fn::GVArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
+ Span<StructT>((const StructT *)data, domain_size));
}
template<typename StructT,
typename ElemT,
ElemT (*GetFunc)(const StructT &),
- void (*SetFunc)(StructT &, const ElemT &),
- AttributeDomain Domain>
-static WriteAttributePtr make_derived_write_attribute(void *data, const int domain_size)
+ void (*SetFunc)(StructT &, ElemT)>
+static GVMutableArrayPtr make_derived_write_attribute(void *data, const int domain_size)
{
- return std::make_unique<DerivedArrayWriteAttribute<StructT, ElemT, GetFunc, SetFunc>>(
- Domain, MutableSpan<StructT>((StructT *)data, domain_size));
+ return std::make_unique<fn::GVMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(
+ MutableSpan<StructT>((StructT *)data, domain_size));
}
static float3 get_vertex_position(const MVert &vert)
@@ -769,7 +742,7 @@ static float3 get_vertex_position(const MVert &vert)
return float3(vert.co);
}
-static void set_vertex_position(MVert &vert, const float3 &position)
+static void set_vertex_position(MVert &vert, float3 position)
{
copy_v3_v3(vert.co, position);
}
@@ -787,7 +760,7 @@ static int get_material_index(const MPoly &mpoly)
return static_cast<int>(mpoly.mat_nr);
}
-static void set_material_index(MPoly &mpoly, const int &index)
+static void set_material_index(MPoly &mpoly, int index)
{
mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX));
}
@@ -797,7 +770,7 @@ static bool get_shade_smooth(const MPoly &mpoly)
return mpoly.flag & ME_SMOOTH;
}
-static void set_shade_smooth(MPoly &mpoly, const bool &value)
+static void set_shade_smooth(MPoly &mpoly, bool value)
{
SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH);
}
@@ -807,7 +780,7 @@ static float2 get_loop_uv(const MLoopUV &uv)
return float2(uv.uv);
}
-static void set_loop_uv(MLoopUV &uv, const float2 &co)
+static void set_loop_uv(MLoopUV &uv, float2 co)
{
copy_v2_v2(uv.uv, co);
}
@@ -821,7 +794,7 @@ static Color4f get_loop_color(const MLoopCol &col)
return linear_color;
}
-static void set_loop_color(MLoopCol &col, const Color4f &linear_color)
+static void set_loop_color(MLoopCol &col, Color4f linear_color)
{
linearrgb_to_srgb_uchar4(&col.r, linear_color);
}
@@ -831,71 +804,62 @@ static float get_crease(const MEdge &edge)
return edge.crease / 255.0f;
}
-static void set_crease(MEdge &edge, const float &value)
+static void set_crease(MEdge &edge, float value)
{
edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
}
-class VertexWeightWriteAttribute final : public WriteAttribute {
+class VMutableArray_For_VertexWeights final : public VMutableArray<float> {
private:
MDeformVert *dverts_;
const int dvert_index_;
public:
- VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index)
- : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
- dverts_(dverts),
- dvert_index_(dvert_index)
+ VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index)
+ : VMutableArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
{
}
- void get_internal(const int64_t index, void *r_value) const override
+ float get_impl(const int64_t index) const override
{
- get_internal(dverts_, dvert_index_, index, r_value);
+ return get_internal(dverts_, dvert_index_, index);
}
- void set_internal(const int64_t index, const void *value) override
+ void set_impl(const int64_t index, const float value) override
{
MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_);
- weight->weight = *reinterpret_cast<const float *>(value);
+ weight->weight = value;
}
- static void get_internal(const MDeformVert *dverts,
- const int dvert_index,
- const int64_t index,
- void *r_value)
+ static float get_internal(const MDeformVert *dverts, const int dvert_index, const int64_t index)
{
if (dverts == nullptr) {
- *(float *)r_value = 0.0f;
- return;
+ return 0.0f;
}
const MDeformVert &dvert = dverts[index];
for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) {
if (weight.def_nr == dvert_index) {
- *(float *)r_value = weight.weight;
- return;
+ return weight.weight;
}
}
- *(float *)r_value = 0.0f;
+ return 0.0f;
}
};
-class VertexWeightReadAttribute final : public ReadAttribute {
+class VArray_For_VertexWeights final : public VArray<float> {
private:
const MDeformVert *dverts_;
const int dvert_index_;
public:
- VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index)
- : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert),
- dverts_(dverts),
- dvert_index_(dvert_index)
+ VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index)
+ : VArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index)
{
}
- void get_internal(const int64_t index, void *r_value) const override
+ float get_impl(const int64_t index) const override
{
- VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value);
+ return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index);
}
};
@@ -904,8 +868,8 @@ class VertexWeightReadAttribute final : public ReadAttribute {
*/
class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
public:
- ReadAttributePtr try_get_for_read(const GeometryComponent &component,
- const StringRef attribute_name) const final
+ ReadAttributeLookup try_get_for_read(const GeometryComponent &component,
+ const StringRef attribute_name) const final
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
@@ -917,15 +881,17 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
}
if (mesh == nullptr || mesh->dvert == nullptr) {
static const float default_value = 0.0f;
- return std::make_unique<ConstantReadAttribute>(
- ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value);
+ return {std::make_unique<fn::GVArray_For_SingleValueRef>(
+ CPPType::get<float>(), mesh->totvert, &default_value),
+ ATTR_DOMAIN_POINT};
}
- return std::make_unique<VertexWeightReadAttribute>(
- mesh->dvert, mesh->totvert, vertex_group_index);
+ return {std::make_unique<fn::GVArray_For_EmbeddedVArray<float, VArray_For_VertexWeights>>(
+ mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
+ ATTR_DOMAIN_POINT};
}
- WriteAttributePtr try_get_for_write(GeometryComponent &component,
- const StringRef attribute_name) const final
+ WriteAttributeLookup try_get_for_write(GeometryComponent &component,
+ const StringRef attribute_name) const final
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_MESH);
MeshComponent &mesh_component = static_cast<MeshComponent &>(component);
@@ -946,8 +912,11 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider {
mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer(
&mesh->vdata, CD_MDEFORMVERT, mesh->totvert);
}
- return std::make_unique<blender::bke::VertexWeightWriteAttribute>(
- mesh->dvert, mesh->totvert, vertex_group_index);
+ return {
+ std::make_unique<
+ fn::GVMutableArray_For_EmbeddedVMutableArray<float, VMutableArray_For_VertexWeights>>(
+ mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index),
+ ATTR_DOMAIN_POINT};
}
bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final
@@ -1009,7 +978,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
{
}
- ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final
+ GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
{
const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
const Mesh *mesh = mesh_component.get_for_read();
@@ -1022,8 +991,8 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
- return std::make_unique<ArrayReadAttribute<float3>>(
- ATTR_DOMAIN_FACE, Span<float3>((const float3 *)data, mesh->totpoly));
+ return std::make_unique<fn::GVArray_For_Span<float3>>(
+ Span<float3>((const float3 *)data, mesh->totpoly));
}
Array<float3> normals(mesh->totpoly);
@@ -1032,10 +1001,10 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider {
BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]);
}
- return std::make_unique<OwnedArrayReadAttribute<float3>>(ATTR_DOMAIN_FACE, std::move(normals));
+ return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals));
}
- WriteAttributePtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
+ GVMutableArrayPtr try_get_for_write(GeometryComponent &UNUSED(component)) const final
{
return {};
}
@@ -1105,12 +1074,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
point_access,
- make_derived_read_attribute<MVert, float3, get_vertex_position, ATTR_DOMAIN_POINT>,
- make_derived_write_attribute<MVert,
- float3,
- get_vertex_position,
- set_vertex_position,
- ATTR_DOMAIN_POINT>,
+ make_derived_read_attribute<MVert, float3, get_vertex_position>,
+ make_derived_write_attribute<MVert, float3, get_vertex_position, set_vertex_position>,
tag_normals_dirty_when_writing_position);
static NormalAttributeProvider normal;
@@ -1124,12 +1089,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
face_access,
- make_derived_read_attribute<MPoly, int, get_material_index, ATTR_DOMAIN_FACE>,
- make_derived_write_attribute<MPoly,
- int,
- get_material_index,
- set_material_index,
- ATTR_DOMAIN_FACE>,
+ make_derived_read_attribute<MPoly, int, get_material_index>,
+ make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>,
nullptr);
static BuiltinCustomDataLayerProvider shade_smooth(
@@ -1141,12 +1102,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
face_access,
- make_derived_read_attribute<MPoly, bool, get_shade_smooth, ATTR_DOMAIN_FACE>,
- make_derived_write_attribute<MPoly,
- bool,
- get_shade_smooth,
- set_shade_smooth,
- ATTR_DOMAIN_FACE>,
+ make_derived_read_attribute<MPoly, bool, get_shade_smooth>,
+ make_derived_write_attribute<MPoly, bool, get_shade_smooth, set_shade_smooth>,
nullptr);
static BuiltinCustomDataLayerProvider crease(
@@ -1158,8 +1115,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::NonDeletable,
edge_access,
- make_derived_read_attribute<MEdge, float, get_crease, ATTR_DOMAIN_EDGE>,
- make_derived_write_attribute<MEdge, float, get_crease, set_crease, ATTR_DOMAIN_EDGE>,
+ make_derived_read_attribute<MEdge, float, get_crease>,
+ make_derived_write_attribute<MEdge, float, get_crease, set_crease>,
nullptr);
static NamedLegacyCustomDataProvider uvs(
@@ -1167,20 +1124,16 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
CD_PROP_FLOAT2,
CD_MLOOPUV,
corner_access,
- make_derived_read_attribute<MLoopUV, float2, get_loop_uv, ATTR_DOMAIN_CORNER>,
- make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv, ATTR_DOMAIN_CORNER>);
+ make_derived_read_attribute<MLoopUV, float2, get_loop_uv>,
+ make_derived_write_attribute<MLoopUV, float2, get_loop_uv, set_loop_uv>);
static NamedLegacyCustomDataProvider vertex_colors(
ATTR_DOMAIN_CORNER,
CD_PROP_COLOR,
CD_MLOOPCOL,
corner_access,
- make_derived_read_attribute<MLoopCol, Color4f, get_loop_color, ATTR_DOMAIN_CORNER>,
- make_derived_write_attribute<MLoopCol,
- Color4f,
- get_loop_color,
- set_loop_color,
- ATTR_DOMAIN_CORNER>);
+ make_derived_read_attribute<MLoopCol, Color4f, get_loop_color>,
+ make_derived_write_attribute<MLoopCol, Color4f, get_loop_color, set_loop_color>);
static VertexGroupsAttributeProvider vertex_groups;
static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access);
diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
index 135de14b4f7..6c4af7a6d23 100644
--- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
+++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc
@@ -140,16 +140,17 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con
namespace blender::bke {
-template<typename T, AttributeDomain Domain>
-static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size)
+template<typename T>
+static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size)
{
- return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size));
+ return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size));
}
-template<typename T, AttributeDomain Domain>
-static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size)
+template<typename T>
+static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size)
{
- return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size));
+ return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>(
+ MutableSpan<T>((T *)data, domain_size));
}
/**
@@ -179,30 +180,28 @@ static ComponentAttributeProviders create_attribute_providers_for_point_cloud()
},
update_custom_data_pointers};
- static BuiltinCustomDataLayerProvider position(
- "position",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT3,
- CD_PROP_FLOAT3,
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
- point_access,
- make_array_read_attribute<float3, ATTR_DOMAIN_POINT>,
- make_array_write_attribute<float3, ATTR_DOMAIN_POINT>,
- nullptr);
- static BuiltinCustomDataLayerProvider radius(
- "radius",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT,
- CD_PROP_FLOAT,
- BuiltinAttributeProvider::Creatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::Deletable,
- point_access,
- make_array_read_attribute<float, ATTR_DOMAIN_POINT>,
- make_array_write_attribute<float, ATTR_DOMAIN_POINT>,
- nullptr);
+ static BuiltinCustomDataLayerProvider position("position",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT3,
+ CD_PROP_FLOAT3,
+ BuiltinAttributeProvider::NonCreatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::NonDeletable,
+ point_access,
+ make_array_read_attribute<float3>,
+ make_array_write_attribute<float3>,
+ nullptr);
+ static BuiltinCustomDataLayerProvider radius("radius",
+ ATTR_DOMAIN_POINT,
+ CD_PROP_FLOAT,
+ CD_PROP_FLOAT,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ point_access,
+ make_array_read_attribute<float>,
+ make_array_write_attribute<float>,
+ nullptr);
static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access);
return ComponentAttributeProviders({&position, &radius}, {&point_custom_data});
}
diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc
index 07d0e520c93..2e9f6daabad 100644
--- a/source/blender/blenkernel/intern/geometry_set_instances.cc
+++ b/source/blender/blenkernel/intern/geometry_set_instances.cc
@@ -450,12 +450,13 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
BLI_assert(cpp_type != nullptr);
result.attribute_try_create(entry.key, domain_output, data_type_output);
- WriteAttributePtr write_attribute = result.attribute_try_get_for_write(name);
- if (!write_attribute || &write_attribute->cpp_type() != cpp_type ||
- write_attribute->domain() != domain_output) {
+ WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(name);
+ if (!write_attribute || &write_attribute.varray->type() != cpp_type ||
+ write_attribute.domain != domain_output) {
continue;
}
- fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
+
+ fn::GVMutableArray_GSpan dst_span{*write_attribute.varray};
int offset = 0;
for (const GeometryInstanceGroup &set_group : set_groups) {
@@ -467,11 +468,11 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
if (domain_size == 0) {
continue; /* Domain size is 0, so no need to increment the offset. */
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(
+ GVArrayPtr source_attribute = component.attribute_try_get_for_read(
name, domain_output, data_type_output);
if (source_attribute) {
- fn::GSpan src_span = source_attribute->get_span();
+ fn::GVArray_GSpan src_span{*source_attribute};
const void *src_buffer = src_span.data();
for (const int UNUSED(i) : set_group.transforms.index_range()) {
void *dst_buffer = dst_span[offset];
@@ -486,7 +487,7 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups,
}
}
- write_attribute->apply_span();
+ dst_span.save();
}
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c
index 729c38ae7cf..1ec3b6a1cbf 100644
--- a/source/blender/blenkernel/intern/mesh_convert.c
+++ b/source/blender/blenkernel/intern/mesh_convert.c
@@ -1542,7 +1542,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
* check whether it is still true with Mesh */
Mesh tmp = *mesh_dst;
int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
- int did_shapekeys = 0;
+ bool did_shapekeys = false;
eCDAllocType alloctype = CD_DUPLICATE;
if (take_ownership /* && dm->type == DM_TYPE_CDDM && dm->needsFree */) {
@@ -1597,7 +1597,7 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
}
shapekey_layers_to_keyblocks(mesh_src, mesh_dst, uid);
- did_shapekeys = 1;
+ did_shapekeys = true;
}
/* copy texture space */
@@ -1626,13 +1626,18 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
totedge);
}
if (!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
- /* TODO(Sybren): assignment to tmp.mxxx is probably not necessary due to the
- * BKE_mesh_update_customdata_pointers() call below. */
- tmp.mloop = (alloctype == CD_ASSIGN) ? mesh_src->mloop : MEM_dupallocN(mesh_src->mloop);
- tmp.mpoly = (alloctype == CD_ASSIGN) ? mesh_src->mpoly : MEM_dupallocN(mesh_src->mpoly);
-
- CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
- CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
+ CustomData_add_layer(&tmp.ldata,
+ CD_MLOOP,
+ CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->mloop :
+ MEM_dupallocN(mesh_src->mloop),
+ tmp.totloop);
+ CustomData_add_layer(&tmp.pdata,
+ CD_MPOLY,
+ CD_ASSIGN,
+ (alloctype == CD_ASSIGN) ? mesh_src->mpoly :
+ MEM_dupallocN(mesh_src->mpoly),
+ tmp.totpoly);
}
/* object had got displacement layer, should copy this layer to save sculpted data */
@@ -1651,9 +1656,6 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src,
/* yes, must be before _and_ after tessellate */
BKE_mesh_update_customdata_pointers(&tmp, false);
- /* since 2.65 caller must do! */
- // BKE_mesh_tessface_calc(&tmp);
-
CustomData_free(&mesh_dst->vdata, mesh_dst->totvert);
CustomData_free(&mesh_dst->edata, mesh_dst->totedge);
CustomData_free(&mesh_dst->fdata, mesh_dst->totface);
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc
new file mode 100644
index 00000000000..91c9951ae89
--- /dev/null
+++ b/source/blender/blenkernel/intern/mesh_sample.cc
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+
+#include "BKE_attribute_math.hh"
+#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+namespace blender::bke::mesh_surface_sample {
+
+static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
+{
+ /* This only updates a cache and can be considered to be logically const. */
+ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh));
+ const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
+ return {looptris, looptris_len};
+}
+
+template<typename T>
+BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const Span<float3> bary_coords,
+ const VArray<T> &data_in,
+ const MutableSpan<T> data_out)
+{
+ const Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const int i : bary_coords.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const float3 &bary_coord = bary_coords[i];
+
+ const int v0_index = mesh.mloop[looptri.tri[0]].v;
+ const int v1_index = mesh.mloop[looptri.tri[1]].v;
+ const int v2_index = mesh.mloop[looptri.tri[2]].v;
+
+ const T v0 = data_in[v0_index];
+ const T v1 = data_in[v1_index];
+ const T v2 = data_in[v2_index];
+
+ const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
+ data_out[i] = interpolated_value;
+ }
+}
+
+void sample_point_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const Span<float3> bary_coords,
+ const GVArray &data_in,
+ const GMutableSpan data_out)
+{
+ BLI_assert(data_out.size() == looptri_indices.size());
+ BLI_assert(data_out.size() == bary_coords.size());
+ BLI_assert(data_in.size() == mesh.totvert);
+ BLI_assert(data_in.type() == data_out.type());
+
+ const CPPType &type = data_in.type();
+ attribute_math::convert_to_static_type(type, [&](auto dummy) {
+ using T = decltype(dummy);
+ sample_point_attribute<T>(
+ mesh, looptri_indices, bary_coords, data_in.typed<T>(), data_out.typed<T>());
+ });
+}
+
+template<typename T>
+BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const Span<float3> bary_coords,
+ const VArray<T> &data_in,
+ const MutableSpan<T> data_out)
+{
+ Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const int i : bary_coords.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const float3 &bary_coord = bary_coords[i];
+
+ const int loop_index_0 = looptri.tri[0];
+ const int loop_index_1 = looptri.tri[1];
+ const int loop_index_2 = looptri.tri[2];
+
+ const T v0 = data_in[loop_index_0];
+ const T v1 = data_in[loop_index_1];
+ const T v2 = data_in[loop_index_2];
+
+ const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
+ data_out[i] = interpolated_value;
+ }
+}
+
+void sample_corner_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const Span<float3> bary_coords,
+ const GVArray &data_in,
+ const GMutableSpan data_out)
+{
+ BLI_assert(data_out.size() == looptri_indices.size());
+ BLI_assert(data_out.size() == bary_coords.size());
+ BLI_assert(data_in.size() == mesh.totloop);
+ BLI_assert(data_in.type() == data_out.type());
+
+ const CPPType &type = data_in.type();
+ attribute_math::convert_to_static_type(type, [&](auto dummy) {
+ using T = decltype(dummy);
+ sample_corner_attribute<T>(
+ mesh, looptri_indices, bary_coords, data_in.typed<T>(), data_out.typed<T>());
+ });
+}
+
+template<typename T>
+void sample_face_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const VArray<T> &data_in,
+ const MutableSpan<T> data_out)
+{
+ Span<MLoopTri> looptris = get_mesh_looptris(mesh);
+
+ for (const int i : data_out.index_range()) {
+ const int looptri_index = looptri_indices[i];
+ const MLoopTri &looptri = looptris[looptri_index];
+ const int poly_index = looptri.poly;
+ data_out[i] = data_in[poly_index];
+ }
+}
+
+void sample_face_attribute(const Mesh &mesh,
+ const Span<int> looptri_indices,
+ const GVArray &data_in,
+ const GMutableSpan data_out)
+{
+ BLI_assert(data_out.size() == looptri_indices.size());
+ BLI_assert(data_in.size() == mesh.totpoly);
+ BLI_assert(data_in.type() == data_out.type());
+
+ const CPPType &type = data_in.type();
+ attribute_math::convert_to_static_type(type, [&](auto dummy) {
+ using T = decltype(dummy);
+ sample_face_attribute<T>(mesh, looptri_indices, data_in.typed<T>(), data_out.typed<T>());
+ });
+}
+
+} // namespace blender::bke::mesh_surface_sample
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 02195e0d60f..473be34d69a 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4968,6 +4968,7 @@ static void registerGeometryNodes()
register_node_type_geo_sample_texture();
register_node_type_geo_subdivide();
register_node_type_geo_subdivision_surface();
+ register_node_type_geo_switch();
register_node_type_geo_transform();
register_node_type_geo_triangulate();
register_node_type_geo_volume_to_mesh();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 160fb93b835..522b4549f57 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1336,7 +1336,7 @@ bool BKE_object_support_modifier_type_check(const Object *ob, int modifier_type)
return (mti->modifyGeometrySet != NULL);
}
if (ob->type == OB_VOLUME) {
- return (mti->modifyVolume != NULL);
+ return (mti->modifyVolume != NULL) || (mti->modifyGeometrySet != NULL);
}
if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsVertexCosOnly) == 0) {
diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc
index 7b03839f659..93d5e116131 100644
--- a/source/blender/blenkernel/intern/volume.cc
+++ b/source/blender/blenkernel/intern/volume.cc
@@ -39,6 +39,7 @@
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
+#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@@ -1003,13 +1004,12 @@ static void volume_update_simplify_level(Volume *volume, const Depsgraph *depsgr
#endif
}
-static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
- struct Scene *scene,
- Object *object,
- Volume *volume_input)
+static void volume_evaluate_modifiers(struct Depsgraph *depsgraph,
+ struct Scene *scene,
+ Object *object,
+ Volume *volume_input,
+ GeometrySet &geometry_set)
{
- Volume *volume = volume_input;
-
/* Modifier evaluation modes. */
const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime;
@@ -1030,25 +1030,22 @@ static Volume *volume_evaluate_modifiers(struct Depsgraph *depsgraph,
continue;
}
- if (mti->modifyVolume) {
- /* Ensure we are not modifying the input. */
- if (volume == volume_input) {
- volume = BKE_volume_copy_for_eval(volume, true);
+ if (mti->modifyGeometrySet) {
+ mti->modifyGeometrySet(md, &mectx, &geometry_set);
+ }
+ else if (mti->modifyVolume) {
+ VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
+ Volume *volume_old = volume_component.get_for_write();
+ if (volume_old == nullptr) {
+ volume_old = BKE_volume_new_for_eval(volume_input);
+ volume_component.replace(volume_old);
}
-
- Volume *volume_next = mti->modifyVolume(md, &mectx, volume);
-
- if (volume_next && volume_next != volume) {
- /* If the modifier returned a new volume, release the old one. */
- if (volume != volume_input) {
- BKE_id_free(nullptr, volume);
- }
- volume = volume_next;
+ Volume *volume_new = mti->modifyVolume(md, &mectx, volume_old);
+ if (volume_new != volume_old) {
+ volume_component.replace(volume_new);
}
}
}
-
- return volume;
}
void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
@@ -1072,6 +1069,24 @@ void BKE_volume_eval_geometry(struct Depsgraph *depsgraph, Volume *volume)
}
}
+static Volume *take_volume_ownership_from_geometry_set(GeometrySet &geometry_set)
+{
+ if (!geometry_set.has<VolumeComponent>()) {
+ return nullptr;
+ }
+ VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
+ Volume *volume = volume_component.release();
+ if (volume != nullptr) {
+ /* Add back, but only as read-only non-owning component. */
+ volume_component.replace(volume, GeometryOwnershipType::ReadOnly);
+ }
+ else {
+ /* The component was empty, we can remove it. */
+ geometry_set.remove<VolumeComponent>();
+ }
+ return volume;
+}
+
void BKE_volume_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Object *object)
{
/* Free any evaluated data and restore original data. */
@@ -1079,11 +1094,22 @@ void BKE_volume_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Ob
/* Evaluate modifiers. */
Volume *volume = (Volume *)object->data;
- Volume *volume_eval = volume_evaluate_modifiers(depsgraph, scene, object, volume);
+ GeometrySet geometry_set;
+ VolumeComponent &volume_component = geometry_set.get_component_for_write<VolumeComponent>();
+ volume_component.replace(volume, GeometryOwnershipType::ReadOnly);
+ volume_evaluate_modifiers(depsgraph, scene, object, volume, geometry_set);
+
+ Volume *volume_eval = take_volume_ownership_from_geometry_set(geometry_set);
+
+ /* If the geometry set did not contain a volume, we still create an empty one. */
+ if (volume_eval == nullptr) {
+ volume_eval = BKE_volume_new_for_eval(volume);
+ }
/* Assign evaluated object. */
- const bool is_owned = (volume != volume_eval);
- BKE_object_eval_assign_data(object, &volume_eval->id, is_owned);
+ const bool eval_is_owned = (volume != volume_eval);
+ BKE_object_eval_assign_data(object, &volume_eval->id, eval_is_owned);
+ object->runtime.geometry_set_eval = new GeometrySet(std::move(geometry_set));
}
void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, const char *filepath)
diff --git a/source/blender/blenlib/BLI_map.hh b/source/blender/blenlib/BLI_map.hh
index 9fa69853e44..376bf5df06f 100644
--- a/source/blender/blenlib/BLI_map.hh
+++ b/source/blender/blenlib/BLI_map.hh
@@ -247,11 +247,11 @@ class Map {
{
this->add_new_as(std::move(key), std::move(value));
}
- template<typename ForwardKey, typename ForwardValue>
- void add_new_as(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ void add_new_as(ForwardKey &&key, ForwardValue &&... value)
{
this->add_new__impl(
- std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
+ std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -277,11 +277,11 @@ class Map {
{
return this->add_as(std::move(key), std::move(value));
}
- template<typename ForwardKey, typename ForwardValue>
- bool add_as(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add_as(ForwardKey &&key, ForwardValue &&... value)
{
return this->add__impl(
- std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
+ std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -307,11 +307,11 @@ class Map {
{
return this->add_overwrite_as(std::move(key), std::move(value));
}
- template<typename ForwardKey, typename ForwardValue>
- bool add_overwrite_as(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add_overwrite_as(ForwardKey &&key, ForwardValue &&... value)
{
return this->add_overwrite__impl(
- std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
+ std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -413,12 +413,12 @@ class Map {
{
return this->pop_default_as(key, std::move(default_value));
}
- template<typename ForwardKey, typename ForwardValue>
- Value pop_default_as(const ForwardKey &key, ForwardValue &&default_value)
+ template<typename ForwardKey, typename... ForwardValue>
+ Value pop_default_as(const ForwardKey &key, ForwardValue &&... default_value)
{
Slot *slot = this->lookup_slot_ptr(key, hash_(key));
if (slot == nullptr) {
- return std::forward<ForwardValue>(default_value);
+ return Value(std::forward<ForwardValue>(default_value)...);
}
Value value = std::move(*slot->value());
slot->remove();
@@ -525,15 +525,15 @@ class Map {
{
return this->lookup_default_as(key, default_value);
}
- template<typename ForwardKey, typename ForwardValue>
- Value lookup_default_as(const ForwardKey &key, ForwardValue &&default_value) const
+ template<typename ForwardKey, typename... ForwardValue>
+ Value lookup_default_as(const ForwardKey &key, ForwardValue &&... default_value) const
{
const Value *ptr = this->lookup_ptr_as(key);
if (ptr != nullptr) {
return *ptr;
}
else {
- return std::forward<ForwardValue>(default_value);
+ return Value(std::forward<ForwardValue>(default_value)...);
}
}
@@ -557,11 +557,11 @@ class Map {
{
return this->lookup_or_add_as(std::move(key), std::move(value));
}
- template<typename ForwardKey, typename ForwardValue>
- Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ Value &lookup_or_add_as(ForwardKey &&key, ForwardValue &&... value)
{
return this->lookup_or_add__impl(
- std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash_(key));
+ std::forward<ForwardKey>(key), hash_(key), std::forward<ForwardValue>(value)...);
}
/**
@@ -982,7 +982,7 @@ class Map {
SLOT_PROBING_BEGIN (ProbingStrategy, hash, new_slot_mask, slot_index) {
Slot &slot = new_slots[slot_index];
if (slot.is_empty()) {
- slot.occupy(std::move(*old_slot.key()), std::move(*old_slot.value()), hash);
+ slot.occupy(std::move(*old_slot.key()), hash, std::move(*old_slot.value()));
return;
}
}
@@ -996,8 +996,8 @@ class Map {
new (this) Map(NoExceptConstructor(), allocator);
}
- template<typename ForwardKey, typename ForwardValue>
- void add_new__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ void add_new__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
BLI_assert(!this->contains_as(key));
@@ -1005,7 +1005,7 @@ class Map {
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
- slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
+ slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
occupied_and_removed_slots_++;
return;
}
@@ -1013,14 +1013,14 @@ class Map {
MAP_SLOT_PROBING_END();
}
- template<typename ForwardKey, typename ForwardValue>
- bool add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
this->ensure_can_add();
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
- slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
+ slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
occupied_and_removed_slots_++;
return true;
}
@@ -1075,7 +1075,7 @@ class Map {
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
- slot.occupy(std::forward<ForwardKey>(key), create_value(), hash);
+ slot.occupy(std::forward<ForwardKey>(key), hash, create_value());
occupied_and_removed_slots_++;
return *slot.value();
}
@@ -1086,14 +1086,14 @@ class Map {
MAP_SLOT_PROBING_END();
}
- template<typename ForwardKey, typename ForwardValue>
- Value &lookup_or_add__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ Value &lookup_or_add__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
this->ensure_can_add();
MAP_SLOT_PROBING_BEGIN (hash, slot) {
if (slot.is_empty()) {
- slot.occupy(std::forward<ForwardKey>(key), std::forward<ForwardValue>(value), hash);
+ slot.occupy(std::forward<ForwardKey>(key), hash, std::forward<ForwardValue>(value)...);
occupied_and_removed_slots_++;
return *slot.value();
}
@@ -1104,15 +1104,15 @@ class Map {
MAP_SLOT_PROBING_END();
}
- template<typename ForwardKey, typename ForwardValue>
- bool add_overwrite__impl(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add_overwrite__impl(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
auto create_func = [&](Value *ptr) {
- new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value));
+ new (static_cast<void *>(ptr)) Value(std::forward<ForwardValue>(value)...);
return true;
};
auto modify_func = [&](Value *ptr) {
- *ptr = std::forward<ForwardValue>(value);
+ *ptr = Value(std::forward<ForwardValue>(value)...);
return false;
};
return this->add_or_modify__impl(
@@ -1221,16 +1221,18 @@ template<typename Key, typename Value> class StdUnorderedMapWrapper {
map_.reserve(n);
}
- template<typename ForwardKey, typename ForwardValue>
- void add_new(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ void add_new(ForwardKey &&key, ForwardValue &&... value)
{
- map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)});
+ map_.insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)});
}
- template<typename ForwardKey, typename ForwardValue>
- bool add(ForwardKey &&key, ForwardValue &&value)
+ template<typename ForwardKey, typename... ForwardValue>
+ bool add(ForwardKey &&key, ForwardValue &&... value)
{
- return map_.insert({std::forward<ForwardKey>(key), std::forward<ForwardValue>(value)}).second;
+ return map_
+ .insert({std::forward<ForwardKey>(key), Value(std::forward<ForwardValue>(value)...)})
+ .second;
}
bool contains(const Key &key) const
diff --git a/source/blender/blenlib/BLI_map_slots.hh b/source/blender/blenlib/BLI_map_slots.hh
index c0cb3091a8e..1b4ca11af41 100644
--- a/source/blender/blenlib/BLI_map_slots.hh
+++ b/source/blender/blenlib/BLI_map_slots.hh
@@ -195,11 +195,11 @@ template<typename Key, typename Value> class SimpleMapSlot {
* Change the state of this slot from empty/removed to occupied. The key/value has to be
* constructed by calling the constructor with the given key/value as parameter.
*/
- template<typename ForwardKey, typename ForwardValue>
- void occupy(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
BLI_assert(!this->is_occupied());
- new (&value_buffer_) Value(std::forward<ForwardValue>(value));
+ new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
this->occupy_no_value(std::forward<ForwardKey>(key), hash);
state_ = Occupied;
}
@@ -315,12 +315,12 @@ template<typename Key, typename Value, typename KeyInfo> class IntrusiveMapSlot
return is_equal(key, key_);
}
- template<typename ForwardKey, typename ForwardValue>
- void occupy(ForwardKey &&key, ForwardValue &&value, uint64_t hash)
+ template<typename ForwardKey, typename... ForwardValue>
+ void occupy(ForwardKey &&key, uint64_t hash, ForwardValue &&... value)
{
BLI_assert(!this->is_occupied());
BLI_assert(KeyInfo::is_not_empty_or_removed(key));
- new (&value_buffer_) Value(std::forward<ForwardValue>(value));
+ new (&value_buffer_) Value(std::forward<ForwardValue>(value)...);
this->occupy_no_value(std::forward<ForwardKey>(key), hash);
}
diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh
index fe511793c46..c32ba0826df 100644
--- a/source/blender/blenlib/BLI_span.hh
+++ b/source/blender/blenlib/BLI_span.hh
@@ -94,7 +94,7 @@ template<typename T> class Span {
using iterator = const T *;
using size_type = int64_t;
- private:
+ protected:
const T *data_ = nullptr;
int64_t size_ = 0;
@@ -477,7 +477,7 @@ template<typename T> class MutableSpan {
using iterator = T *;
using size_type = int64_t;
- private:
+ protected:
T *data_;
int64_t size_;
diff --git a/source/blender/blenlib/BLI_stack.hh b/source/blender/blenlib/BLI_stack.hh
index 19f77078c5b..d66316a95d9 100644
--- a/source/blender/blenlib/BLI_stack.hh
+++ b/source/blender/blenlib/BLI_stack.hh
@@ -232,13 +232,14 @@ class Stack {
{
this->push_as(std::move(value));
}
- template<typename ForwardT> void push_as(ForwardT &&value)
+ /* This is similar to `std::stack::emplace`. */
+ template<typename... ForwardT> void push_as(ForwardT &&... value)
{
if (top_ == top_chunk_->capacity_end) {
this->activate_next_chunk(1);
}
try {
- new (top_) T(std::forward<ForwardT>(value));
+ new (top_) T(std::forward<ForwardT>(value)...);
top_++;
size_++;
}
diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh
index 328d623787b..d08a5c65c52 100644
--- a/source/blender/blenlib/BLI_vector.hh
+++ b/source/blender/blenlib/BLI_vector.hh
@@ -437,13 +437,17 @@ class Vector {
*/
void append(const T &value)
{
- this->ensure_space_for_one();
- this->append_unchecked(value);
+ this->append_as(value);
}
void append(T &&value)
{
+ this->append_as(std::move(value));
+ }
+ /* This is similar to `std::vector::emplace_back`. */
+ template<typename... ForwardValue> void append_as(ForwardValue &&... value)
+ {
this->ensure_space_for_one();
- this->append_unchecked(std::move(value));
+ this->append_unchecked_as(std::forward<ForwardValue>(value)...);
}
/**
@@ -474,10 +478,18 @@ class Vector {
* behavior when not enough capacity has been reserved beforehand. Only use this in performance
* critical code.
*/
- template<typename ForwardT> void append_unchecked(ForwardT &&value)
+ void append_unchecked(const T &value)
+ {
+ this->append_unchecked_as(value);
+ }
+ void append_unchecked(T &&value)
+ {
+ this->append_unchecked_as(std::move(value));
+ }
+ template<typename... ForwardT> void append_unchecked_as(ForwardT &&... value)
{
BLI_assert(end_ < capacity_end_);
- new (end_) T(std::forward<ForwardT>(value));
+ new (end_) T(std::forward<ForwardT>(value)...);
end_++;
UPDATE_VECTOR_SIZE(this);
}
diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh
index f9b0aaa7de6..eae15f0300c 100644
--- a/source/blender/blenlib/BLI_virtual_array.hh
+++ b/source/blender/blenlib/BLI_virtual_array.hh
@@ -37,6 +37,7 @@
* see of the increased compile time and binary size is worth it.
*/
+#include "BLI_array.hh"
#include "BLI_span.hh"
namespace blender {
@@ -71,6 +72,11 @@ template<typename T> class VArray {
return size_ == 0;
}
+ IndexRange index_range() const
+ {
+ return IndexRange(size_);
+ }
+
/* Returns true when the virtual array is stored as a span internally. */
bool is_span() const
{
@@ -82,13 +88,13 @@ template<typename T> class VArray {
/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
* virtual array is not stored as a span internally. */
- Span<T> get_span() const
+ Span<T> get_internal_span() const
{
BLI_assert(this->is_span());
if (size_ == 0) {
return {};
}
- return this->get_span_impl();
+ return this->get_internal_span_impl();
}
/* Returns true when the virtual array returns the same value for every index. */
@@ -102,20 +108,35 @@ template<typename T> class VArray {
/* Returns the value that is returned for every index. This invokes undefined behavior if the
* virtual array would not return the same value for every index. */
- T get_single() const
+ T get_internal_single() const
{
BLI_assert(this->is_single());
if (size_ == 1) {
return this->get(0);
}
- return this->get_single_impl();
+ return this->get_internal_single_impl();
}
+ /* Get the element at a specific index. Note that this operator cannot be used to assign values
+ * to an index, because the return value is not a reference. */
T operator[](const int64_t index) const
{
return this->get(index);
}
+ /* Copy the entire virtual array into a span. */
+ void materialize(MutableSpan<T> r_span) const
+ {
+ BLI_assert(size_ == r_span.size());
+ this->materialize_impl(r_span);
+ }
+
+ void materialize_to_uninitialized(MutableSpan<T> r_span) const
+ {
+ BLI_assert(size_ == r_span.size());
+ this->materialize_to_uninitialized_impl(r_span);
+ }
+
protected:
virtual T get_impl(const int64_t index) const = 0;
@@ -124,7 +145,7 @@ template<typename T> class VArray {
return false;
}
- virtual Span<T> get_span_impl() const
+ virtual Span<T> get_internal_span_impl() const
{
BLI_assert_unreachable();
return {};
@@ -135,56 +156,201 @@ template<typename T> class VArray {
return false;
}
- virtual T get_single_impl() const
+ virtual T get_internal_single_impl() const
{
/* Provide a default implementation, so that subclasses don't have to provide it. This method
* should never be called because `is_single_impl` returns false by default. */
BLI_assert_unreachable();
return T();
}
+
+ virtual void materialize_impl(MutableSpan<T> r_span) const
+ {
+ if (this->is_span()) {
+ const Span<T> span = this->get_internal_span();
+ initialized_copy_n(span.data(), size_, r_span.data());
+ }
+ else if (this->is_single()) {
+ const T single = this->get_internal_single();
+ initialized_fill_n(r_span.data(), size_, single);
+ }
+ else {
+ const int64_t size = size_;
+ for (int64_t i = 0; i < size; i++) {
+ r_span[i] = this->get(i);
+ }
+ }
+ }
+
+ virtual void materialize_to_uninitialized_impl(MutableSpan<T> r_span) const
+ {
+ if (this->is_span()) {
+ const Span<T> span = this->get_internal_span();
+ uninitialized_copy_n(span.data(), size_, r_span.data());
+ }
+ else if (this->is_single()) {
+ const T single = this->get_internal_single();
+ uninitialized_fill_n(r_span.data(), size_, single);
+ }
+ else {
+ const int64_t size = size_;
+ T *dst = r_span.data();
+ for (int64_t i = 0; i < size; i++) {
+ new (dst + i) T(this->get(i));
+ }
+ }
+ }
+};
+
+/* Similar to VArray, but the elements are mutable. */
+template<typename T> class VMutableArray : public VArray<T> {
+ public:
+ VMutableArray(const int64_t size) : VArray<T>(size)
+ {
+ }
+
+ void set(const int64_t index, T value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < this->size_);
+ this->set_impl(index, std::move(value));
+ }
+
+ /* Copy the values from the source span to all elements in the virtual array. */
+ void set_all(Span<T> src)
+ {
+ BLI_assert(src.size() == this->size_);
+ this->set_all_impl(src);
+ }
+
+ MutableSpan<T> get_internal_span()
+ {
+ BLI_assert(this->is_span());
+ Span<T> span = static_cast<const VArray<T> *>(this)->get_internal_span();
+ return MutableSpan<T>(const_cast<T *>(span.data()), span.size());
+ }
+
+ protected:
+ virtual void set_impl(const int64_t index, T value) = 0;
+
+ virtual void set_all_impl(Span<T> src)
+ {
+ if (this->is_span()) {
+ const MutableSpan<T> span = this->get_internal_span();
+ initialized_copy_n(src.data(), this->size_, span.data());
+ }
+ else {
+ const int64_t size = this->size_;
+ for (int64_t i = 0; i < size; i++) {
+ this->set(i, src[i]);
+ }
+ }
+ }
};
+template<typename T> using VArrayPtr = std::unique_ptr<VArray<T>>;
+template<typename T> using VMutableArrayPtr = std::unique_ptr<VMutableArray<T>>;
+
/**
- * A virtual array implementation for a span. This class is final so that it can be devirtualized
- * by the compiler in some cases (e.g. when #devirtualize_varray is used).
+ * A virtual array implementation for a span. Methods in this class are final so that it can be
+ * devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used).
*/
-template<typename T> class VArrayForSpan final : public VArray<T> {
- private:
- const T *data_;
+template<typename T> class VArray_For_Span : public VArray<T> {
+ protected:
+ const T *data_ = nullptr;
public:
- VArrayForSpan(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
+ VArray_For_Span(const Span<T> data) : VArray<T>(data.size()), data_(data.data())
{
}
protected:
- T get_impl(const int64_t index) const override
+ VArray_For_Span(const int64_t size) : VArray<T>(size)
+ {
+ }
+
+ T get_impl(const int64_t index) const final
+ {
+ return data_[index];
+ }
+
+ bool is_span_impl() const final
+ {
+ return true;
+ }
+
+ Span<T> get_internal_span_impl() const final
+ {
+ return Span<T>(data_, this->size_);
+ }
+};
+
+template<typename T> class VMutableArray_For_MutableSpan : public VMutableArray<T> {
+ protected:
+ T *data_ = nullptr;
+
+ public:
+ VMutableArray_For_MutableSpan(const MutableSpan<T> data)
+ : VMutableArray<T>(data.size()), data_(data.data())
+ {
+ }
+
+ protected:
+ VMutableArray_For_MutableSpan(const int64_t size) : VMutableArray<T>(size)
+ {
+ }
+
+ T get_impl(const int64_t index) const final
{
return data_[index];
}
+ void set_impl(const int64_t index, T value) final
+ {
+ data_[index] = value;
+ }
+
bool is_span_impl() const override
{
return true;
}
- Span<T> get_span_impl() const override
+ Span<T> get_internal_span_impl() const override
{
return Span<T>(data_, this->size_);
}
};
/**
+ * A variant of `VArray_For_Span` that owns the underlying data.
+ * The `Container` type has to implement a `size()` and `data()` method.
+ * The `data()` method has to return a pointer to the first element in the continuous array of
+ * elements.
+ */
+template<typename Container, typename T = typename Container::value_type>
+class VArray_For_ArrayContainer : public VArray_For_Span<T> {
+ private:
+ Container container_;
+
+ public:
+ VArray_For_ArrayContainer(Container container)
+ : VArray_For_Span<T>((int64_t)container.size()), container_(std::move(container))
+ {
+ this->data_ = container_.data();
+ }
+};
+
+/**
* A virtual array implementation that returns the same value for every index. This class is final
* so that it can be devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is
* used).
*/
-template<typename T> class VArrayForSingle final : public VArray<T> {
+template<typename T> class VArray_For_Single final : public VArray<T> {
private:
T value_;
public:
- VArrayForSingle(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
+ VArray_For_Single(T value, const int64_t size) : VArray<T>(size), value_(std::move(value))
{
}
@@ -199,7 +365,7 @@ template<typename T> class VArrayForSingle final : public VArray<T> {
return this->size_ == 1;
}
- Span<T> get_span_impl() const override
+ Span<T> get_internal_span_impl() const override
{
return Span<T>(&value_, 1);
}
@@ -209,13 +375,171 @@ template<typename T> class VArrayForSingle final : public VArray<T> {
return true;
}
- T get_single_impl() const override
+ T get_internal_single_impl() const override
{
return value_;
}
};
/**
+ * In many cases a virtual array is a span internally. In those cases, access to individual could
+ * be much more efficient than calling a virtual method. When the underlying virtual array is not a
+ * span, this class allocates a new array and copies the values over.
+ *
+ * This should be used in those cases:
+ * - All elements in the virtual array are accessed multiple times.
+ * - In most cases, the underlying virtual array is a span, so no copy is necessary to benefit
+ * from faster access.
+ * - An API is called, that does not accept virtual arrays, but only spans.
+ */
+template<typename T> class VArray_Span final : public Span<T> {
+ private:
+ const VArray<T> &varray_;
+ Array<T> owned_data_;
+
+ public:
+ VArray_Span(const VArray<T> &varray) : Span<T>(), varray_(varray)
+ {
+ this->size_ = varray_.size();
+ if (varray_.is_span()) {
+ this->data_ = varray_.get_internal_span().data();
+ }
+ else {
+ owned_data_.~Array();
+ new (&owned_data_) Array<T>(varray_.size(), NoInitialization{});
+ varray_.materialize_to_uninitialized(owned_data_);
+ this->data_ = owned_data_.data();
+ }
+ }
+};
+
+/**
+ * Same as VArray_Span, but for a mutable span.
+ * The important thing to note is that when changing this span, the results might not be
+ * immediately reflected in the underlying virtual array (only when the virtual array is a span
+ * internally). The #save method can be used to write all changes to the underlying virtual array,
+ * if necessary.
+ */
+template<typename T> class VMutableArray_Span final : public MutableSpan<T> {
+ private:
+ VMutableArray<T> &varray_;
+ Array<T> owned_data_;
+ bool save_has_been_called_ = false;
+ bool show_not_saved_warning_ = true;
+
+ public:
+ /* Create a span for any virtual array. This is cheap when the virtual array is a span itself. If
+ * not, a new array has to be allocated as a wrapper for the underlying virtual array. */
+ VMutableArray_Span(VMutableArray<T> &varray, const bool copy_values_to_span = true)
+ : MutableSpan<T>(), varray_(varray)
+ {
+ this->size_ = varray_.size();
+ if (varray_.is_span()) {
+ this->data_ = varray_.get_internal_span().data();
+ }
+ else {
+ if (copy_values_to_span) {
+ owned_data_.~Array();
+ new (&owned_data_) Array<T>(varray_.size(), NoInitialization{});
+ varray_.materialize_to_uninitialized(owned_data_);
+ }
+ else {
+ owned_data_.reinitialize(varray_.size());
+ }
+ this->data_ = owned_data_.data();
+ }
+ }
+
+ ~VMutableArray_Span()
+ {
+ if (show_not_saved_warning_) {
+ if (!save_has_been_called_) {
+ std::cout << "Warning: Call `save()` to make sure that changes persist in all cases.\n";
+ }
+ }
+ }
+
+ /* Write back all values from a temporary allocated array to the underlying virtual array. */
+ void save()
+ {
+ save_has_been_called_ = true;
+ if (this->data_ != owned_data_.data()) {
+ return;
+ }
+ varray_.set_all(owned_data_);
+ }
+
+ void disable_not_applied_warning()
+ {
+ show_not_saved_warning_ = false;
+ }
+};
+
+/**
+ * This class makes it easy to create a virtual array for an existing function or lambda. The
+ * `GetFunc` should take a single `index` argument and return the value at that index.
+ */
+template<typename T, typename GetFunc> class VArray_For_Func final : public VArray<T> {
+ private:
+ GetFunc get_func_;
+
+ public:
+ VArray_For_Func(const int64_t size, GetFunc get_func)
+ : VArray<T>(size), get_func_(std::move(get_func))
+ {
+ }
+
+ private:
+ T get_impl(const int64_t index) const override
+ {
+ return get_func_(index);
+ }
+};
+
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
+class VArray_For_DerivedSpan : public VArray<ElemT> {
+ private:
+ const StructT *data_;
+
+ public:
+ VArray_For_DerivedSpan(const Span<StructT> data) : VArray<ElemT>(data.size()), data_(data.data())
+ {
+ }
+
+ private:
+ ElemT get_impl(const int64_t index) const override
+ {
+ return GetFunc(data_[index]);
+ }
+};
+
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, ElemT)>
+class VMutableArray_For_DerivedSpan : public VMutableArray<ElemT> {
+ private:
+ StructT *data_;
+
+ public:
+ VMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
+ : VMutableArray<ElemT>(data.size()), data_(data.data())
+ {
+ }
+
+ private:
+ ElemT get_impl(const int64_t index) const override
+ {
+ return GetFunc(data_[index]);
+ }
+
+ void set_impl(const int64_t index, ElemT value) override
+ {
+ SetFunc(data_[index], std::move(value));
+ }
+};
+
+/**
* Generate multiple versions of the given function optimized for different virtual arrays.
* One has to be careful with nesting multiple devirtualizations, because that results in an
* exponential number of function instantiations (increasing compile time and binary size).
@@ -229,14 +553,14 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool
/* Support disabling the devirtualization to simplify benchmarking. */
if (enable) {
if (varray.is_single()) {
- /* `VArrayForSingle` can be used for devirtualization, because it is declared `final`. */
- const VArrayForSingle<T> varray_single{varray.get_single(), varray.size()};
+ /* `VArray_For_Single` can be used for devirtualization, because it is declared `final`. */
+ const VArray_For_Single<T> varray_single{varray.get_internal_single(), varray.size()};
func(varray_single);
return;
}
if (varray.is_span()) {
- /* `VArrayForSpan` can be used for devirtualization, because it is declared `final`. */
- const VArrayForSpan<T> varray_span{varray.get_span()};
+ /* `VArray_For_Span` can be used for devirtualization, because it is declared `final`. */
+ const VArray_For_Span<T> varray_span{varray.get_internal_span()};
func(varray_span);
return;
}
@@ -262,26 +586,26 @@ inline void devirtualize_varray2(const VArray<T1> &varray1,
const bool is_single1 = varray1.is_single();
const bool is_single2 = varray2.is_single();
if (is_span1 && is_span2) {
- const VArrayForSpan<T1> varray1_span{varray1.get_span()};
- const VArrayForSpan<T2> varray2_span{varray2.get_span()};
+ const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
+ const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
func(varray1_span, varray2_span);
return;
}
if (is_span1 && is_single2) {
- const VArrayForSpan<T1> varray1_span{varray1.get_span()};
- const VArrayForSingle<T2> varray2_single{varray2.get_single(), varray2.size()};
+ const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()};
+ const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
func(varray1_span, varray2_single);
return;
}
if (is_single1 && is_span2) {
- const VArrayForSingle<T1> varray1_single{varray1.get_single(), varray1.size()};
- const VArrayForSpan<T2> varray2_span{varray2.get_span()};
+ const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
+ const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()};
func(varray1_single, varray2_span);
return;
}
if (is_single1 && is_single2) {
- const VArrayForSingle<T1> varray1_single{varray1.get_single(), varray1.size()};
- const VArrayForSingle<T2> varray2_single{varray2.get_single(), varray2.size()};
+ const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()};
+ const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()};
func(varray1_single, varray2_single);
return;
}
diff --git a/source/blender/blenlib/tests/BLI_map_test.cc b/source/blender/blenlib/tests/BLI_map_test.cc
index f1ae8fb3921..bb15f7f0d8d 100644
--- a/source/blender/blenlib/tests/BLI_map_test.cc
+++ b/source/blender/blenlib/tests/BLI_map_test.cc
@@ -604,6 +604,15 @@ TEST(map, GenericAlgorithms)
EXPECT_EQ(std::count(map.keys().begin(), map.keys().end(), 7), 1);
}
+TEST(map, AddAsVariadic)
+{
+ Map<int, StringRef> map;
+ map.add_as(3, "hello", 2);
+ map.add_as(2, "test", 1);
+ EXPECT_EQ(map.lookup(3), "he");
+ EXPECT_EQ(map.lookup(2), "t");
+}
+
/**
* Set this to 1 to activate the benchmark. It is disabled by default, because it prints a lot.
*/
diff --git a/source/blender/blenlib/tests/BLI_stack_cxx_test.cc b/source/blender/blenlib/tests/BLI_stack_cxx_test.cc
index f1fcdae3a52..b3108381d78 100644
--- a/source/blender/blenlib/tests/BLI_stack_cxx_test.cc
+++ b/source/blender/blenlib/tests/BLI_stack_cxx_test.cc
@@ -93,6 +93,15 @@ TEST(stack, Push)
EXPECT_EQ(stack.size(), 2);
}
+TEST(stack, PushAs)
+{
+ Stack<StringRef> stack;
+ stack.push_as("hello", 3);
+ stack.push_as("world", 1);
+ EXPECT_EQ(stack.pop(), "w");
+ EXPECT_EQ(stack.pop(), "hel");
+}
+
TEST(stack, PushMultiple)
{
Stack<int> stack;
diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc
index 462f13c15ab..e8636168308 100644
--- a/source/blender/blenlib/tests/BLI_vector_test.cc
+++ b/source/blender/blenlib/tests/BLI_vector_test.cc
@@ -248,6 +248,15 @@ TEST(vector, Append)
EXPECT_EQ(vec[2], 7);
}
+TEST(vector, AppendAs)
+{
+ Vector<StringRef> vec;
+ vec.append_as("hello", 2);
+ vec.append_as("world", 3);
+ EXPECT_EQ(vec[0], "he");
+ EXPECT_EQ(vec[1], "wor");
+}
+
TEST(vector, AppendAndGetIndex)
{
Vector<int> vec;
diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
index ac25229cd69..a6d2ca10315 100644
--- a/source/blender/blenlib/tests/BLI_virtual_array_test.cc
+++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc
@@ -1,26 +1,29 @@
/* Apache License, Version 2.0 */
+#include "BLI_array.hh"
#include "BLI_strict_flags.h"
+#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
#include "BLI_virtual_array.hh"
#include "testing/testing.h"
namespace blender::tests {
-TEST(virtual_array, ForSpan)
+TEST(virtual_array, Span)
{
std::array<int, 5> data = {3, 4, 5, 6, 7};
- VArrayForSpan<int> varray{data};
+ VArray_For_Span<int> varray{data};
EXPECT_EQ(varray.size(), 5);
EXPECT_EQ(varray.get(0), 3);
EXPECT_EQ(varray.get(4), 7);
EXPECT_TRUE(varray.is_span());
EXPECT_FALSE(varray.is_single());
- EXPECT_EQ(varray.get_span().data(), data.data());
+ EXPECT_EQ(varray.get_internal_span().data(), data.data());
}
-TEST(virtual_array, ForSingle)
+TEST(virtual_array, Single)
{
- VArrayForSingle<int> varray{10, 4};
+ VArray_For_Single<int> varray{10, 4};
EXPECT_EQ(varray.size(), 4);
EXPECT_EQ(varray.get(0), 10);
EXPECT_EQ(varray.get(3), 10);
@@ -28,4 +31,124 @@ TEST(virtual_array, ForSingle)
EXPECT_TRUE(varray.is_single());
}
+TEST(virtual_array, Array)
+{
+ Array<int> array = {1, 2, 3, 5, 8};
+ {
+ VArray_For_ArrayContainer varray{array};
+ EXPECT_EQ(varray.size(), 5);
+ EXPECT_EQ(varray[0], 1);
+ EXPECT_EQ(varray[2], 3);
+ EXPECT_EQ(varray[3], 5);
+ EXPECT_TRUE(varray.is_span());
+ }
+ {
+ VArray_For_ArrayContainer varray{std::move(array)};
+ EXPECT_EQ(varray.size(), 5);
+ EXPECT_EQ(varray[0], 1);
+ EXPECT_EQ(varray[2], 3);
+ EXPECT_EQ(varray[3], 5);
+ EXPECT_TRUE(varray.is_span());
+ }
+ {
+ VArray_For_ArrayContainer varray{array}; /* NOLINT: bugprone-use-after-move */
+ EXPECT_TRUE(varray.is_empty());
+ }
+}
+
+TEST(virtual_array, Vector)
+{
+ Vector<int> vector = {9, 8, 7, 6};
+ VArray_For_ArrayContainer varray{std::move(vector)};
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[0], 9);
+ EXPECT_EQ(varray[3], 6);
+}
+
+TEST(virtual_array, StdVector)
+{
+ std::vector<int> vector = {5, 6, 7, 8};
+ VArray_For_ArrayContainer varray{std::move(vector)};
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[0], 5);
+ EXPECT_EQ(varray[1], 6);
+}
+
+TEST(virtual_array, StdArray)
+{
+ std::array<int, 4> array = {2, 3, 4, 5};
+ VArray_For_ArrayContainer varray{array};
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[0], 2);
+ EXPECT_EQ(varray[1], 3);
+}
+
+TEST(virtual_array, VectorSet)
+{
+ VectorSet<int> vector_set = {5, 3, 7, 3, 3, 5, 1};
+ VArray_For_ArrayContainer varray{std::move(vector_set)};
+ EXPECT_TRUE(vector_set.is_empty()); /* NOLINT: bugprone-use-after-move. */
+ EXPECT_EQ(varray.size(), 4);
+ EXPECT_EQ(varray[0], 5);
+ EXPECT_EQ(varray[1], 3);
+ EXPECT_EQ(varray[2], 7);
+ EXPECT_EQ(varray[3], 1);
+}
+
+TEST(virtual_array, Func)
+{
+ auto func = [](int64_t index) { return (int)(index * index); };
+ VArray_For_Func<int, decltype(func)> varray{10, func};
+ EXPECT_EQ(varray.size(), 10);
+ EXPECT_EQ(varray[0], 0);
+ EXPECT_EQ(varray[3], 9);
+ EXPECT_EQ(varray[9], 81);
+}
+
+TEST(virtual_array, AsSpan)
+{
+ auto func = [](int64_t index) { return (int)(10 * index); };
+ VArray_For_Func<int, decltype(func)> func_varray{10, func};
+ VArray_Span span_varray{func_varray};
+ EXPECT_EQ(span_varray.size(), 10);
+ Span<int> span = span_varray;
+ EXPECT_EQ(span.size(), 10);
+ EXPECT_EQ(span[0], 0);
+ EXPECT_EQ(span[3], 30);
+ EXPECT_EQ(span[6], 60);
+}
+
+static int get_x(const std::array<int, 3> &item)
+{
+ return item[0];
+}
+
+static void set_x(std::array<int, 3> &item, int value)
+{
+ item[0] = value;
+}
+
+TEST(virtual_array, DerivedSpan)
+{
+ Vector<std::array<int, 3>> vector;
+ vector.append({3, 4, 5});
+ vector.append({1, 1, 1});
+ {
+ VArray_For_DerivedSpan<std::array<int, 3>, int, get_x> varray{vector};
+ EXPECT_EQ(varray.size(), 2);
+ EXPECT_EQ(varray[0], 3);
+ EXPECT_EQ(varray[1], 1);
+ }
+ {
+ VMutableArray_For_DerivedSpan<std::array<int, 3>, int, get_x, set_x> varray{vector};
+ EXPECT_EQ(varray.size(), 2);
+ EXPECT_EQ(varray[0], 3);
+ EXPECT_EQ(varray[1], 1);
+ varray.set(0, 10);
+ varray.set(1, 20);
+ EXPECT_EQ(vector[0][0], 10);
+ EXPECT_EQ(vector[1][0], 20);
+ }
+}
+
} // namespace blender::tests
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index ee9b9a49768..36802fc8842 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -57,6 +57,7 @@ set(SRC
intern/versioning_270.c
intern/versioning_280.c
intern/versioning_290.c
+ intern/versioning_300.c
intern/versioning_cycles.c
intern/versioning_defaults.c
intern/versioning_dna.c
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 85cf45bd868..b4623425582 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -3868,6 +3868,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
blo_do_versions_270(fd, lib, main);
blo_do_versions_280(fd, lib, main);
blo_do_versions_290(fd, lib, main);
+ blo_do_versions_300(fd, lib, main);
blo_do_versions_cycles(fd, lib, main);
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
@@ -3891,6 +3892,7 @@ static void do_versions_after_linking(Main *main, ReportList *reports)
do_versions_after_linking_270(main);
do_versions_after_linking_280(main, reports);
do_versions_after_linking_290(main, reports);
+ do_versions_after_linking_300(main, reports);
do_versions_after_linking_cycles(main);
main->is_locked_for_linking = false;
diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h
index 9682b5456d2..d1d4e0b3256 100644
--- a/source/blender/blenloader/intern/readfile.h
+++ b/source/blender/blenloader/intern/readfile.h
@@ -210,6 +210,7 @@ void blo_do_versions_260(struct FileData *fd, struct Library *lib, struct Main *
void blo_do_versions_270(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_280(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_290(struct FileData *fd, struct Library *lib, struct Main *bmain);
+void blo_do_versions_300(struct FileData *fd, struct Library *lib, struct Main *bmain);
void blo_do_versions_cycles(struct FileData *fd, struct Library *lib, struct Main *bmain);
void do_versions_after_linking_250(struct Main *bmain);
@@ -217,6 +218,7 @@ void do_versions_after_linking_260(struct Main *bmain);
void do_versions_after_linking_270(struct Main *bmain);
void do_versions_after_linking_280(struct Main *bmain, struct ReportList *reports);
void do_versions_after_linking_290(struct Main *bmain, struct ReportList *reports);
+void do_versions_after_linking_300(struct Main *bmain, struct ReportList *reports);
void do_versions_after_linking_cycles(struct Main *bmain);
/* This is rather unfortunate to have to expose this here, but better use that nasty hack in
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index fe8e46e8928..916c4bf0cad 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -2059,19 +2059,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
}
}
- /* Set default value for the new bisect_threshold parameter in the mirror modifier. */
- if (!MAIN_VERSION_ATLEAST(bmain, 293, 19)) {
- LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
- LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
- if (md->type == eModifierType_Mirror) {
- MirrorModifierData *mmd = (MirrorModifierData *)md;
- /* This was the previous hard-coded value. */
- mmd->bisect_threshold = 0.001f;
- }
- }
- }
- }
-
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c
new file mode 100644
index 00000000000..6b13b21f057
--- /dev/null
+++ b/source/blender/blenloader/intern/versioning_300.c
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup blenloader
+ */
+/* allow readfile to use deprecated functionality */
+#define DNA_DEPRECATED_ALLOW
+
+#include "BLI_listbase.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_genfile.h"
+#include "DNA_modifier_types.h"
+
+#include "BKE_main.h"
+
+#include "BLO_readfile.h"
+#include "readfile.h"
+
+void do_versions_after_linking_300(Main *UNUSED(bmain), ReportList *UNUSED(reports))
+{
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - #blo_do_versions_300 in this file.
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+ }
+}
+
+/* NOLINTNEXTLINE: readability-function-size */
+void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
+{
+
+ /**
+ * Versioning code until next subversion bump goes here.
+ *
+ * \note Be sure to check when bumping the version:
+ * - "versioning_userdef.c", #blo_do_versions_userdef
+ * - "versioning_userdef.c", #do_versions_theme
+ *
+ * \note Keep this message at the bottom of the function.
+ */
+ {
+ /* Keep this block, even when empty. */
+
+ /* Set default value for the new bisect_threshold parameter in the mirror modifier. */
+ if (!DNA_struct_elem_find(fd->filesdna, "MirrorModifierData", "float", "bisect_threshold")) {
+ LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
+ LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
+ if (md->type == eModifierType_Mirror) {
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+ /* This was the previous hard-coded value. */
+ mmd->bisect_threshold = 0.001f;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c
index c07271a0d33..49b5e0fecd3 100644
--- a/source/blender/draw/intern/draw_cache_impl_gpencil.c
+++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c
@@ -348,7 +348,14 @@ static void gpencil_buffer_add_stroke(gpStrokeVert *verts,
}
/* Draw line to first point to complete the loop for cyclic strokes. */
if (is_cyclic) {
- gpencil_buffer_add_point(verts, cols, gps, &pts[0], v++, false);
+ gpencil_buffer_add_point(verts, cols, gps, &pts[0], v, false);
+ /* UV factor needs to be adjusted for the last point to not be equal to the UV factor of the
+ * first point. It should be the factor of the last point plus the distance from the last point
+ * to the first.
+ */
+ gpStrokeVert *vert = &verts[v];
+ vert->u_stroke = verts[v - 1].u_stroke + len_v3v3(&pts[pts_len - 1].x, &pts[0].x);
+ v++;
}
/* Last adjacency point (not drawn). */
adj_idx = (is_cyclic) ? 1 : max_ii(0, pts_len - 2);
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 767d822aa39..535ccaa06fd 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -5576,7 +5576,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = (vc.obedit != NULL) ? SNAP_NOT_ACTIVE : SNAP_ALL,
- .use_object_edit_cage = false,
+ .edit_mode_type = SNAP_GEOM_FINAL,
},
mval,
NULL,
diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
index 364444f99ae..68322ed56af 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c
@@ -292,7 +292,7 @@ static int gizmo_move_modal(bContext *C,
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE),
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_EDIT,
.use_occlusion_test = true,
},
mval_fl,
diff --git a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
index cd7d0f5fb4c..ee344561b0e 100644
--- a/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
+++ b/source/blender/editors/gizmo_library/gizmo_types/snap3d_gizmo.c
@@ -68,7 +68,9 @@ typedef struct SnapGizmo3D {
struct {
int x;
int y;
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
short shift, ctrl, alt, oskey;
+#endif
} last_eventstate;
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
@@ -99,28 +101,30 @@ static bool eventstate_has_changed(SnapGizmo3D *snap_gizmo, const wmWindowManage
if (wm && wm->winactive) {
const wmEvent *event = wm->winactive->eventstate;
if ((event->x != snap_gizmo->last_eventstate.x) ||
- (event->y != snap_gizmo->last_eventstate.y) ||
- (event->ctrl != snap_gizmo->last_eventstate.ctrl) ||
- (event->shift != snap_gizmo->last_eventstate.shift) ||
- (event->alt != snap_gizmo->last_eventstate.alt) ||
- (event->oskey != snap_gizmo->last_eventstate.oskey)) {
+ (event->y != snap_gizmo->last_eventstate.y)) {
return true;
}
+#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
+ if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) {
+ if ((event->ctrl != snap_gizmo->last_eventstate.ctrl) ||
+ (event->shift != snap_gizmo->last_eventstate.shift) ||
+ (event->alt != snap_gizmo->last_eventstate.alt) ||
+ (event->oskey != snap_gizmo->last_eventstate.oskey)) {
+ return true;
+ }
+ }
+#endif
}
return false;
}
/* Copies the current eventstate. */
-static void eventstate_save(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
+static void eventstate_save_xy(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
{
if (wm && wm->winactive) {
const wmEvent *event = wm->winactive->eventstate;
snap_gizmo->last_eventstate.x = event->x;
snap_gizmo->last_eventstate.y = event->y;
- snap_gizmo->last_eventstate.ctrl = event->ctrl;
- snap_gizmo->last_eventstate.shift = event->shift;
- snap_gizmo->last_eventstate.alt = event->alt;
- snap_gizmo->last_eventstate.oskey = event->oskey;
}
}
@@ -140,6 +144,12 @@ static bool invert_snap(SnapGizmo3D *snap_gizmo, const wmWindowManager *wm)
return snap_gizmo->invert_snap;
}
+ /* Save new eventstate. */
+ snap_gizmo->last_eventstate.ctrl = event->ctrl;
+ snap_gizmo->last_eventstate.shift = event->shift;
+ snap_gizmo->last_eventstate.alt = event->alt;
+ snap_gizmo->last_eventstate.oskey = event->oskey;
+
const int snap_on = snap_gizmo->snap_on;
wmKeyMap *keymap = WM_keymap_active(wm, snap_gizmo->keymap);
@@ -328,23 +338,17 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
Scene *scene = DEG_get_input_scene(depsgraph);
#ifdef USE_SNAP_DETECT_FROM_KEYMAP_HACK
- if ((snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE) == 0) {
- bool invert_snap_toggle = invert_snap(snap_gizmo, wm);
- if (invert_snap_toggle != snap_gizmo->invert_snap) {
- snap_gizmo->invert_snap = invert_snap_toggle;
-
- /* Status has changed, be sure to save before early return. */
- eventstate_save(snap_gizmo, wm);
- }
+ if (!(snap_gizmo->flag & ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE)) {
+ snap_gizmo->invert_snap = invert_snap(snap_gizmo, wm);
const ToolSettings *ts = scene->toolsettings;
- if (invert_snap_toggle != !(ts->snap_flag & SCE_SNAP)) {
+ if (snap_gizmo->invert_snap != !(ts->snap_flag & SCE_SNAP)) {
snap_gizmo->snap_elem = 0;
return 0;
}
}
#endif
- eventstate_save(snap_gizmo, wm);
+ eventstate_save_xy(snap_gizmo, wm);
snap_gizmo->is_enabled = true;
@@ -364,25 +368,39 @@ short ED_gizmotypes_snap_3d_update(wmGizmo *gz,
snap_elements &= ~SCE_SNAP_MODE_EDGE_PERPENDICULAR;
}
+ eSnapSelect snap_select = (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_ONLY_ACTIVE) ?
+ SNAP_ONLY_ACTIVE :
+ SNAP_ALL;
+
+ eSnapEditType edit_mode_type = (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_EDIT_GEOM_FINAL) ?
+ SNAP_GEOM_FINAL :
+ (snap_gizmo->flag & ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE) ?
+ SNAP_GEOM_CAGE :
+ SNAP_GEOM_EDIT;
+
+ bool use_occlusion_test = (snap_gizmo->flag & ED_SNAPGIZMO_OCCLUSION_ALWAYS_TRUE) ? false :
+ true;
+
float dist_px = 12.0f * U.pixelsize;
ED_gizmotypes_snap_3d_context_ensure(scene, region, v3d, gz);
- snap_elem = ED_transform_snap_object_project_view3d_ex(snap_gizmo->snap_context_v3d,
- depsgraph,
- snap_elements,
- &(const struct SnapObjectParams){
- .snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
- .use_occlusion_test = true,
- },
- mval_fl,
- prev_co,
- &dist_px,
- co,
- no,
- &index,
- NULL,
- NULL);
+ snap_elem = ED_transform_snap_object_project_view3d_ex(
+ snap_gizmo->snap_context_v3d,
+ depsgraph,
+ snap_elements,
+ &(const struct SnapObjectParams){
+ .snap_select = snap_select,
+ .edit_mode_type = edit_mode_type,
+ .use_occlusion_test = use_occlusion_test,
+ },
+ mval_fl,
+ prev_co,
+ &dist_px,
+ co,
+ no,
+ &index,
+ NULL,
+ NULL);
}
if (snap_elem == 0) {
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index b269fd84d5f..c93fcb9eb8c 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -3745,3 +3745,51 @@ void GPENCIL_OT_layer_mask_remove(wmOperatorType *ot)
ot->exec = gpencil_layer_mask_remove_exec;
ot->poll = gpencil_active_layer_poll;
}
+
+static int gpencil_layer_mask_move_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
+ const int direction = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl)) {
+ return OPERATOR_CANCELLED;
+ }
+ if (gpl->act_mask > 0) {
+ bGPDlayer_Mask *mask = BLI_findlink(&gpl->mask_layers, gpl->act_mask - 1);
+ if (mask != NULL) {
+ BLI_assert(ELEM(direction, -1, 0, 1)); /* we use value below */
+ if (BLI_listbase_link_move(&gpl->mask_layers, mask, direction)) {
+ gpl->act_mask += direction;
+ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ }
+ }
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_layer_mask_move(wmOperatorType *ot)
+{
+ static const EnumPropertyItem slot_move[] = {
+ {GP_LAYER_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_LAYER_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Move Grease Pencil Layer Mask";
+ ot->idname = "GPENCIL_OT_layer_mask_move";
+ ot->description = "Move the active Grease Pencil mask layer up/down in the list";
+
+ /* api callbacks */
+ ot->exec = gpencil_layer_mask_move_exec;
+ ot->poll = gpencil_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ ot->prop = RNA_def_enum(ot->srna, "type", slot_move, 0, "Type", "");
+}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index d388e11dc8c..a2a69d94ce9 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -3762,6 +3762,7 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
const eGP_ReprojectModes mode = RNA_enum_get(op->ptr, "type");
const bool keep_original = RNA_boolean_get(op->ptr, "keep_original");
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
/* Init snap context for geometry projection. */
SnapObjectContext *sctx = NULL;
@@ -3774,36 +3775,55 @@ static int gpencil_strokes_reproject_exec(bContext *C, wmOperator *op)
int cfra_prv = INT_MIN;
/* Go through each editable + selected stroke, adjusting each of its points one by one... */
- GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
- bool curve_select = false;
- if (is_curve_edit && gps->editcurve != NULL) {
- curve_select = gps->editcurve->flag & GP_CURVE_SELECT;
- }
+ CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
- if (gps->flag & GP_STROKE_SELECT || curve_select) {
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL) {
+ continue;
+ }
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ bool curve_select = false;
+ if (is_curve_edit && gps->editcurve != NULL) {
+ curve_select = gps->editcurve->flag & GP_CURVE_SELECT;
+ }
- /* update frame to get the new location of objects */
- if ((mode == GP_REPROJECT_SURFACE) && (cfra_prv != gpf_->framenum)) {
- cfra_prv = gpf_->framenum;
- CFRA = gpf_->framenum;
- BKE_scene_graph_update_for_newframe(depsgraph);
- }
+ if (gps->flag & GP_STROKE_SELECT || curve_select) {
- ED_gpencil_stroke_reproject(depsgraph, &gsc, sctx, gpl, gpf_, gps, mode, keep_original);
+ /* update frame to get the new location of objects */
+ if ((mode == GP_REPROJECT_SURFACE) && (cfra_prv != gpf->framenum)) {
+ cfra_prv = gpf->framenum;
+ CFRA = gpf->framenum;
+ BKE_scene_graph_update_for_newframe(depsgraph);
+ }
- if (is_curve_edit && gps->editcurve != NULL) {
- BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
- /* Update the selection from the stroke to the curve. */
- BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve);
+ ED_gpencil_stroke_reproject(depsgraph, &gsc, sctx, gpl, gpf, gps, mode, keep_original);
- gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
- BKE_gpencil_stroke_geometry_update(gpd, gps);
- }
+ if (is_curve_edit && gps->editcurve != NULL) {
+ BKE_gpencil_stroke_editcurve_update(gpd, gpl, gps);
+ /* Update the selection from the stroke to the curve. */
+ BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve);
- changed = true;
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
+ }
+
+ changed = true;
+ /* If not multi-edit, exit loop. */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
}
}
- GP_EDITABLE_STROKES_END(gpstroke_iter);
+ CTX_DATA_END;
/* return frame state and DB to original state */
CFRA = oldframe;
@@ -3832,7 +3852,8 @@ void GPENCIL_OT_reproject(wmOperatorType *ot)
"VIEW",
0,
"View",
- "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint "
+ "Reproject the strokes to end up on the same plane, as if drawn from the current "
+ "viewpoint "
"using 'Cursor' Stroke Placement"},
{GP_REPROJECT_SURFACE,
"SURFACE",
@@ -3851,7 +3872,8 @@ void GPENCIL_OT_reproject(wmOperatorType *ot)
ot->name = "Reproject Strokes";
ot->idname = "GPENCIL_OT_reproject";
ot->description =
- "Reproject the selected strokes from the current viewpoint as if they had been newly drawn "
+ "Reproject the selected strokes from the current viewpoint as if they had been newly "
+ "drawn "
"(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, "
"or for matching deforming geometry)";
@@ -4208,7 +4230,8 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot)
ot->name = "Subdivide Stroke";
ot->idname = "GPENCIL_OT_stroke_subdivide";
ot->description =
- "Subdivide between continuous selected points of the stroke adding a point half way between "
+ "Subdivide between continuous selected points of the stroke adding a point half way "
+ "between "
"them";
/* api callbacks */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index c6f74c39beb..09200125cb7 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -421,6 +421,7 @@ void GPENCIL_OT_layer_duplicate_object(struct wmOperatorType *ot);
void GPENCIL_OT_layer_mask_add(struct wmOperatorType *ot);
void GPENCIL_OT_layer_mask_remove(struct wmOperatorType *ot);
+void GPENCIL_OT_layer_mask_move(struct wmOperatorType *ot);
void GPENCIL_OT_hide(struct wmOperatorType *ot);
void GPENCIL_OT_reveal(struct wmOperatorType *ot);
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index 7ca53779522..0062e363cdf 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -1434,36 +1434,32 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
static void gpencil_interpolate_seq_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
uiLayout *col, *row;
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
const eGP_Interpolate_Type type = RNA_enum_get(op->ptr, "type");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "step", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "step", 0, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "layers", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "layers", 0, NULL, ICON_NONE);
if (CTX_data_mode_enum(C) == CTX_MODE_EDIT_GPENCIL) {
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "interpolate_selected_only", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "interpolate_selected_only", 0, NULL, ICON_NONE);
}
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "flip", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "flip", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, &ptr, "smooth_factor", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "smooth_steps", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "smooth_factor", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "smooth_steps", 0, NULL, ICON_NONE);
row = uiLayoutRow(layout, true);
- uiItemR(row, &ptr, "type", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "type", 0, NULL, ICON_NONE);
if (type == GP_IPO_CURVEMAP) {
/* Get an RNA pointer to ToolSettings to give to the custom curve. */
@@ -1477,16 +1473,16 @@ static void gpencil_interpolate_seq_ui(bContext *C, wmOperator *op)
}
else if (type != GP_IPO_LINEAR) {
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "easing", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "easing", 0, NULL, ICON_NONE);
if (type == GP_IPO_BACK) {
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "back", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "back", 0, NULL, ICON_NONE);
}
else if (type == GP_IPO_ELASTIC) {
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "amplitude", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "amplitude", 0, NULL, ICON_NONE);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "period", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "period", 0, NULL, ICON_NONE);
}
}
}
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 1a6cb5670c4..7d454eb3be1 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -601,6 +601,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_layer_mask_add);
WM_operatortype_append(GPENCIL_OT_layer_mask_remove);
+ WM_operatortype_append(GPENCIL_OT_layer_mask_move);
WM_operatortype_append(GPENCIL_OT_hide);
WM_operatortype_append(GPENCIL_OT_reveal);
diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h
index 58b2cb80bbe..571519e52f7 100644
--- a/source/blender/editors/include/ED_gizmo_library.h
+++ b/source/blender/editors/include/ED_gizmo_library.h
@@ -263,6 +263,11 @@ struct SnapObjectContext *ED_gizmotypes_snap_3d_context_ensure(struct Scene *sce
typedef enum {
ED_SNAPGIZMO_TOGGLE_ALWAYS_TRUE = 1 << 0,
+ ED_SNAPGIZMO_OCCLUSION_ALWAYS_TRUE = 1 << 1,
+ ED_SNAPGIZMO_OCCLUSION_ALWAYS_FALSE = 1 << 2, /* TODO. */
+ ED_SNAPGIZMO_SNAP_ONLY_ACTIVE = 1 << 3,
+ ED_SNAPGIZMO_SNAP_EDIT_GEOM_FINAL = 1 << 4,
+ ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE = 1 << 5,
} eSnapGizmo;
void ED_gizmotypes_snap_3d_flag_set(struct wmGizmo *gz, eSnapGizmo flag);
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 12d6f1fce54..179c9d5b30d 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -511,6 +511,7 @@ bool ED_autokeyframe_property(struct bContext *C,
#define ANIM_KS_ROTATION_ID "Rotation"
#define ANIM_KS_SCALING_ID "Scaling"
#define ANIM_KS_LOC_ROT_SCALE_ID "LocRotScale"
+#define ANIM_KS_LOC_ROT_SCALE_CPROP_ID "LocRotScaleCProp"
#define ANIM_KS_AVAILABLE_ID "Available"
#define ANIM_KS_WHOLE_CHARACTER_ID "WholeCharacter"
#define ANIM_KS_WHOLE_CHARACTER_SELECTED_ID "WholeCharacterSelected"
diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h
index b7174964ef6..42e73bbf744 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -39,12 +39,19 @@ struct View3D;
/* ED_transform_snap_object_*** API */
-typedef enum eSnapSelect {
+typedef enum {
SNAP_ALL = 0,
SNAP_NOT_SELECTED = 1,
SNAP_NOT_ACTIVE = 2,
+ SNAP_ONLY_ACTIVE = 3,
} eSnapSelect;
+typedef enum {
+ SNAP_GEOM_FINAL = 0,
+ SNAP_GEOM_CAGE = 1,
+ SNAP_GEOM_EDIT = 2, /* Bmesh for mesh-type. */
+} eSnapEditType;
+
/** used for storing multiple hits */
struct SnapObjectHitDepth {
struct SnapObjectHitDepth *next, *prev;
@@ -54,7 +61,7 @@ struct SnapObjectHitDepth {
float no[3];
int index;
- struct Object *ob;
+ struct Object *ob_eval;
float obmat[4][4];
/* needed to tell which ray-cast this was part of,
@@ -64,10 +71,10 @@ struct SnapObjectHitDepth {
/** parameters that define which objects will be used to snap. */
struct SnapObjectParams {
- /* special context sensitive handling for the active or selected object */
+ /* Special context sensitive handling for the active or selected object. */
char snap_select;
- /* use editmode cage */
- unsigned int use_object_edit_cage : 1;
+ /* Geometry for snapping in edit mode. */
+ char edit_mode_type;
/* snap to the closest element, use when using more than one snap type */
unsigned int use_occlusion_test : 1;
/* exclude back facing geometry from snapping */
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 81872428038..e0d9971529f 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -186,17 +186,17 @@ enum {
UI_RETURN_POPUP_OK = 1 << 5,
};
-/* but->flag - general state flags. */
+/** #uiBut.flag general state flags. */
enum {
- /** Warning, the first 6 flags are internal. */
- UI_BUT_ICON_SUBMENU = 1 << 6,
- UI_BUT_ICON_PREVIEW = 1 << 7,
+ /* WARNING: the first 7 flags are internal (see #UI_SELECT definition). */
+ UI_BUT_ICON_SUBMENU = 1 << 7,
+ UI_BUT_ICON_PREVIEW = 1 << 8,
- UI_BUT_NODE_LINK = 1 << 8,
- UI_BUT_NODE_ACTIVE = 1 << 9,
- UI_BUT_DRAG_LOCK = 1 << 10,
+ UI_BUT_NODE_LINK = 1 << 9,
+ UI_BUT_NODE_ACTIVE = 1 << 10,
+ UI_BUT_DRAG_LOCK = 1 << 11,
/** Grayed out and un-editable. */
- UI_BUT_DISABLED = 1 << 11,
+ UI_BUT_DISABLED = 1 << 12,
UI_BUT_ANIMATED = 1 << 13,
UI_BUT_ANIMATED_KEY = 1 << 14,
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index a5a5a69728e..4cbf5fca49a 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -1121,6 +1121,12 @@ static void ui_apply_but_NUM(bContext *C, uiBut *but, uiHandleButtonData *data)
data->cancel = true;
return;
}
+
+ /* If the value entered is the exact same, do not trigger an update. */
+ if (data->value == data->startvalue) {
+ data->cancel = true;
+ return;
+ }
}
else {
ui_but_value_set(but, data->value);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 4c96512b4f3..0e465be5bf6 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -77,17 +77,20 @@ struct wmTimer;
/* popover width (multiplied by 'U.widget_unit') */
#define UI_POPOVER_WIDTH_UNITS 10
-/* uiBut->flag */
+/** #uiBut.flag */
enum {
- UI_SELECT = (1 << 0), /* use when the button is pressed */
- UI_SCROLLED = (1 << 1), /* temp hidden, scrolled away */
+ /** Use when the button is pressed. */
+ UI_SELECT = (1 << 0),
+ /** Temporarily hidden (scrolled out of the view). */
+ UI_SCROLLED = (1 << 1),
UI_ACTIVE = (1 << 2),
UI_HAS_ICON = (1 << 3),
UI_HIDDEN = (1 << 4),
- UI_SELECT_DRAW = (1 << 5), /* Display selected, doesn't impact interaction. */
+ /** Display selected, doesn't impact interaction. */
+ UI_SELECT_DRAW = (1 << 5),
/** Property search filter is active and the button does not match. */
- UI_SEARCH_FILTER_NO_MATCH = (1 << 12),
- /* warn: rest of uiBut->flag in UI_interface.h */
+ UI_SEARCH_FILTER_NO_MATCH = (1 << 6),
+ /* WARNING: rest of #uiBut.flag in UI_interface.h */
};
/* uiBut->dragflag */
diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c
index b11a727b173..accfb78ab94 100644
--- a/source/blender/editors/interface/interface_region_tooltip.c
+++ b/source/blender/editors/interface/interface_region_tooltip.c
@@ -947,12 +947,13 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
/* button is disabled, we may be able to tell user why */
if (but->flag & UI_BUT_DISABLED) {
const char *disabled_msg = NULL;
+ bool disabled_msg_free = false;
/* if operator poll check failed, it can give pretty precise info why */
if (but->optype) {
- CTX_wm_operator_poll_msg_set(C, NULL);
+ CTX_wm_operator_poll_msg_clear(C);
WM_operator_poll_context(C, but->optype, but->opcontext);
- disabled_msg = CTX_wm_operator_poll_msg_get(C);
+ disabled_msg = CTX_wm_operator_poll_msg_get(C, &disabled_msg_free);
}
/* alternatively, buttons can store some reasoning too */
else if (but->disabled_info) {
@@ -967,6 +968,9 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but)
});
field->text = BLI_sprintfN(TIP_("Disabled: %s"), disabled_msg);
}
+ if (disabled_msg_free) {
+ MEM_freeN((void *)disabled_msg);
+ }
}
if ((U.flag & USER_TOOLTIPS_PYTHON) && !but->optype && rna_struct.strinfo) {
diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c
index 1f1165a464b..592467c2a85 100644
--- a/source/blender/editors/io/io_alembic.c
+++ b/source/blender/editors/io/io_alembic.c
@@ -240,22 +240,17 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr)
static void wm_alembic_export_draw(bContext *C, wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
/* Conveniently set start and end frame to match the scene's frame range. */
Scene *scene = CTX_data_scene(C);
- if (scene != NULL && RNA_boolean_get(&ptr, "init_scene_frame_range")) {
- RNA_int_set(&ptr, "start", SFRA);
- RNA_int_set(&ptr, "end", EFRA);
+ if (scene != NULL && RNA_boolean_get(op->ptr, "init_scene_frame_range")) {
+ RNA_int_set(op->ptr, "start", SFRA);
+ RNA_int_set(op->ptr, "end", EFRA);
- RNA_boolean_set(&ptr, "init_scene_frame_range", false);
+ RNA_boolean_set(op->ptr, "init_scene_frame_range", false);
}
- ui_alembic_export_settings(op->layout, &ptr);
+ ui_alembic_export_settings(op->layout, op->ptr);
}
static bool wm_alembic_export_check(bContext *UNUSED(C), wmOperator *op)
@@ -594,13 +589,9 @@ static void ui_alembic_import_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(col, imfptr, "validate_meshes", 0, NULL, ICON_NONE);
}
-static void wm_alembic_import_draw(bContext *C, wmOperator *op)
+static void wm_alembic_import_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- ui_alembic_import_settings(op->layout, &ptr);
+ ui_alembic_import_settings(op->layout, op->ptr);
}
/* op->invoke, opens fileselect if path property not set, otherwise executes */
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index c8e3e1814fc..859c12d7e52 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -400,13 +400,9 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
}
}
-static void wm_collada_export_draw(bContext *C, wmOperator *op)
+static void wm_collada_export_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- uiCollada_exportSettings(op->layout, &ptr);
+ uiCollada_exportSettings(op->layout, op->ptr);
}
static bool wm_collada_export_check(bContext *UNUSED(C), wmOperator *op)
@@ -798,13 +794,9 @@ static void uiCollada_importSettings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(box, imfptr, "keep_bind_info", 0, NULL, ICON_NONE);
}
-static void wm_collada_import_draw(bContext *C, wmOperator *op)
+static void wm_collada_import_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- uiCollada_importSettings(op->layout, &ptr);
+ uiCollada_importSettings(op->layout, op->ptr);
}
void WM_OT_collada_import(wmOperatorType *ot)
diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c
index 7b4b59902f9..b49be324372 100644
--- a/source/blender/editors/io/io_gpencil_export.c
+++ b/source/blender/editors/io/io_gpencil_export.c
@@ -215,14 +215,9 @@ static void ui_gpencil_export_svg_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(col, imfptr, "use_clip_camera", 0, NULL, ICON_NONE);
}
-static void wm_gpencil_export_svg_draw(bContext *C, wmOperator *op)
+static void wm_gpencil_export_svg_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- ui_gpencil_export_svg_settings(op->layout, &ptr);
+ ui_gpencil_export_svg_settings(op->layout, op->ptr);
}
static bool wm_gpencil_export_svg_poll(bContext *C)
@@ -378,14 +373,9 @@ static void ui_gpencil_export_pdf_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(sub, imfptr, "use_normalized_thickness", 0, NULL, ICON_NONE);
}
-static void wm_gpencil_export_pdf_draw(bContext *C, wmOperator *op)
+static void wm_gpencil_export_pdf_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- ui_gpencil_export_pdf_settings(op->layout, &ptr);
+ ui_gpencil_export_pdf_settings(op->layout, op->ptr);
}
static bool wm_gpencil_export_pdf_poll(bContext *C)
diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c
index e4fabc0c5de..a9911f1cef2 100644
--- a/source/blender/editors/io/io_gpencil_import.c
+++ b/source/blender/editors/io/io_gpencil_import.c
@@ -136,13 +136,9 @@ static void ui_gpencil_import_svg_settings(uiLayout *layout, PointerRNA *imfptr)
uiItemR(col, imfptr, "scale", 0, NULL, ICON_NONE);
}
-static void wm_gpencil_import_svg_draw(bContext *C, wmOperator *op)
+static void wm_gpencil_import_svg_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- ui_gpencil_import_svg_settings(op->layout, &ptr);
+ ui_gpencil_import_svg_settings(op->layout, op->ptr);
}
static bool wm_gpencil_import_svg_poll(bContext *C)
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 51190268c4c..43492cd57af 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -911,76 +911,73 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void edbm_bevel_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
uiLayout *col, *row;
- PointerRNA ptr, toolsettings_ptr;
+ PointerRNA toolsettings_ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- int profile_type = RNA_enum_get(&ptr, "profile_type");
- int offset_type = RNA_enum_get(&ptr, "offset_type");
- bool affect_type = RNA_enum_get(&ptr, "affect");
+ int profile_type = RNA_enum_get(op->ptr, "profile_type");
+ int offset_type = RNA_enum_get(op->ptr, "offset_type");
+ bool affect_type = RNA_enum_get(op->ptr, "affect");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "affect", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "affect", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
- uiItemR(layout, &ptr, "offset_type", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "offset_type", 0, NULL, ICON_NONE);
if (offset_type == BEVEL_AMT_PERCENT) {
- uiItemR(layout, &ptr, "offset_pct", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "offset_pct", 0, NULL, ICON_NONE);
}
else {
- uiItemR(layout, &ptr, "offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "offset", 0, NULL, ICON_NONE);
}
- uiItemR(layout, &ptr, "segments", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "segments", 0, NULL, ICON_NONE);
if (ELEM(profile_type, BEVEL_PROFILE_SUPERELLIPSE, BEVEL_PROFILE_CUSTOM)) {
uiItemR(layout,
- &ptr,
+ op->ptr,
"profile",
UI_ITEM_R_SLIDER,
(profile_type == BEVEL_PROFILE_SUPERELLIPSE) ? IFACE_("Shape") : IFACE_("Miter Shape"),
ICON_NONE);
}
- uiItemR(layout, &ptr, "material", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "material", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, true);
- uiItemR(col, &ptr, "harden_normals", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "clamp_overlap", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "loop_slide", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "harden_normals", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "clamp_overlap", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "loop_slide", 0, NULL, ICON_NONE);
col = uiLayoutColumnWithHeading(layout, true, IFACE_("Mark"));
uiLayoutSetActive(col, affect_type == BEVEL_AFFECT_EDGES);
- uiItemR(col, &ptr, "mark_seam", 0, IFACE_("Seams"), ICON_NONE);
- uiItemR(col, &ptr, "mark_sharp", 0, IFACE_("Sharp"), ICON_NONE);
+ uiItemR(col, op->ptr, "mark_seam", 0, IFACE_("Seams"), ICON_NONE);
+ uiItemR(col, op->ptr, "mark_sharp", 0, IFACE_("Sharp"), ICON_NONE);
uiItemS(layout);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, affect_type == BEVEL_AFFECT_EDGES);
- uiItemR(col, &ptr, "miter_outer", 0, IFACE_("Miter Outer"), ICON_NONE);
- uiItemR(col, &ptr, "miter_inner", 0, IFACE_("Inner"), ICON_NONE);
- if (RNA_enum_get(&ptr, "miter_inner") == BEVEL_MITER_ARC) {
- uiItemR(col, &ptr, "spread", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "miter_outer", 0, IFACE_("Miter Outer"), ICON_NONE);
+ uiItemR(col, op->ptr, "miter_inner", 0, IFACE_("Inner"), ICON_NONE);
+ if (RNA_enum_get(op->ptr, "miter_inner") == BEVEL_MITER_ARC) {
+ uiItemR(col, op->ptr, "spread", 0, NULL, ICON_NONE);
}
uiItemS(layout);
col = uiLayoutColumn(layout, false);
uiLayoutSetActive(col, affect_type == BEVEL_AFFECT_EDGES);
- uiItemR(col, &ptr, "vmesh_method", 0, IFACE_("Intersection Type"), ICON_NONE);
+ uiItemR(col, op->ptr, "vmesh_method", 0, IFACE_("Intersection Type"), ICON_NONE);
- uiItemR(layout, &ptr, "face_strength_mode", 0, IFACE_("Face Strength"), ICON_NONE);
+ uiItemR(layout, op->ptr, "face_strength_mode", 0, IFACE_("Face Strength"), ICON_NONE);
uiItemS(layout);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "profile_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "profile_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
if (profile_type == BEVEL_PROFILE_CUSTOM) {
/* Get an RNA pointer to ToolSettings to give to the curve profile template code. */
Scene *scene = CTX_data_scene(C);
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
index 141f120396a..d1f228e951a 100644
--- a/source/blender/editors/mesh/editmesh_intersect.c
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -251,32 +251,28 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void edbm_intersect_ui(bContext *C, wmOperator *op)
+static void edbm_intersect_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
uiLayout *row;
- PointerRNA ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- bool use_exact = RNA_enum_get(&ptr, "solver") == ISECT_SOLVER_EXACT;
+ bool use_exact = RNA_enum_get(op->ptr, "solver") == ISECT_SOLVER_EXACT;
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "separate_mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "separate_mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
if (!use_exact) {
- uiItemR(layout, &ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "threshold", 0, NULL, ICON_NONE);
}
}
@@ -418,32 +414,28 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void edbm_intersect_boolean_ui(bContext *C, wmOperator *op)
+static void edbm_intersect_boolean_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
uiLayout *row;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- bool use_exact = RNA_enum_get(&ptr, "solver") == ISECT_SOLVER_EXACT;
+ bool use_exact = RNA_enum_get(op->ptr, "solver") == ISECT_SOLVER_EXACT;
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "operation", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "operation", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
uiItemS(layout);
- uiItemR(layout, &ptr, "use_swap", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "use_self", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "use_swap", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "use_self", 0, NULL, ICON_NONE);
if (!use_exact) {
- uiItemR(layout, &ptr, "threshold", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "threshold", 0, NULL, ICON_NONE);
}
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 33e4691bfb5..bb332a4094c 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3694,21 +3694,18 @@ static const EnumPropertyItem *shape_itemf(bContext *C,
static void edbm_blend_from_shape_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
Object *obedit = CTX_data_edit_object(C);
Mesh *me = obedit->data;
PointerRNA ptr_key;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
RNA_id_pointer_create((ID *)me->key, &ptr_key);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
- uiItemPointerR(layout, &ptr, "shape", &ptr_key, "key_blocks", NULL, ICON_SHAPEKEY_DATA);
- uiItemR(layout, &ptr, "blend", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "add", 0, NULL, ICON_NONE);
+ uiItemPointerR(layout, op->ptr, "shape", &ptr_key, "key_blocks", NULL, ICON_SHAPEKEY_DATA);
+ uiItemR(layout, op->ptr, "blend", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "add", 0, NULL, ICON_NONE);
}
void MESH_OT_blend_from_shape(wmOperatorType *ot)
@@ -5612,29 +5609,25 @@ static bool edbm_decimate_check(bContext *UNUSED(C), wmOperator *UNUSED(op))
return true;
}
-static void edbm_decimate_ui(bContext *C, wmOperator *op)
+static void edbm_decimate_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout, *row, *col, *sub;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiLayoutSetPropSep(layout, true);
- uiItemR(layout, &ptr, "ratio", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "ratio", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "use_vertex_group", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "use_vertex_group", 0, NULL, ICON_NONE);
col = uiLayoutColumn(layout, false);
- uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_vertex_group"));
- uiItemR(col, &ptr, "vertex_group_factor", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "invert_vertex_group", 0, NULL, ICON_NONE);
+ uiLayoutSetActive(col, RNA_boolean_get(op->ptr, "use_vertex_group"));
+ uiItemR(col, op->ptr, "vertex_group_factor", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "invert_vertex_group", 0, NULL, ICON_NONE);
row = uiLayoutRowWithHeading(layout, true, IFACE_("Symmetry"));
- uiItemR(row, &ptr, "use_symmetry", 0, "", ICON_NONE);
+ uiItemR(row, op->ptr, "use_symmetry", 0, "", ICON_NONE);
sub = uiLayoutRow(row, true);
- uiLayoutSetActive(sub, RNA_boolean_get(&ptr, "use_symmetry"));
- uiItemR(sub, &ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiLayoutSetActive(sub, RNA_boolean_get(op->ptr, "use_symmetry"));
+ uiItemR(sub, op->ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
}
void MESH_OT_decimate(wmOperatorType *ot)
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 2e98f0558f3..19c9909039c 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -1721,7 +1721,7 @@ void EDBM_project_snap_verts(
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_NOT_ACTIVE,
- .use_object_edit_cage = false,
+ .edit_mode_type = SNAP_GEOM_FINAL,
.use_occlusion_test = true,
},
mval,
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index bcddf3d585c..a0de1e0fa84 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -3110,24 +3110,21 @@ static int object_convert_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void object_convert_ui(bContext *C, wmOperator *op)
+static void object_convert_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
uiLayoutSetPropSep(layout, true);
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
- uiItemR(layout, &ptr, "target", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "keep_original", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "target", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "keep_original", 0, NULL, ICON_NONE);
- if (RNA_enum_get(&ptr, "target") == OB_GPENCIL) {
- uiItemR(layout, &ptr, "thickness", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "angle", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "offset", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "seams", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "faces", 0, NULL, ICON_NONE);
+ if (RNA_enum_get(op->ptr, "target") == OB_GPENCIL) {
+ uiItemR(layout, op->ptr, "thickness", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "angle", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "offset", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "seams", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "faces", 0, NULL, ICON_NONE);
}
}
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 3df63d423e2..6df96b1e30f 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -199,10 +199,9 @@ static bool screenshot_draw_check_prop(PointerRNA *UNUSED(ptr),
return !(STREQ(prop_id, "filepath"));
}
-static void screenshot_draw(bContext *C, wmOperator *op)
+static void screenshot_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
ScreenshotData *scd = op->customdata;
uiLayoutSetPropSep(layout, true);
@@ -214,9 +213,8 @@ static void screenshot_draw(bContext *C, wmOperator *op)
uiTemplateImageSettings(layout, &ptr, false);
/* main draw call */
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, screenshot_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, op->ptr, screenshot_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
}
static bool screenshot_poll(bContext *C)
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 83dd5098a30..6053253790a 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1479,18 +1479,16 @@ static bool image_open_draw_check_prop(PointerRNA *UNUSED(ptr),
return !(STR_ELEM(prop_id, "filepath", "directory", "filename"));
}
-static void image_open_draw(bContext *C, wmOperator *op)
+static void image_open_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
ImageOpenData *iod = op->customdata;
ImageFormatData *imf = &iod->im_format;
- PointerRNA imf_ptr, ptr;
+ PointerRNA imf_ptr;
/* main draw call */
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, image_open_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, op->ptr, image_open_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
/* image template */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
@@ -2001,12 +1999,11 @@ static bool image_save_as_draw_check_prop(PointerRNA *ptr,
((STREQ(prop_id, "relative_path")) && RNA_boolean_get(ptr, "copy")));
}
-static void image_save_as_draw(bContext *C, wmOperator *op)
+static void image_save_as_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
ImageSaveData *isd = op->customdata;
- PointerRNA imf_ptr, ptr;
+ PointerRNA imf_ptr;
const bool is_multiview = RNA_boolean_get(op->ptr, "show_multiview");
/* image template */
@@ -2014,9 +2011,8 @@ static void image_save_as_draw(bContext *C, wmOperator *op)
uiTemplateImageSettings(layout, &imf_ptr, false);
/* main draw call */
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, op->ptr, image_save_as_draw_check_prop, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
/* multiview template */
if (is_multiview) {
@@ -2614,38 +2610,34 @@ static int image_new_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
return WM_operator_props_dialog_popup(C, op, 300);
}
-static void image_new_draw(bContext *C, wmOperator *op)
+static void image_new_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *col;
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
#if 0
Scene *scene = CTX_data_scene(C);
const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
#endif
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
/* copy of WM_operator_props_dialog_popup() layout */
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
col = uiLayoutColumn(layout, false);
- uiItemR(col, &ptr, "name", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "width", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "height", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "color", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "alpha", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "generated_type", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "float", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "tiled", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "name", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "width", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "height", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "color", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "alpha", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "generated_type", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "float", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "tiled", 0, NULL, ICON_NONE);
#if 0
if (is_multiview) {
uiItemL(col[0], "", ICON_NONE);
- uiItemR(col[1], &ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
+ uiItemR(col[1], op->ptr, "use_stereo_3d", 0, NULL, ICON_NONE);
}
#endif
}
@@ -3991,26 +3983,22 @@ static int tile_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(ev
return WM_operator_props_dialog_popup(C, op, 300);
}
-static void tile_add_draw(bContext *C, wmOperator *op)
+static void tile_add_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *col;
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
-
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
col = uiLayoutColumn(layout, false);
- uiItemR(col, &ptr, "number", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "count", 0, NULL, ICON_NONE);
- uiItemR(col, &ptr, "label", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "fill", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "number", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "count", 0, NULL, ICON_NONE);
+ uiItemR(col, op->ptr, "label", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "fill", 0, NULL, ICON_NONE);
- if (RNA_boolean_get(&ptr, "fill")) {
- draw_fill_tile(&ptr, layout);
+ if (RNA_boolean_get(op->ptr, "fill")) {
+ draw_fill_tile(op->ptr, layout);
}
}
@@ -4128,13 +4116,9 @@ static int tile_fill_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(e
return WM_operator_props_dialog_popup(C, op, 300);
}
-static void tile_fill_draw(bContext *C, wmOperator *op)
+static void tile_fill_draw(bContext *UNUSED(C), wmOperator *op)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- PointerRNA ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
- draw_fill_tile(&ptr, op->layout);
+ draw_fill_tile(op->ptr, op->layout);
}
void IMAGE_OT_tile_fill(wmOperatorType *ot)
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 0b0c43d3417..c4fd0dd5d73 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -729,18 +729,16 @@ static int sequencer_add_movie_strip_invoke(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
-static void sequencer_add_draw(bContext *C, wmOperator *op)
+static void sequencer_add_draw(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
SequencerAddData *sad = op->customdata;
ImageFormatData *imf = &sad->im_format;
- PointerRNA imf_ptr, ptr;
+ PointerRNA imf_ptr;
/* Main draw call. */
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
uiDefAutoButsRNA(
- layout, &ptr, sequencer_add_draw_check_fn, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
+ layout, op->ptr, sequencer_add_draw_check_fn, NULL, NULL, UI_BUT_LABEL_ALIGN_NONE, false);
/* Image template. */
RNA_pointer_create(NULL, &RNA_ImageFormatSettings, imf, &imf_ptr);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 5d616969a4f..52cfeeecb5c 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1485,26 +1485,22 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev
return sequencer_split_exec(C, op);
}
-static void sequencer_split_ui(bContext *C, wmOperator *op)
+static void sequencer_split_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
- wmWindowManager *wm = CTX_wm_manager(C);
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
- PointerRNA ptr;
- RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-
uiLayout *row = uiLayoutRow(layout, false);
- uiItemR(row, &ptr, "type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "frame", 0, NULL, ICON_NONE);
- uiItemR(layout, &ptr, "side", 0, NULL, ICON_NONE);
+ uiItemR(row, op->ptr, "type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "frame", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "side", 0, NULL, ICON_NONE);
uiItemS(layout);
- uiItemR(layout, &ptr, "use_cursor_position", 0, NULL, ICON_NONE);
- if (RNA_boolean_get(&ptr, "use_cursor_position")) {
- uiItemR(layout, &ptr, "channel", 0, NULL, ICON_NONE);
+ uiItemR(layout, op->ptr, "use_cursor_position", 0, NULL, ICON_NONE);
+ if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
+ uiItemR(layout, op->ptr, "channel", 0, NULL, ICON_NONE);
}
}
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index 190f50ed443..26f89a0700e 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -256,7 +256,7 @@ static std::unique_ptr<DataSource> get_data_source(const bContext *C)
return {};
}
Object *object_orig = (Object *)used_id;
- if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD)) {
+ if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD, OB_VOLUME)) {
return {};
}
Object *object_eval = DEG_get_evaluated_object(depsgraph, object_orig);
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
index 520d29ce306..405f0cd9455 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -78,24 +78,25 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
{
std::lock_guard lock{mutex_};
- bke::ReadAttributePtr attribute_ptr = component_->attribute_try_get_for_read(column_id.name);
- if (!attribute_ptr) {
+ bke::ReadAttributeLookup attribute = component_->attribute_try_get_for_read(column_id.name);
+ if (!attribute) {
return {};
}
- const bke::ReadAttribute *attribute = scope_.add(std::move(attribute_ptr), __func__);
- if (attribute->domain() != domain_) {
+ const fn::GVArray *varray = scope_.add(std::move(attribute.varray), __func__);
+ if (attribute.domain != domain_) {
return {};
}
- int domain_size = attribute->size();
- switch (attribute->custom_data_type()) {
+ int domain_size = varray->size();
+ const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type());
+ switch (type) {
case CD_PROP_FLOAT:
if (column_id.index != -1) {
return {};
}
return column_values_from_function(
- column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
+ column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
float value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_float = value;
});
case CD_PROP_INT32:
@@ -103,9 +104,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return {};
}
return column_values_from_function(
- column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
+ column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
int value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_int = value;
});
case CD_PROP_BOOL:
@@ -113,9 +114,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
return {};
}
return column_values_from_function(
- column_id.name, domain_size, [attribute](int index, CellValue &r_cell_value) {
+ column_id.name, domain_size, [varray](int index, CellValue &r_cell_value) {
bool value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_bool = value;
});
case CD_PROP_FLOAT2: {
@@ -125,11 +126,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const std::array<const char *, 2> suffixes = {" X", " Y"};
const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
return column_values_from_function(
- name,
- domain_size,
- [attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
+ name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) {
float2 value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_float = value[axis];
});
}
@@ -140,11 +139,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const std::array<const char *, 3> suffixes = {" X", " Y", " Z"};
const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
return column_values_from_function(
- name,
- domain_size,
- [attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
+ name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) {
float3 value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_float = value[axis];
});
}
@@ -155,11 +152,9 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
const std::array<const char *, 4> suffixes = {" R", " G", " B", " A"};
const std::string name = StringRef(column_id.name) + suffixes[column_id.index];
return column_values_from_function(
- name,
- domain_size,
- [attribute, axis = column_id.index](int index, CellValue &r_cell_value) {
+ name, domain_size, [varray, axis = column_id.index](int index, CellValue &r_cell_value) {
Color4f value;
- attribute->get(index, &value);
+ varray->get(index, &value);
r_cell_value.value_float = value[axis];
});
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 5f3d71cc190..358373ea4d1 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -5065,7 +5065,7 @@ void ED_view3d_cursor3d_position_rotation(bContext *C,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = false,
+ .edit_mode_type = SNAP_GEOM_FINAL,
.use_occlusion_test = true,
},
mval_fl,
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index e202276831c..3134553c159 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -338,7 +338,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_CAGE,
},
mval_fl,
NULL,
@@ -352,7 +352,7 @@ static bool view3d_ruler_item_mousemove(struct Depsgraph *depsgraph,
depsgraph,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_CAGE,
},
ray_start,
ray_normal,
@@ -1124,12 +1124,13 @@ static void WIDGETGROUP_ruler_setup(const bContext *C, wmGizmoGroup *gzgroup)
const wmGizmoType *gzt_snap;
gzt_snap = WM_gizmotype_find("GIZMO_GT_snap_3d", true);
gizmo = WM_gizmo_new_ptr(gzt_snap, gzgroup, NULL);
+
RNA_enum_set(gizmo->ptr,
"snap_elements_force",
(SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE |
/* SCE_SNAP_MODE_VOLUME | SCE_SNAP_MODE_GRID | SCE_SNAP_MODE_INCREMENT | */
SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT));
-
+ ED_gizmotypes_snap_3d_flag_set(gizmo, ED_SNAPGIZMO_SNAP_EDIT_GEOM_CAGE);
WM_gizmo_set_color(gizmo, (float[4]){1.0f, 1.0f, 1.0f, 1.0f});
wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_ruler_add", true);
diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c
index 7347e528edc..1afdcdd2993 100644
--- a/source/blender/editors/space_view3d/view3d_placement.c
+++ b/source/blender/editors/space_view3d/view3d_placement.c
@@ -323,7 +323,7 @@ static bool idp_poject_surface_normal(SnapObjectContext *snap_context,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_EDIT,
},
mval_fl,
NULL,
@@ -941,7 +941,7 @@ static void view3d_interactive_add_calc_plane(bContext *C,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_EDIT,
},
mval_fl,
NULL,
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index cbd65e3175d..ab4cf0c2135 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -407,7 +407,7 @@ static bool walk_floor_distance_get(RegionView3D *rv3d,
&(const struct SnapObjectParams){
.snap_select = SNAP_ALL,
/* Avoid having to convert the edit-mesh to a regular mesh. */
- .use_object_edit_cage = true,
+ .edit_mode_type = SNAP_GEOM_EDIT,
},
ray_start,
ray_normal,
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index d0f91802fff..193954fffb6 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -345,7 +345,7 @@ void applyProject(TransInfo *t)
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
- .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
.use_occlusion_test = false,
.use_backface_culling = t->tsnap.use_backface_culling,
},
@@ -1167,7 +1167,7 @@ short snapObjectsTransform(
t->settings->snap_mode,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
- .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
.use_occlusion_test = t->settings->snap_mode != SCE_SNAP_MODE_FACE,
.use_backface_culling = t->tsnap.use_backface_culling,
},
@@ -1201,7 +1201,7 @@ bool peelObjectsTransform(TransInfo *t,
t->depsgraph,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
- .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL,
},
mval,
-1.0f,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index ec98b6af169..3277baeba5b 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -43,6 +43,7 @@
#include "BKE_curve.h"
#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
+#include "BKE_global.h"
#include "BKE_layer.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
@@ -144,9 +145,37 @@ struct SnapObjectContext {
/** \name Utilities
* \{ */
-static bool editmesh_eval_final_is_bmesh(const BMEditMesh *em)
+/* Mesh used for snapping.
+ * If NULL the BMesh should be used. */
+static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide)
{
- return (em->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH);
+ Mesh *me_eval = ob_eval->data;
+ bool use_hide = false;
+ if (BKE_object_is_in_editmode(ob_eval)) {
+ if (edit_mode_type == SNAP_GEOM_EDIT) {
+ return NULL;
+ }
+
+ BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
+ if ((edit_mode_type == SNAP_GEOM_FINAL) && em_eval->mesh_eval_final) {
+ if (em_eval->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ return NULL;
+ }
+ me_eval = em_eval->mesh_eval_final;
+ use_hide = true;
+ }
+ else if ((edit_mode_type == SNAP_GEOM_CAGE) && em_eval->mesh_eval_cage) {
+ if (em_eval->mesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) {
+ return NULL;
+ }
+ me_eval = em_eval->mesh_eval_cage;
+ use_hide = true;
+ }
+ }
+ if (r_use_hide) {
+ *r_use_hide = use_hide;
+ }
+ return me_eval;
}
/** \} */
@@ -208,30 +237,69 @@ static void snap_object_data_clear(SnapObjectData *sod)
memset(&sod->type, 0x0, sizeof(*sod) - offsetof(SnapObjectData, type));
}
-static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob)
+static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob_eval)
{
- SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
+ SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob_eval);
if (sod == NULL) {
if (sctx->cache.data_to_object_map != NULL) {
- ob = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob->data);
+ ob_eval = BLI_ghash_lookup(sctx->cache.data_to_object_map, ob_eval->data);
/* Could be NULl when mixing edit-mode and non edit-mode objects. */
- if (ob != NULL) {
- sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
+ if (ob_eval != NULL) {
+ sod = BLI_ghash_lookup(sctx->cache.object_map, ob_eval);
}
}
}
return sod;
}
-static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob)
+static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx,
+ Object *ob_eval,
+ Mesh *me_eval,
+ bool use_hide)
{
SnapObjectData *sod;
void **sod_p;
bool init = false;
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob_eval, &sod_p)) {
sod = *sod_p;
+ bool is_dirty = false;
if (sod->type != SNAP_MESH) {
+ is_dirty = true;
+ }
+ else if (sod->treedata_mesh.tree && sod->treedata_mesh.cached &&
+ !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->treedata_mesh.tree)) {
+ /* The tree is owned by the Mesh and may have been freed since we last used. */
+ is_dirty = true;
+ }
+ else if (sod->bvhtree[0] && sod->cached[0] &&
+ !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[0])) {
+ /* The tree is owned by the Mesh and may have been freed since we last used. */
+ is_dirty = true;
+ }
+ else if (sod->bvhtree[1] && sod->cached[1] &&
+ !bvhcache_has_tree(me_eval->runtime.bvh_cache, sod->bvhtree[1])) {
+ /* The tree is owned by the Mesh and may have been freed since we last used. */
+ is_dirty = true;
+ }
+ else if (!sod->treedata_mesh.looptri_allocated &&
+ sod->treedata_mesh.looptri != me_eval->runtime.looptris.array) {
+ is_dirty = true;
+ }
+ else if (!sod->treedata_mesh.vert_allocated && sod->treedata_mesh.vert != me_eval->mvert) {
+ is_dirty = true;
+ }
+ else if (!sod->treedata_mesh.loop_allocated && sod->treedata_mesh.loop != me_eval->mloop) {
+ is_dirty = true;
+ }
+ else if (!sod->treedata_mesh.edge_allocated && sod->treedata_mesh.edge != me_eval->medge) {
+ is_dirty = true;
+ }
+ else if (sod->poly != me_eval->mpoly) {
+ is_dirty = true;
+ }
+
+ if (is_dirty) {
snap_object_data_clear(sod);
init = true;
}
@@ -243,8 +311,32 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object
if (init) {
sod->type = SNAP_MESH;
- /* start assuming that it has each of these element types */
- sod->has_looptris = true;
+
+ /* The BVHTree from looptris is always required. */
+ BLI_assert(sod->treedata_mesh.tree == NULL);
+ BKE_bvhtree_from_mesh_get(&sod->treedata_mesh,
+ me_eval,
+ use_hide ? BVHTREE_FROM_LOOPTRI_NO_HIDDEN : BVHTREE_FROM_LOOPTRI,
+ 4);
+
+ if (sod->treedata_mesh.tree == NULL) {
+ sod->treedata_mesh.vert = me_eval->mvert;
+ sod->treedata_mesh.loop = me_eval->mloop;
+ sod->treedata_mesh.looptri = BKE_mesh_runtime_looptri_ensure(me_eval);
+ BLI_assert(sod->has_looptris == false);
+ }
+ else {
+ BLI_assert(sod->treedata_mesh.vert != NULL);
+ BLI_assert(sod->treedata_mesh.loop != NULL);
+ BLI_assert(sod->treedata_mesh.looptri != NULL);
+ sod->has_looptris = true;
+ }
+
+ /* Required for snapping with occlusion. */
+ sod->treedata_mesh.edge = me_eval->medge;
+ sod->poly = me_eval->mpoly;
+
+ /* Start assuming that it has each of these element types. */
sod->has_loose_edge = true;
sod->has_loose_vert = true;
}
@@ -252,26 +344,26 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object
return sod;
}
-static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob)
+static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval)
{
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- if (em->mesh_eval_final) {
- return &em->mesh_eval_final->runtime;
+ BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval);
+ if (em_eval->mesh_eval_final) {
+ return &em_eval->mesh_eval_final->runtime;
}
- if (em->mesh_eval_cage) {
- return &em->mesh_eval_cage->runtime;
+ if (em_eval->mesh_eval_cage) {
+ return &em_eval->mesh_eval_cage->runtime;
}
- return &((Mesh *)ob->data)->runtime;
+ return &((Mesh *)ob_eval->data)->runtime;
}
static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
- Object *ob,
+ Object *ob_eval,
BMEditMesh *em)
{
SnapObjectData *sod;
void **sod_p;
- bool init = false, init_min_max = true, clear_cache = false;
+ bool init = false;
{
/* Use object-data as the key in ghash since the editmesh
@@ -280,48 +372,53 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
sctx->cache.data_to_object_map = BLI_ghash_ptr_new(__func__);
}
void **ob_p;
- if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob->data, &ob_p)) {
- ob = *ob_p;
+ if (BLI_ghash_ensure_p(sctx->cache.data_to_object_map, ob_eval->data, &ob_p)) {
+ ob_eval = *ob_p;
}
else {
- *ob_p = ob;
+ *ob_p = ob_eval;
}
}
- if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
+ if (BLI_ghash_ensure_p(sctx->cache.object_map, ob_eval, &sod_p)) {
sod = *sod_p;
- bool clear = false;
+ bool is_dirty = false;
/* Check if the geometry has changed. */
if (sod->type != SNAP_EDIT_MESH) {
- clear = true;
+ is_dirty = true;
}
else if (sod->treedata_editmesh.em != em) {
- clear_cache = true;
- init = true;
+ is_dirty = true;
}
else if (sod->mesh_runtime) {
- if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob)) {
- clear_cache = true;
- init = true;
+ if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob_eval)) {
+ if (G.moving) {
+ /* Hack to avoid updating while transforming. */
+ BLI_assert(!sod->treedata_editmesh.cached && !sod->cached[0] && !sod->cached[1]);
+ sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval);
+ }
+ else {
+ is_dirty = true;
+ }
}
else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached &&
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
- clear = true;
+ is_dirty = true;
}
else if (sod->bvhtree[0] && sod->cached[0] &&
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
- clear = true;
+ is_dirty = true;
}
else if (sod->bvhtree[1] && sod->cached[1] &&
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
- clear = true;
+ is_dirty = true;
}
}
- if (clear) {
+ if (is_dirty) {
snap_object_data_clear(sod);
init = true;
}
@@ -334,27 +431,8 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
if (init) {
sod->type = SNAP_EDIT_MESH;
sod->treedata_editmesh.em = em;
-
- if (clear_cache) {
- /* Only init min and max when you have a non-custom bvhtree pending. */
- init_min_max = false;
- if (sod->treedata_editmesh.cached) {
- sod->treedata_editmesh.tree = NULL;
- init_min_max = true;
- }
- for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) {
- if (sod->cached[i]) {
- sod->bvhtree[i] = NULL;
- init_min_max = true;
- }
- }
- }
-
- if (init_min_max) {
- bm_mesh_minmax(em->bm, sod->min, sod->max);
- }
-
- sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob);
+ sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob_eval);
+ bm_mesh_minmax(em->bm, sod->min, sod->max);
}
return sod;
@@ -367,9 +445,9 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
* \{ */
typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
- Object *ob,
+ Object *ob_eval,
float obmat[4][4],
- bool use_obedit,
+ eSnapEditType edit_mode_type,
bool use_backface_culling,
bool is_object_active,
void *data);
@@ -386,10 +464,17 @@ static void iter_snap_objects(SnapObjectContext *sctx,
ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
const View3D *v3d = sctx->v3d_data.v3d;
const eSnapSelect snap_select = params->snap_select;
- const bool use_object_edit_cage = params->use_object_edit_cage;
+ const eSnapEditType edit_mode_type = params->edit_mode_type;
const bool use_backface_culling = params->use_backface_culling;
Base *base_act = view_layer->basact;
+ if (snap_select == SNAP_ONLY_ACTIVE) {
+ Object *obj_eval = DEG_get_evaluated_object(depsgraph, base_act->object);
+ sob_callback(
+ sctx, obj_eval, obj_eval->obmat, edit_mode_type, use_backface_culling, true, data);
+ return;
+ }
+
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
if (!BASE_VISIBLE(v3d, base)) {
continue;
@@ -422,7 +507,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
sob_callback(sctx,
dupli_ob->ob,
dupli_ob->mat,
- use_object_edit_cage,
+ edit_mode_type,
use_backface_culling,
is_object_active,
data);
@@ -433,7 +518,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
sob_callback(sctx,
obj_eval,
obj_eval->obmat,
- use_object_edit_cage,
+ edit_mode_type,
use_backface_culling,
is_object_active,
data);
@@ -461,7 +546,7 @@ struct RayCastAll_Data {
float len_diff;
float local_scale;
- Object *ob;
+ Object *ob_eval;
uint ob_uuid;
/* output data */
@@ -473,7 +558,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth,
const float co[3],
const float no[3],
int index,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
uint ob_uuid)
{
@@ -484,7 +569,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth,
copy_v3_v3(hit->no, no);
hit->index = index;
- hit->ob = ob;
+ hit->ob_eval = ob_eval;
copy_m4_m4(hit->obmat, (float(*)[4])obmat);
hit->ob_uuid = ob_uuid;
@@ -526,7 +611,7 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
normalize_v3(normal);
struct SnapObjectHitDepth *hit_item = hit_depth_create(
- depth, location, normal, hit->index, data->ob, data->obmat, data->ob_uuid);
+ depth, location, normal, hit->index, data->ob_eval, data->obmat, data->ob_uuid);
BLI_addtail(data->hit_list, hit_item);
}
}
@@ -598,8 +683,8 @@ static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
static bool raycastMesh(SnapObjectContext *sctx,
const float ray_start[3],
const float ray_dir[3],
- Object *ob,
- Mesh *me,
+ Object *ob_eval,
+ Mesh *me_eval,
const float obmat[4][4],
const uint ob_index,
bool use_hide,
@@ -614,7 +699,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
{
bool retval = false;
- if (me->totpoly == 0) {
+ if (me_eval->totpoly == 0) {
return retval;
}
@@ -638,7 +723,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
}
/* Test BoundBox */
- BoundBox *bb = BKE_mesh_boundbox_get(ob);
+ BoundBox *bb = BKE_mesh_boundbox_get(ob_eval);
if (bb) {
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!isect_ray_aabb_v3_simple(
@@ -658,53 +743,18 @@ static bool raycastMesh(SnapObjectContext *sctx,
len_diff = 0.0f;
}
- SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob);
+ SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
BVHTreeFromMesh *treedata = &sod->treedata_mesh;
- /* The tree is owned by the Mesh and may have been freed since we last used. */
- if (treedata->tree) {
- BLI_assert(treedata->cached);
- if (!bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) {
- free_bvhtree_from_mesh(treedata);
- }
- else {
- /* Update Pointers. */
- if (treedata->vert && treedata->vert_allocated == false) {
- treedata->vert = me->mvert;
- }
- if (treedata->loop && treedata->loop_allocated == false) {
- treedata->loop = me->mloop;
- }
- if (treedata->looptri && treedata->looptri_allocated == false) {
- treedata->looptri = BKE_mesh_runtime_looptri_ensure(me);
- }
- /* required for snapping with occlusion. */
- treedata->edge = me->medge;
- sod->poly = me->mpoly;
- }
- }
-
if (treedata->tree == NULL) {
- if (use_hide) {
- BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI_NO_HIDDEN, 4);
- }
- else {
- BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4);
- }
-
- /* required for snapping with occlusion. */
- treedata->edge = me->medge;
- sod->poly = me->mpoly;
-
- if (treedata->tree == NULL) {
- return retval;
- }
+ return retval;
}
float timat[3][3]; /* transpose inverse matrix for normals */
transpose_m3_m4(timat, imat);
+ BLI_assert(treedata->raycast_callback != NULL);
if (r_hit_list) {
struct RayCastAll_Data data;
@@ -714,7 +764,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
data.timat = timat;
data.len_diff = len_diff;
data.local_scale = local_scale;
- data.ob = ob;
+ data.ob_eval = ob_eval;
data.ob_uuid = ob_index;
data.hit_list = r_hit_list;
data.retval = retval;
@@ -773,7 +823,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
static bool raycastEditMesh(SnapObjectContext *sctx,
const float ray_start[3],
const float ray_dir[3],
- Object *ob,
+ Object *ob_eval,
BMEditMesh *em,
const float obmat[4][4],
const uint ob_index,
@@ -810,7 +860,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
local_depth *= local_scale;
}
- SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em);
+ SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
/* Test BoundBox */
@@ -836,7 +886,8 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
if (treedata->tree == NULL) {
/* Operators only update the editmesh looptris of the original mesh. */
- BLI_assert(sod->treedata_editmesh.em == BKE_editmesh_from_object(DEG_get_original_object(ob)));
+ BLI_assert(sod->treedata_editmesh.em ==
+ BKE_editmesh_from_object(DEG_get_original_object(ob_eval)));
em = sod->treedata_editmesh.em;
if (sctx->callbacks.edit_mesh.test_face_fn) {
@@ -883,7 +934,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
data.timat = timat;
data.len_diff = len_diff;
data.local_scale = local_scale;
- data.ob = ob;
+ data.ob_eval = ob_eval;
data.ob_uuid = ob_index;
data.hit_list = r_hit_list;
data.retval = retval;
@@ -964,9 +1015,9 @@ struct RaycastObjUserData {
* \note Duplicate args here are documented at #snapObjectsRay
*/
static void raycast_obj_fn(SnapObjectContext *sctx,
- Object *ob,
+ Object *ob_eval,
float obmat[4][4],
- bool use_obedit,
+ eSnapEditType edit_mode_type,
bool use_backface_culling,
bool is_object_active,
void *data)
@@ -979,53 +1030,46 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
bool retval = false;
if (use_occlusion_test) {
- if (use_obedit && sctx->use_v3d && XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) {
+ if ((edit_mode_type == SNAP_GEOM_EDIT) && sctx->use_v3d &&
+ XRAY_FLAG_ENABLED(sctx->v3d_data.v3d)) {
/* Use of occlude geometry in editing mode disabled. */
return;
}
- if (ELEM(ob->dt, OB_BOUNDBOX, OB_WIRE)) {
+ if (ELEM(ob_eval->dt, OB_BOUNDBOX, OB_WIRE)) {
/* Do not hit objects that are in wire or bounding box
* display mode. */
return;
}
}
- switch (ob->type) {
+ switch (ob_eval->type) {
case OB_MESH: {
- Mesh *me = ob->data;
bool use_hide = false;
- if (BKE_object_is_in_editmode(ob)) {
- if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
- /* Operators only update the editmesh looptris of the original mesh. */
- BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
- retval = raycastEditMesh(sctx,
- dt->ray_start,
- dt->ray_dir,
- ob,
- em_orig,
- obmat,
- ob_index,
- use_backface_culling,
- ray_depth,
- dt->r_loc,
- dt->r_no,
- dt->r_index,
- dt->r_hit_list);
- break;
- }
-
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- if (em->mesh_eval_final) {
- me = em->mesh_eval_final;
- use_hide = true;
- }
+ Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
+ if (me_eval == NULL) {
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
+ retval = raycastEditMesh(sctx,
+ dt->ray_start,
+ dt->ray_dir,
+ ob_eval,
+ em_orig,
+ obmat,
+ ob_index,
+ use_backface_culling,
+ ray_depth,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index,
+ dt->r_hit_list);
+ break;
}
retval = raycastMesh(sctx,
dt->ray_start,
dt->ray_dir,
- ob,
- me,
+ ob_eval,
+ me_eval,
obmat,
ob_index,
use_hide,
@@ -1041,12 +1085,12 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
case OB_SURF:
case OB_FONT: {
if (!is_object_active) {
- Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
retval = raycastMesh(sctx,
dt->ray_start,
dt->ray_dir,
- ob,
+ ob_eval,
mesh_eval,
obmat,
ob_index,
@@ -1065,7 +1109,7 @@ static void raycast_obj_fn(SnapObjectContext *sctx,
if (retval) {
if (dt->r_ob) {
- *dt->r_ob = ob;
+ *dt->r_ob = ob_eval;
}
if (dt->r_obmat) {
copy_m4_m4(dt->r_obmat, obmat);
@@ -1320,6 +1364,33 @@ typedef struct Nearest2dUserData {
bool use_backface_culling;
} Nearest2dUserData;
+static void nearest2d_data_init(SnapObjectData *sod,
+ bool is_persp,
+ bool use_backface_culling,
+ Nearest2dUserData *r_nearest2d)
+{
+ if (sod->type == SNAP_MESH) {
+ r_nearest2d->userdata = &sod->treedata_mesh;
+ r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
+ r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
+ r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
+ r_nearest2d->get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get;
+ r_nearest2d->get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get;
+ }
+ else {
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ r_nearest2d->userdata = sod->treedata_editmesh.em;
+ r_nearest2d->get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
+ r_nearest2d->get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
+ r_nearest2d->copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
+ r_nearest2d->get_tri_verts_index = NULL;
+ r_nearest2d->get_tri_edges_index = NULL;
+ }
+
+ r_nearest2d->is_persp = is_persp;
+ r_nearest2d->use_backface_culling = use_backface_culling;
+}
+
static void cb_snap_vert(void *userdata,
int index,
const struct DistProjectedAABBPrecalc *precalc,
@@ -1467,7 +1538,7 @@ static void cb_snap_tri_verts(void *userdata,
static short snap_mesh_polygon(SnapObjectContext *sctx,
SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
bool use_backface_culling,
/* read/write args */
@@ -1492,28 +1563,21 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
}
- Nearest2dUserData nearest2d = {
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
- .use_backface_culling = use_backface_culling,
- };
-
BVHTreeNearest nearest = {
.index = -1,
.dist_sq = square_f(*dist_px),
};
- SnapObjectData *sod = snap_object_data_lookup(sctx, ob);
-
+ SnapObjectData *sod = snap_object_data_lookup(sctx, ob_eval);
BLI_assert(sod != NULL);
+ Nearest2dUserData nearest2d;
+ nearest2d_data_init(
+ sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
+
if (sod->type == SNAP_MESH) {
BVHTreeFromMesh *treedata = &sod->treedata_mesh;
- nearest2d.userdata = treedata;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
-
const MPoly *mp = &sod->poly[*r_index];
const MLoop *ml = &treedata->loop[mp->loopstart];
if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
@@ -1544,11 +1608,6 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BLI_assert(sod->type == SNAP_EDIT_MESH);
BMEditMesh *em = sod->treedata_editmesh.em;
- nearest2d.userdata = em;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
-
BM_mesh_elem_table_ensure(em->bm, BM_FACE);
BMFace *f = BM_face_at_index(em->bm, *r_index);
BMLoop *l_iter, *l_first;
@@ -1605,7 +1664,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
float original_dist_px,
const float prev_co[3],
@@ -1619,32 +1678,16 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
{
short elem = SCE_SNAP_MODE_EDGE;
- if (ob->type != OB_MESH) {
+ if (ob_eval->type != OB_MESH) {
return elem;
}
- SnapObjectData *sod = snap_object_data_lookup(sctx, ob);
-
+ SnapObjectData *sod = snap_object_data_lookup(sctx, ob_eval);
BLI_assert(sod != NULL);
Nearest2dUserData nearest2d;
- {
- nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
- nearest2d.use_backface_culling = use_backface_culling;
- if (sod->type == SNAP_MESH) {
- nearest2d.userdata = &sod->treedata_mesh;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
- }
- else {
- BLI_assert(sod->type == SNAP_EDIT_MESH);
- nearest2d.userdata = sod->treedata_editmesh.em;
- nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
- nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
- nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
- }
- }
+ nearest2d_data_init(
+ sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
int vindex[2];
nearest2d.get_edge_verts_index(*r_index, vindex, nearest2d.userdata);
@@ -1769,9 +1812,8 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
}
static short snapArmature(SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
- bool use_obedit,
/* read/write args */
float *dist_px,
/* return args */
@@ -1792,11 +1834,11 @@ static short snapArmature(SnapData *snapdata,
dist_squared_to_projected_aabb_precalc(
&neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
- use_obedit = use_obedit && BKE_object_is_in_editmode(ob);
+ bool use_obedit = ((bArmature *)ob_eval->data)->edbo != NULL;
if (use_obedit == false) {
/* Test BoundBox */
- BoundBox *bb = BKE_armature_boundbox_get(ob);
+ BoundBox *bb = BKE_armature_boundbox_get(ob_eval);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return retval;
@@ -1811,7 +1853,7 @@ static short snapArmature(SnapData *snapdata,
bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
- bArmature *arm = ob->data;
+ bArmature *arm = ob_eval->data;
if (arm->edbo) {
LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
if (eBone->layer & arm->layer) {
@@ -1855,8 +1897,8 @@ static short snapArmature(SnapData *snapdata,
}
}
}
- else if (ob->pose && ob->pose->chanbase.first) {
- LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ else if (ob_eval->pose && ob_eval->pose->chanbase.first) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob_eval->pose->chanbase) {
Bone *bone = pchan->bone;
/* skip hidden bones */
if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
@@ -1914,7 +1956,7 @@ static short snapArmature(SnapData *snapdata,
}
static short snapCurve(SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
bool use_obedit,
/* read/write args */
@@ -1931,7 +1973,7 @@ static short snapCurve(SnapData *snapdata,
return 0;
}
- Curve *cu = ob->data;
+ Curve *cu = ob_eval->data;
float dist_px_sq = square_f(*dist_px);
float lpmat[4][4];
@@ -1941,11 +1983,11 @@ static short snapCurve(SnapData *snapdata,
dist_squared_to_projected_aabb_precalc(
&neasrest_precalc, lpmat, snapdata->win_size, snapdata->mval);
- use_obedit = use_obedit && BKE_object_is_in_editmode(ob);
+ use_obedit = use_obedit && BKE_object_is_in_editmode(ob_eval);
if (use_obedit == false) {
/* Test BoundBox */
- BoundBox *bb = BKE_curve_boundbox_get(ob);
+ BoundBox *bb = BKE_curve_boundbox_get(ob_eval);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return 0;
@@ -2065,7 +2107,7 @@ static short snapCurve(SnapData *snapdata,
/* may extend later (for now just snaps to empty center) */
static short snap_object_center(SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
const float obmat[4][4],
/* read/write args */
float *dist_px,
@@ -2076,7 +2118,7 @@ static short snap_object_center(SnapData *snapdata,
{
short retval = 0;
- if (ob->transflag & OB_DUPLI) {
+ if (ob_eval->transflag & OB_DUPLI) {
return retval;
}
@@ -2219,9 +2261,10 @@ static short snapCamera(const SnapObjectContext *sctx,
static short snapMesh(SnapObjectContext *sctx,
SnapData *snapdata,
- Object *ob,
- Mesh *me,
+ Object *ob_eval,
+ Mesh *me_eval,
const float obmat[4][4],
+ bool use_hide,
bool use_backface_culling,
/* read/write args */
float *dist_px,
@@ -2231,10 +2274,10 @@ static short snapMesh(SnapObjectContext *sctx,
int *r_index)
{
BLI_assert(snapdata->snap_to_flag != SCE_SNAP_MODE_FACE);
- if (me->totvert == 0) {
+ if (me_eval->totvert == 0) {
return 0;
}
- else if (me->totedge == 0 && !(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
+ if (me_eval->totedge == 0 && !(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
return 0;
}
@@ -2244,65 +2287,46 @@ static short snapMesh(SnapObjectContext *sctx,
float dist_px_sq = square_f(*dist_px);
/* Test BoundBox */
- BoundBox *bb = BKE_mesh_boundbox_get(ob);
+ BoundBox *bb = BKE_mesh_boundbox_get(ob_eval);
if (bb && !snap_bound_box_check_dist(
bb->vec[0], bb->vec[6], lpmat, snapdata->win_size, snapdata->mval, dist_px_sq)) {
return 0;
}
- SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob);
+ SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob_eval, me_eval, use_hide);
- BVHTreeFromMesh *treedata, dummy_treedata;
+ BVHTreeFromMesh *treedata, treedata_tmp;
treedata = &sod->treedata_mesh;
- /* The tree is owned by the Mesh and may have been freed since we last used! */
- if (treedata->cached && treedata->tree &&
- !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) {
- free_bvhtree_from_mesh(treedata);
- }
- if (sod->cached[0] && sod->bvhtree[0] &&
- !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[0])) {
- sod->bvhtree[0] = NULL;
- }
- if (sod->cached[1] && sod->bvhtree[1] &&
- !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[1])) {
- sod->bvhtree[1] = NULL;
- }
-
- if (sod->has_looptris && treedata->tree == NULL) {
- BKE_bvhtree_from_mesh_get(treedata, me, BVHTREE_FROM_LOOPTRI, 4);
- sod->has_looptris = (treedata->tree != NULL);
- if (sod->has_looptris) {
- /* Make sure that the array of edges is referenced in the callbacks. */
- treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
- }
- }
if (sod->has_loose_edge && sod->bvhtree[0] == NULL) {
- sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2);
- sod->has_loose_edge = sod->bvhtree[0] != NULL;
- sod->cached[0] = dummy_treedata.cached;
-
- if (sod->has_loose_edge) {
- BLI_assert(treedata->vert_allocated == false);
- treedata->vert = dummy_treedata.vert;
- treedata->vert_allocated = dummy_treedata.vert_allocated;
-
- BLI_assert(treedata->edge_allocated == false);
- treedata->edge = dummy_treedata.edge;
- treedata->edge_allocated = dummy_treedata.edge_allocated;
+ sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(
+ &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEEDGES, 2);
+ if (sod->bvhtree[0] == NULL) {
+ sod->has_loose_edge = false;
}
+ sod->cached[0] = treedata_tmp.cached;
+ BLI_assert(!ELEM(true,
+ treedata_tmp.vert_allocated,
+ treedata_tmp.edge_allocated,
+ treedata_tmp.face_allocated,
+ treedata_tmp.loop_allocated,
+ treedata_tmp.looptri_allocated));
}
+
if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
if (sod->has_loose_vert && sod->bvhtree[1] == NULL) {
- sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2);
- sod->has_loose_vert = sod->bvhtree[1] != NULL;
- sod->cached[1] = dummy_treedata.cached;
-
- if (sod->has_loose_vert) {
- BLI_assert(treedata->vert_allocated == false);
- treedata->vert = dummy_treedata.vert;
- treedata->vert_allocated = dummy_treedata.vert_allocated;
+ sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(
+ &treedata_tmp, me_eval, BVHTREE_FROM_LOOSEVERTS, 2);
+ if (sod->bvhtree[1] == NULL) {
+ sod->has_loose_vert = false;
}
+ sod->cached[1] = treedata_tmp.cached;
+ BLI_assert(!ELEM(true,
+ treedata_tmp.vert_allocated,
+ treedata_tmp.edge_allocated,
+ treedata_tmp.face_allocated,
+ treedata_tmp.loop_allocated,
+ treedata_tmp.looptri_allocated));
}
}
else {
@@ -2310,33 +2334,9 @@ static short snapMesh(SnapObjectContext *sctx,
sod->has_loose_vert = false;
}
- /* Update pointers. */
- if (treedata->vert_allocated == false) {
- treedata->vert = me->mvert; /* CustomData_get_layer(&me->vdata, CD_MVERT);? */
- }
- if (treedata->tree || sod->bvhtree[0]) {
- if (treedata->edge_allocated == false) {
- /* If raycast has been executed before, `treedata->edge` can be NULL. */
- treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
- }
- if (treedata->loop && treedata->loop_allocated == false) {
- treedata->loop = me->mloop; /* CustomData_get_layer(&me->edata, CD_MLOOP);? */
- }
- if (treedata->looptri && treedata->looptri_allocated == false) {
- treedata->looptri = BKE_mesh_runtime_looptri_ensure(me);
- }
- }
-
- Nearest2dUserData nearest2d = {
- .userdata = treedata,
- .get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get,
- .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get,
- .get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get,
- .get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get,
- .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy,
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
- .use_backface_culling = use_backface_culling,
- };
+ Nearest2dUserData nearest2d;
+ nearest2d_data_init(
+ sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2452,7 +2452,7 @@ static short snapMesh(SnapObjectContext *sctx,
static short snapEditMesh(SnapObjectContext *sctx,
SnapData *snapdata,
- Object *ob,
+ Object *ob_eval,
BMEditMesh *em,
const float obmat[4][4],
bool use_backface_culling,
@@ -2481,7 +2481,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
float dist_px_sq = square_f(*dist_px);
- SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em);
+ SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob_eval, em);
/* Test BoundBox */
@@ -2555,14 +2555,9 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
}
- Nearest2dUserData nearest2d = {
- .userdata = em,
- .get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get,
- .get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get,
- .copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy,
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
- .use_backface_culling = use_backface_culling,
- };
+ Nearest2dUserData nearest2d;
+ nearest2d_data_init(
+ sod, snapdata->view_proj == VIEW_PROJ_PERSP, use_backface_culling, &nearest2d);
BVHTreeNearest nearest = {
.index = -1,
@@ -2656,9 +2651,9 @@ struct SnapObjUserData {
* \note Duplicate args here are documented at #snapObjectsRay
*/
static void snap_obj_fn(SnapObjectContext *sctx,
- Object *ob,
+ Object *ob_eval,
float obmat[4][4],
- bool use_obedit,
+ eSnapEditType edit_mode_type,
bool use_backface_culling,
bool UNUSED(is_object_active),
void *data)
@@ -2666,41 +2661,36 @@ static void snap_obj_fn(SnapObjectContext *sctx,
struct SnapObjUserData *dt = data;
short retval = 0;
- switch (ob->type) {
+ switch (ob_eval->type) {
case OB_MESH: {
- Mesh *me = ob->data;
- if (BKE_object_is_in_editmode(ob)) {
- if (use_obedit || editmesh_eval_final_is_bmesh(me->edit_mesh)) {
- /* Operators only update the editmesh looptris of the original mesh. */
- BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
- retval = snapEditMesh(sctx,
- dt->snapdata,
- ob,
- em_orig,
- obmat,
- use_backface_culling,
- dt->dist_px,
- dt->r_loc,
- dt->r_no,
- dt->r_index);
- break;
- }
-
- BMEditMesh *em = BKE_editmesh_from_object(ob);
- if (em->mesh_eval_final) {
- me = em->mesh_eval_final;
- }
+ bool use_hide;
+ Mesh *me_eval = mesh_for_snap(ob_eval, edit_mode_type, &use_hide);
+ if (me_eval == NULL) {
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob_eval));
+ retval = snapEditMesh(sctx,
+ dt->snapdata,
+ ob_eval,
+ em_orig,
+ obmat,
+ use_backface_culling,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
+ break;
}
- else if (ob->dt == OB_BOUNDBOX) {
+ if (ob_eval->dt == OB_BOUNDBOX) {
/* Do not snap to objects that are in bounding box display mode */
return;
}
retval = snapMesh(sctx,
dt->snapdata,
- ob,
- me,
+ ob_eval,
+ me_eval,
obmat,
+ use_hide,
use_backface_culling,
dt->dist_px,
dt->r_loc,
@@ -2710,21 +2700,28 @@ static void snap_obj_fn(SnapObjectContext *sctx,
}
case OB_ARMATURE:
retval = snapArmature(
- dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CURVE:
- retval = snapCurve(
- dt->snapdata, ob, obmat, use_obedit, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ retval = snapCurve(dt->snapdata,
+ ob_eval,
+ obmat,
+ edit_mode_type == SNAP_GEOM_EDIT,
+ dt->dist_px,
+ dt->r_loc,
+ dt->r_no,
+ dt->r_index);
break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
case OB_FONT: {
- Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
retval |= snapMesh(sctx,
dt->snapdata,
- ob,
+ ob_eval,
mesh_eval,
obmat,
+ false,
use_backface_culling,
dt->dist_px,
dt->r_loc,
@@ -2737,17 +2734,17 @@ static void snap_obj_fn(SnapObjectContext *sctx,
case OB_GPENCIL:
case OB_LAMP:
retval = snap_object_center(
- dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
case OB_CAMERA:
retval = snapCamera(
- sctx, dt->snapdata, ob, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
+ sctx, dt->snapdata, ob_eval, obmat, dt->dist_px, dt->r_loc, dt->r_no, dt->r_index);
break;
}
if (retval) {
if (dt->r_ob) {
- *dt->r_ob = ob;
+ *dt->r_ob = ob_eval;
}
if (dt->r_obmat) {
copy_m4_m4(dt->r_obmat, obmat);
@@ -3020,7 +3017,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
short retval = 0;
bool has_hit = false;
- Object *ob = NULL;
+ Object *ob_eval = NULL;
float loc[3];
/* Not all snapping callbacks set the normal,
* initialize this since any hit copies both the `loc` and `no`. */
@@ -3057,7 +3054,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
loc,
no,
&index,
- &ob,
+ &ob_eval,
obmat,
NULL);
@@ -3069,7 +3066,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
copy_v3_v3(r_no, no);
}
if (r_ob) {
- *r_ob = ob;
+ *r_ob = ob_eval;
}
if (r_obmat) {
copy_m4_m4(r_obmat, obmat);
@@ -3105,9 +3102,10 @@ static short transform_snap_context_project_view3d_mixed_impl(
snapdata.has_occlusion_plane = false;
/* By convention we only snap to the original elements of a curve. */
- if (has_hit && ob->type != OB_CURVE) {
+ if (has_hit && ob_eval->type != OB_CURVE) {
/* Compute the new clip_pane but do not add it yet. */
float new_clipplane[4];
+ BLI_ASSERT_UNIT_V3(no);
plane_from_point_normal_v3(new_clipplane, loc, no);
if (dot_v3v3(snapdata.clip_plane[0], new_clipplane) > 0.0f) {
/* The plane is facing the wrong direction. */
@@ -3118,8 +3116,15 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem_test = snap_mesh_polygon(
- sctx, &snapdata, ob, obmat, params->use_backface_culling, &dist_px_tmp, loc, no, &index);
+ elem_test = snap_mesh_polygon(sctx,
+ &snapdata,
+ ob_eval,
+ obmat,
+ params->use_backface_culling,
+ &dist_px_tmp,
+ loc,
+ no,
+ &index);
if (elem_test) {
elem = elem_test;
}
@@ -3134,7 +3139,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
}
elem_test = snapObjectsRay(
- sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat);
+ sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob_eval, obmat);
if (elem_test) {
elem = elem_test;
}
@@ -3145,7 +3150,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
snapdata.snap_to_flag = snap_to_flag;
elem = snap_mesh_edge_verts_mixed(sctx,
&snapdata,
- ob,
+ ob_eval,
obmat,
*dist_px,
prev_co,
@@ -3164,7 +3169,7 @@ static short transform_snap_context_project_view3d_mixed_impl(
copy_v3_v3(r_no, no);
}
if (r_ob) {
- *r_ob = ob;
+ *r_ob = ob_eval;
}
if (r_obmat) {
copy_m4_m4(r_obmat, obmat);
diff --git a/source/blender/functions/FN_generic_span.hh b/source/blender/functions/FN_generic_span.hh
index 31b67dd3d70..e2c49697ba9 100644
--- a/source/blender/functions/FN_generic_span.hh
+++ b/source/blender/functions/FN_generic_span.hh
@@ -30,7 +30,7 @@ namespace blender::fn {
* A generic span. It behaves just like a blender::Span<T>, but the type is only known at run-time.
*/
class GSpan {
- private:
+ protected:
const CPPType *type_;
const void *data_;
int64_t size_;
@@ -85,6 +85,14 @@ class GSpan {
BLI_assert(type_->is<T>());
return Span<T>(static_cast<const T *>(data_), size_);
}
+
+ GSpan slice(const int64_t start, int64_t size) const
+ {
+ BLI_assert(start >= 0);
+ BLI_assert(size >= 0);
+ const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
+ return GSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
+ }
};
/**
@@ -92,7 +100,7 @@ class GSpan {
* known at run-time.
*/
class GMutableSpan {
- private:
+ protected:
const CPPType *type_;
void *data_;
int64_t size_;
@@ -153,6 +161,14 @@ class GMutableSpan {
BLI_assert(type_->is<T>());
return MutableSpan<T>(static_cast<T *>(data_), size_);
}
+
+ GMutableSpan slice(const int64_t start, int64_t size) const
+ {
+ BLI_assert(start >= 0);
+ BLI_assert(size >= 0);
+ const int64_t new_size = std::max<int64_t>(0, std::min(size, size_ - start));
+ return GMutableSpan(*type_, POINTER_OFFSET(data_, type_->size() * start), new_size);
+ }
};
} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh
index ae6eb8a614f..b02ed471875 100644
--- a/source/blender/functions/FN_generic_vector_array.hh
+++ b/source/blender/functions/FN_generic_vector_array.hh
@@ -123,7 +123,7 @@ template<typename T> class GVectorArray_TypedMutableRef {
void extend(const int64_t index, const VArray<T> &values)
{
- GVArrayForVArray<T> array{values};
+ GVArray_For_VArray<T> array{values};
this->extend(index, array);
}
@@ -134,12 +134,12 @@ template<typename T> class GVectorArray_TypedMutableRef {
};
/* A generic virtual vector array implementation for a `GVectorArray`. */
-class GVVectorArrayForGVectorArray : public GVVectorArray {
+class GVVectorArray_For_GVectorArray : public GVVectorArray {
private:
const GVectorArray &vector_array_;
public:
- GVVectorArrayForGVectorArray(const GVectorArray &vector_array)
+ GVVectorArray_For_GVectorArray(const GVectorArray &vector_array)
: GVVectorArray(vector_array.type(), vector_array.size()), vector_array_(vector_array)
{
}
diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh
index c6230730a8d..c1af00fd4cd 100644
--- a/source/blender/functions/FN_generic_virtual_array.hh
+++ b/source/blender/functions/FN_generic_virtual_array.hh
@@ -23,12 +23,17 @@
* the data type is only known at runtime.
*/
+#include <optional>
+
#include "BLI_virtual_array.hh"
#include "FN_generic_span.hh"
namespace blender::fn {
+template<typename T> class GVArray_Typed;
+template<typename T> class GVMutableArray_Typed;
+
/* A generically typed version of `VArray<T>`. */
class GVArray {
protected:
@@ -86,13 +91,13 @@ class GVArray {
/* Returns the internally used span of the virtual array. This invokes undefined behavior is the
* virtual array is not stored as a span internally. */
- GSpan get_span() const
+ GSpan get_internal_span() const
{
BLI_assert(this->is_span());
if (size_ == 0) {
return GSpan(*type_);
}
- return this->get_span_impl();
+ return this->get_internal_span_impl();
}
/* Returns true when the virtual array returns the same value for every index. */
@@ -107,57 +112,136 @@ class GVArray {
/* Copies the value that is used for every element into `r_value`, which is expected to point to
* initialized memory. This invokes undefined behavior if the virtual array would not return the
* same value for every index. */
- void get_single(void *r_value) const
+ void get_internal_single(void *r_value) const
{
BLI_assert(this->is_single());
if (size_ == 1) {
this->get(0, r_value);
}
- this->get_single_impl(r_value);
+ this->get_internal_single_impl(r_value);
}
- /* Same as `get_single`, but `r_value` points to initialized memory. */
+ /* Same as `get_internal_single`, but `r_value` points to initialized memory. */
void get_single_to_uninitialized(void *r_value) const
{
type_->construct_default(r_value);
- this->get_single(r_value);
+ this->get_internal_single(r_value);
}
void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
+ template<typename T> const VArray<T> *try_get_internal_varray() const
+ {
+ BLI_assert(type_->is<T>());
+ return (const VArray<T> *)this->try_get_internal_varray_impl();
+ }
+
+ /* Create a typed virtual array for this generic virtual array. */
+ template<typename T> GVArray_Typed<T> typed() const
+ {
+ return GVArray_Typed<T>(*this);
+ }
+
protected:
virtual void get_impl(const int64_t index, void *r_value) const;
virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0;
virtual bool is_span_impl() const;
- virtual GSpan get_span_impl() const;
+ virtual GSpan get_internal_span_impl() const;
virtual bool is_single_impl() const;
- virtual void get_single_impl(void *UNUSED(r_value)) const;
+ virtual void get_internal_single_impl(void *UNUSED(r_value)) const;
+
+ virtual const void *try_get_internal_varray_impl() const;
+};
+
+/* Similar to GVArray, but supports changing the elements in the virtual array. */
+class GVMutableArray : public GVArray {
+ public:
+ GVMutableArray(const CPPType &type, const int64_t size) : GVArray(type, size)
+ {
+ }
+
+ void set_by_copy(const int64_t index, const void *value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ this->set_by_copy_impl(index, value);
+ }
+
+ void set_by_move(const int64_t index, void *value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ this->set_by_move_impl(index, value);
+ }
+
+ void set_by_relocate(const int64_t index, void *value)
+ {
+ BLI_assert(index >= 0);
+ BLI_assert(index < size_);
+ this->set_by_relocate_impl(index, value);
+ }
+
+ GMutableSpan get_internal_span()
+ {
+ BLI_assert(this->is_span());
+ GSpan span = static_cast<const GVArray *>(this)->get_internal_span();
+ return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size());
+ }
+
+ template<typename T> VMutableArray<T> *try_get_internal_mutable_varray()
+ {
+ BLI_assert(type_->is<T>());
+ return (VMutableArray<T> *)this->try_get_internal_mutable_varray_impl();
+ }
+
+ /* Create a typed virtual array for this generic virtual array. */
+ template<typename T> GVMutableArray_Typed<T> typed()
+ {
+ return GVMutableArray_Typed<T>(*this);
+ }
+
+ void fill(const void *value);
+
+ protected:
+ virtual void set_by_copy_impl(const int64_t index, const void *value);
+ virtual void set_by_relocate_impl(const int64_t index, void *value);
+ virtual void set_by_move_impl(const int64_t index, void *value) = 0;
+
+ virtual void *try_get_internal_mutable_varray_impl();
};
-class GVArrayForGSpan : public GVArray {
+using GVArrayPtr = std::unique_ptr<GVArray>;
+using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>;
+
+class GVArray_For_GSpan : public GVArray {
protected:
- const void *data_;
+ const void *data_ = nullptr;
const int64_t element_size_;
public:
- GVArrayForGSpan(const GSpan span)
+ GVArray_For_GSpan(const GSpan span)
: GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size())
{
}
protected:
+ GVArray_For_GSpan(const CPPType &type, const int64_t size)
+ : GVArray(type, size), element_size_(type.size())
+ {
+ }
+
void get_impl(const int64_t index, void *r_value) const override;
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
bool is_span_impl() const override;
- GSpan get_span_impl() const override;
+ GSpan get_internal_span_impl() const override;
};
-class GVArrayForEmpty : public GVArray {
+class GVArray_For_Empty : public GVArray {
public:
- GVArrayForEmpty(const CPPType &type) : GVArray(type, 0)
+ GVArray_For_Empty(const CPPType &type) : GVArray(type, 0)
{
}
@@ -168,108 +252,617 @@ class GVArrayForEmpty : public GVArray {
}
};
-class GVArrayForSingleValueRef : public GVArray {
- private:
- const void *value_;
+class GVMutableArray_For_GMutableSpan : public GVMutableArray {
+ protected:
+ void *data_ = nullptr;
+ const int64_t element_size_;
+
+ public:
+ GVMutableArray_For_GMutableSpan(const GMutableSpan span)
+ : GVMutableArray(span.type(), span.size()),
+ data_(span.data()),
+ element_size_(span.type().size())
+ {
+ }
+
+ protected:
+ GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size)
+ : GVMutableArray(type, size), element_size_(type.size())
+ {
+ }
+
+ void get_impl(const int64_t index, void *r_value) const override;
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
+
+ void set_by_copy_impl(const int64_t index, const void *value) override;
+ void set_by_move_impl(const int64_t index, void *value) override;
+ void set_by_relocate_impl(const int64_t index, void *value) override;
+
+ bool is_span_impl() const override;
+ GSpan get_internal_span_impl() const override;
+};
+
+/* Generic virtual array where each element has the same value. The value is not owned. */
+class GVArray_For_SingleValueRef : public GVArray {
+ protected:
+ const void *value_ = nullptr;
public:
- GVArrayForSingleValueRef(const CPPType &type, const int64_t size, const void *value)
+ GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value)
: GVArray(type, size), value_(value)
{
}
protected:
+ GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size)
+ {
+ }
+
void get_impl(const int64_t index, void *r_value) const override;
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override;
bool is_span_impl() const override;
- GSpan get_span_impl() const override;
+ GSpan get_internal_span_impl() const override;
bool is_single_impl() const override;
- void get_single_impl(void *r_value) const override;
+ void get_internal_single_impl(void *r_value) const override;
};
-template<typename T> class GVArrayForVArray : public GVArray {
- private:
- const VArray<T> &array_;
+/* Same as GVArray_For_SingleValueRef, but the value is owned. */
+class GVArray_For_SingleValue : public GVArray_For_SingleValueRef {
+ public:
+ GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value);
+ ~GVArray_For_SingleValue();
+};
+
+/* Used to convert a typed virtual array into a generic one. */
+template<typename T> class GVArray_For_VArray : public GVArray {
+ protected:
+ const VArray<T> *varray_ = nullptr;
public:
- GVArrayForVArray(const VArray<T> &array)
- : GVArray(CPPType::get<T>(), array.size()), array_(array)
+ GVArray_For_VArray(const VArray<T> &varray)
+ : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray)
{
}
protected:
+ GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size)
+ {
+ }
+
void get_impl(const int64_t index, void *r_value) const override
{
- *(T *)r_value = array_.get(index);
+ *(T *)r_value = varray_->get(index);
}
void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
{
- new (r_value) T(array_.get(index));
+ new (r_value) T(varray_->get(index));
}
bool is_span_impl() const override
{
- return array_.is_span();
+ return varray_->is_span();
}
- GSpan get_span_impl() const override
+ GSpan get_internal_span_impl() const override
{
- return GSpan(array_.get_span());
+ return GSpan(varray_->get_internal_span());
}
bool is_single_impl() const override
{
- return array_.is_single();
+ return varray_->is_single();
+ }
+
+ void get_internal_single_impl(void *r_value) const override
+ {
+ *(T *)r_value = varray_->get_internal_single();
}
- void get_single_impl(void *r_value) const override
+ const void *try_get_internal_varray_impl() const override
{
- *(T *)r_value = array_.get_single();
+ return varray_;
}
};
-template<typename T> class VArrayForGVArray : public VArray<T> {
- private:
- const GVArray &array_;
+/* Used to convert any generic virtual array into a typed one. */
+template<typename T> class VArray_For_GVArray : public VArray<T> {
+ protected:
+ const GVArray *varray_ = nullptr;
public:
- VArrayForGVArray(const GVArray &array) : VArray<T>(array.size()), array_(array)
+ VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray)
+ {
+ BLI_assert(varray_->type().template is<T>());
+ }
+
+ protected:
+ VArray_For_GVArray(const int64_t size) : VArray<T>(size)
+ {
+ }
+
+ T get_impl(const int64_t index) const override
+ {
+ T value;
+ varray_->get(index, &value);
+ return value;
+ }
+
+ bool is_span_impl() const override
+ {
+ return varray_->is_span();
+ }
+
+ Span<T> get_internal_span_impl() const override
{
- BLI_assert(array_.type().template is<T>());
+ return varray_->get_internal_span().template typed<T>();
}
+ bool is_single_impl() const override
+ {
+ return varray_->is_single();
+ }
+
+ T get_internal_single_impl() const override
+ {
+ T value;
+ varray_->get_internal_single(&value);
+ return value;
+ }
+};
+
+/* Used to convert an generic mutable virtual array into a typed one. */
+template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> {
protected:
+ GVMutableArray *varray_ = nullptr;
+
+ public:
+ VMutableArray_For_GVMutableArray(GVMutableArray &varray)
+ : VMutableArray<T>(varray.size()), varray_(&varray)
+ {
+ BLI_assert(varray.type().template is<T>());
+ }
+
+ VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size)
+ {
+ }
+
+ private:
T get_impl(const int64_t index) const override
{
T value;
- array_.get(index, &value);
+ varray_->get(index, &value);
return value;
}
+ void set_impl(const int64_t index, T value) override
+ {
+ varray_->set_by_relocate(index, &value);
+ }
+
bool is_span_impl() const override
{
- return array_.is_span();
+ return varray_->is_span();
}
- Span<T> get_span_impl() const override
+ Span<T> get_internal_span_impl() const override
{
- return array_.get_span().template typed<T>();
+ return varray_->get_internal_span().template typed<T>();
}
bool is_single_impl() const override
{
- return array_.is_single();
+ return varray_->is_single();
}
- T get_single_impl() const override
+ T get_internal_single_impl() const override
{
T value;
- array_.get_single(&value);
+ varray_->get_internal_single(&value);
return value;
}
};
+/* Used to convert any typed virtual mutable array into a generic one. */
+template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray {
+ protected:
+ VMutableArray<T> *varray_ = nullptr;
+
+ public:
+ GVMutableArray_For_VMutableArray(VMutableArray<T> &varray)
+ : GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray)
+ {
+ }
+
+ protected:
+ GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size)
+ {
+ }
+
+ void get_impl(const int64_t index, void *r_value) const override
+ {
+ *(T *)r_value = varray_->get(index);
+ }
+
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ {
+ new (r_value) T(varray_->get(index));
+ }
+
+ bool is_span_impl() const override
+ {
+ return varray_->is_span();
+ }
+
+ GSpan get_internal_span_impl() const override
+ {
+ Span<T> span = varray_->get_internal_span();
+ return span;
+ }
+
+ bool is_single_impl() const override
+ {
+ return varray_->is_single();
+ }
+
+ void get_internal_single_impl(void *r_value) const override
+ {
+ *(T *)r_value = varray_->get_internal_single();
+ }
+
+ void set_by_copy_impl(const int64_t index, const void *value) override
+ {
+ const T &value_ = *(const T *)value;
+ varray_->set(index, value_);
+ }
+
+ void set_by_relocate_impl(const int64_t index, void *value) override
+ {
+ T &value_ = *(T *)value;
+ varray_->set(index, std::move(value_));
+ value_.~T();
+ }
+
+ void set_by_move_impl(const int64_t index, void *value) override
+ {
+ T &value_ = *(T *)value;
+ varray_->set(index, std::move(value_));
+ }
+
+ const void *try_get_internal_varray_impl() const override
+ {
+ return (const VArray<T> *)varray_;
+ }
+
+ void *try_get_internal_mutable_varray_impl() override
+ {
+ return varray_;
+ }
+};
+
+/* A generic version of VArray_Span. */
+class GVArray_GSpan : public GSpan {
+ private:
+ const GVArray &varray_;
+ void *owned_data_ = nullptr;
+
+ public:
+ GVArray_GSpan(const GVArray &varray);
+ ~GVArray_GSpan();
+};
+
+/* A generic version of VMutableArray_Span. */
+class GVMutableArray_GSpan : public GMutableSpan {
+ private:
+ GVMutableArray &varray_;
+ void *owned_data_ = nullptr;
+ bool save_has_been_called_ = false;
+ bool show_not_saved_warning_ = true;
+
+ public:
+ GVMutableArray_GSpan(GVMutableArray &varray, bool copy_values_to_span = true);
+ ~GVMutableArray_GSpan();
+
+ void save();
+ void disable_not_applied_warning();
+};
+
+/* Similar to GVArray_GSpan, but the resulting span is typed. */
+template<typename T> class GVArray_Span : public Span<T> {
+ private:
+ GVArray_GSpan varray_gspan_;
+
+ public:
+ GVArray_Span(const GVArray &varray) : varray_gspan_(varray)
+ {
+ BLI_assert(varray.type().is<T>());
+ this->data_ = (const T *)varray_gspan_.data();
+ this->size_ = varray_gspan_.size();
+ }
+};
+
+template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> {
+ private:
+ VArrayPtr<T> owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ GVArray_For_OwnedVArray(VArrayPtr<T> varray)
+ : GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> {
+ private:
+ GVArrayPtr owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ VArray_For_OwnedGVArray(GVArrayPtr varray)
+ : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+template<typename T>
+class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
+ private:
+ VMutableArrayPtr<T> owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<T> varray)
+ : GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+template<typename T>
+class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> {
+ private:
+ GVMutableArrayPtr owned_varray_;
+
+ public:
+ /* Takes ownership of varray and passes a reference to the base class. */
+ VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr varray)
+ : VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray))
+ {
+ }
+};
+
+/* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give
+ * the compiler more opportunity to optimize the generic virtual array. */
+template<typename T, typename VArrayT>
+class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> {
+ private:
+ VArrayT embedded_varray_;
+
+ public:
+ template<typename... Args>
+ GVArray_For_EmbeddedVArray(const int64_t size, Args &&... args)
+ : GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
+ {
+ this->varray_ = &embedded_varray_;
+ }
+};
+
+/* Same as GVArray_For_EmbeddedVArray, but for mutable virtual arrays. */
+template<typename T, typename VMutableArrayT>
+class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMutableArray<T> {
+ private:
+ VMutableArrayT embedded_varray_;
+
+ public:
+ template<typename... Args>
+ GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&... args)
+ : GVMutableArray_For_VMutableArray<T>(size), embedded_varray_(std::forward<Args>(args)...)
+ {
+ this->varray_ = &embedded_varray_;
+ }
+};
+
+/* Same as VArray_For_ArrayContainer, but for a generic virtual array. */
+template<typename Container, typename T = typename Container::value_type>
+class GVArray_For_ArrayContainer
+ : public GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>> {
+ public:
+ GVArray_For_ArrayContainer(Container container)
+ : GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>>(
+ container.size(), std::move(container))
+ {
+ }
+};
+
+/* Same as VArray_For_DerivedSpan, but for a generic virtual array. */
+template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)>
+class GVArray_For_DerivedSpan
+ : public GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>> {
+ public:
+ GVArray_For_DerivedSpan(const Span<StructT> data)
+ : GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>>(
+ data.size(), data)
+ {
+ }
+};
+
+/* Same as VMutableArray_For_DerivedSpan, but for a generic virtual array. */
+template<typename StructT,
+ typename ElemT,
+ ElemT (*GetFunc)(const StructT &),
+ void (*SetFunc)(StructT &, ElemT)>
+class GVMutableArray_For_DerivedSpan
+ : public GVMutableArray_For_EmbeddedVMutableArray<
+ ElemT,
+ VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> {
+ public:
+ GVMutableArray_For_DerivedSpan(const MutableSpan<StructT> data)
+ : GVMutableArray_For_EmbeddedVMutableArray<
+ ElemT,
+ VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(data.size(), data)
+ {
+ }
+};
+
+/* Same as VArray_For_Span, but for a generic virtual array. */
+template<typename T>
+class GVArray_For_Span : public GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>> {
+ public:
+ GVArray_For_Span(const Span<T> data)
+ : GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>>(data.size(), data)
+ {
+ }
+};
+
+/* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */
+template<typename T>
+class GVMutableArray_For_MutableSpan
+ : public GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>> {
+ public:
+ GVMutableArray_For_MutableSpan(const MutableSpan<T> data)
+ : GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(),
+ data)
+ {
+ }
+};
+
+/**
+ * Utility class to create the "best" typed virtual array for a given generic virtual array.
+ * In most cases we don't just want to use VArray_For_GVArray, because it adds an additional
+ * indirection on element-access that can be avoided in many cases (e.g. when the virtual array is
+ * just a span or single value).
+ *
+ * This is not a virtual array itself, but is used to get a virtual array.
+ */
+template<typename T> class GVArray_Typed {
+ private:
+ const VArray<T> *varray_;
+ /* Of these optional virtual arrays, at most one is constructed at any time. */
+ std::optional<VArray_For_Span<T>> varray_span_;
+ std::optional<VArray_For_Single<T>> varray_single_;
+ std::optional<VArray_For_GVArray<T>> varray_any_;
+ GVArrayPtr owned_gvarray_;
+
+ public:
+ explicit GVArray_Typed(const GVArray &gvarray)
+ {
+ BLI_assert(gvarray.type().is<T>());
+ if (gvarray.is_span()) {
+ const GSpan span = gvarray.get_internal_span();
+ varray_span_.emplace(span.typed<T>());
+ varray_ = &*varray_span_;
+ }
+ else if (gvarray.is_single()) {
+ T single_value;
+ gvarray.get_internal_single(&single_value);
+ varray_single_.emplace(single_value, gvarray.size());
+ varray_ = &*varray_single_;
+ }
+ else if (const VArray<T> *internal_varray = gvarray.try_get_internal_varray<T>()) {
+ varray_ = internal_varray;
+ }
+ else {
+ varray_any_.emplace(gvarray);
+ varray_ = &*varray_any_;
+ }
+ }
+
+ /* Same as the constructor above, but also takes ownership of the passed in virtual array. */
+ explicit GVArray_Typed(GVArrayPtr gvarray) : GVArray_Typed(*gvarray)
+ {
+ owned_gvarray_ = std::move(gvarray);
+ }
+
+ const VArray<T> &operator*() const
+ {
+ return *varray_;
+ }
+
+ const VArray<T> *operator->() const
+ {
+ return varray_;
+ }
+
+ /* Support implicit cast to the typed virtual array for convenience when `varray->typed<T>()` is
+ * used within an expression. */
+ operator const VArray<T> &() const
+ {
+ return *varray_;
+ }
+
+ T operator[](const int64_t index) const
+ {
+ return varray_->get(index);
+ }
+
+ int64_t size() const
+ {
+ return varray_->size();
+ }
+
+ IndexRange index_range() const
+ {
+ return IndexRange(this->size());
+ }
+};
+
+/* Same as GVArray_Typed, but for mutable virtual arrays. */
+template<typename T> class GVMutableArray_Typed {
+ private:
+ VMutableArray<T> *varray_;
+ std::optional<VMutableArray_For_MutableSpan<T>> varray_span_;
+ std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_;
+ GVMutableArrayPtr owned_gvarray_;
+
+ public:
+ explicit GVMutableArray_Typed(GVMutableArray &gvarray)
+ {
+ BLI_assert(gvarray.type().is<T>());
+ if (gvarray.is_span()) {
+ const GMutableSpan span = gvarray.get_internal_span();
+ varray_span_.emplace(span.typed<T>());
+ varray_ = &*varray_span_;
+ }
+ else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) {
+ varray_ = internal_varray;
+ }
+ else {
+ varray_any_.emplace(gvarray);
+ varray_ = &*varray_any_;
+ }
+ }
+
+ explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray)
+ {
+ owned_gvarray_ = std::move(gvarray);
+ }
+
+ VMutableArray<T> &operator*()
+ {
+ return *varray_;
+ }
+
+ VMutableArray<T> *operator->()
+ {
+ return varray_;
+ }
+
+ operator VMutableArray<T> &()
+ {
+ return *varray_;
+ }
+
+ T operator[](const int64_t index) const
+ {
+ return varray_->get(index);
+ }
+
+ int64_t size() const
+ {
+ return varray_->size();
+ }
+};
+
} // namespace blender::fn
diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/functions/FN_generic_virtual_vector_array.hh
index ef3f53b5c25..4155a55a801 100644
--- a/source/blender/functions/FN_generic_virtual_vector_array.hh
+++ b/source/blender/functions/FN_generic_virtual_vector_array.hh
@@ -100,13 +100,13 @@ class GVVectorArray {
}
};
-class GVArrayForGVVectorArrayIndex : public GVArray {
+class GVArray_For_GVVectorArrayIndex : public GVArray {
private:
const GVVectorArray &vector_array_;
const int64_t index_;
public:
- GVArrayForGVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index)
+ GVArray_For_GVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index)
: GVArray(vector_array.type(), vector_array.get_vector_size(index)),
vector_array_(vector_array),
index_(index)
@@ -118,12 +118,12 @@ class GVArrayForGVVectorArrayIndex : public GVArray {
void get_to_uninitialized_impl(const int64_t index_in_vector, void *r_value) const override;
};
-class GVVectorArrayForSingleGVArray : public GVVectorArray {
+class GVVectorArray_For_SingleGVArray : public GVVectorArray {
private:
const GVArray &array_;
public:
- GVVectorArrayForSingleGVArray(const GVArray &array, const int64_t size)
+ GVVectorArray_For_SingleGVArray(const GVArray &array, const int64_t size)
: GVVectorArray(array.type(), size), array_(array)
{
}
@@ -137,12 +137,12 @@ class GVVectorArrayForSingleGVArray : public GVVectorArray {
bool is_single_vector_impl() const override;
};
-class GVVectorArrayForSingleGSpan : public GVVectorArray {
+class GVVectorArray_For_SingleGSpan : public GVVectorArray {
private:
const GSpan span_;
public:
- GVVectorArrayForSingleGSpan(const GSpan span, const int64_t size)
+ GVVectorArray_For_SingleGSpan(const GSpan span, const int64_t size)
: GVVectorArray(span.type(), size), span_(span)
{
}
@@ -156,12 +156,12 @@ class GVVectorArrayForSingleGSpan : public GVVectorArray {
bool is_single_vector_impl() const override;
};
-template<typename T> class VVectorArrayForGVVectorArray : public VVectorArray<T> {
+template<typename T> class VVectorArray_For_GVVectorArray : public VVectorArray<T> {
private:
const GVVectorArray &vector_array_;
public:
- VVectorArrayForGVVectorArray(const GVVectorArray &vector_array)
+ VVectorArray_For_GVVectorArray(const GVVectorArray &vector_array)
: VVectorArray<T>(vector_array.size()), vector_array_(vector_array)
{
}
diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh
index 72ebc0d9b94..3b15f0278f3 100644
--- a/source/blender/functions/FN_multi_function_params.hh
+++ b/source/blender/functions/FN_multi_function_params.hh
@@ -55,13 +55,13 @@ class MFParamsBuilder {
template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "")
{
- this->add_readonly_single_input(scope_.construct<GVArrayForSingleValueRef>(
+ this->add_readonly_single_input(scope_.construct<GVArray_For_SingleValueRef>(
__func__, CPPType::get<T>(), min_array_size_, value),
expected_name);
}
void add_readonly_single_input(const GSpan span, StringRef expected_name = "")
{
- this->add_readonly_single_input(scope_.construct<GVArrayForGSpan>(__func__, span),
+ this->add_readonly_single_input(scope_.construct<GVArray_For_GSpan>(__func__, span),
expected_name);
}
void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "")
@@ -74,7 +74,7 @@ class MFParamsBuilder {
void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "")
{
this->add_readonly_vector_input(
- scope_.construct<GVVectorArrayForGVectorArray>(__func__, vector_array), expected_name);
+ scope_.construct<GVVectorArray_For_GVectorArray>(__func__, vector_array), expected_name);
}
void add_readonly_vector_input(const GVVectorArray &ref, StringRef expected_name = "")
{
@@ -177,7 +177,7 @@ class MFParams {
template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "")
{
const GVArray &array = this->readonly_single_input(param_index, name);
- return builder_->scope_.construct<VArrayForGVArray<T>>(__func__, array);
+ return builder_->scope_.construct<VArray_For_GVArray<T>>(__func__, array);
}
const GVArray &readonly_single_input(int param_index, StringRef name = "")
{
@@ -202,7 +202,7 @@ class MFParams {
const VVectorArray<T> &readonly_vector_input(int param_index, StringRef name = "")
{
const GVVectorArray &vector_array = this->readonly_vector_input(param_index, name);
- return builder_->scope_.construct<VVectorArrayForGVVectorArray<T>>(__func__, vector_array);
+ return builder_->scope_.construct<VVectorArray_For_GVVectorArray<T>>(__func__, vector_array);
}
const GVVectorArray &readonly_vector_input(int param_index, StringRef name = "")
{
diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc
index b3c5517cc43..3335b07e559 100644
--- a/source/blender/functions/intern/generic_vector_array.cc
+++ b/source/blender/functions/intern/generic_vector_array.cc
@@ -60,21 +60,21 @@ void GVectorArray::extend(const int64_t index, const GVArray &values)
void GVectorArray::extend(const int64_t index, const GSpan values)
{
- GVArrayForGSpan varray{values};
+ GVArray_For_GSpan varray{values};
this->extend(index, varray);
}
void GVectorArray::extend(IndexMask mask, const GVVectorArray &values)
{
for (const int i : mask) {
- GVArrayForGVVectorArrayIndex array{values, i};
+ GVArray_For_GVVectorArrayIndex array{values, i};
this->extend(i, array);
}
}
void GVectorArray::extend(IndexMask mask, const GVectorArray &values)
{
- GVVectorArrayForGVectorArray virtual_values{values};
+ GVVectorArray_For_GVectorArray virtual_values{values};
this->extend(mask, virtual_values);
}
diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc
index 9380eb257b2..e11501828f8 100644
--- a/source/blender/functions/intern/generic_virtual_array.cc
+++ b/source/blender/functions/intern/generic_virtual_array.cc
@@ -18,6 +18,10 @@
namespace blender::fn {
+/* --------------------------------------------------------------------
+ * GVArray.
+ */
+
void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const
{
for (const int64_t i : mask) {
@@ -37,7 +41,7 @@ bool GVArray::is_span_impl() const
return false;
}
-GSpan GVArray::get_span_impl() const
+GSpan GVArray::get_internal_span_impl() const
{
BLI_assert(false);
return GSpan(*type_);
@@ -48,60 +52,246 @@ bool GVArray::is_single_impl() const
return false;
}
-void GVArray::get_single_impl(void *UNUSED(r_value)) const
+void GVArray::get_internal_single_impl(void *UNUSED(r_value)) const
{
BLI_assert(false);
}
-void GVArrayForGSpan::get_impl(const int64_t index, void *r_value) const
+const void *GVArray::try_get_internal_varray_impl() const
+{
+ return nullptr;
+}
+
+/* --------------------------------------------------------------------
+ * GVMutableArray.
+ */
+
+void GVMutableArray::set_by_copy_impl(const int64_t index, const void *value)
+{
+ BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer);
+ type_->copy_to_uninitialized(value, buffer);
+ this->set_by_move_impl(index, buffer);
+ type_->destruct(buffer);
+}
+
+void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value)
+{
+ this->set_by_move_impl(index, value);
+ type_->destruct(value);
+}
+
+void *GVMutableArray::try_get_internal_mutable_varray_impl()
+{
+ return nullptr;
+}
+
+void GVMutableArray::fill(const void *value)
+{
+ if (this->is_span()) {
+ const GMutableSpan span = this->get_internal_span();
+ type_->fill_initialized(value, span.data(), size_);
+ }
+ else {
+ for (int64_t i : IndexRange(size_)) {
+ this->set_by_copy(i, value);
+ }
+ }
+}
+
+/* --------------------------------------------------------------------
+ * GVArray_For_GSpan.
+ */
+
+void GVArray_For_GSpan::get_impl(const int64_t index, void *r_value) const
{
type_->copy_to_initialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-void GVArrayForGSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const
+void GVArray_For_GSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const
{
type_->copy_to_uninitialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
}
-bool GVArrayForGSpan::is_span_impl() const
+bool GVArray_For_GSpan::is_span_impl() const
{
return true;
}
-GSpan GVArrayForGSpan::get_span_impl() const
+GSpan GVArray_For_GSpan::get_internal_span_impl() const
{
return GSpan(*type_, data_, size_);
}
-void GVArrayForSingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const
+/* --------------------------------------------------------------------
+ * GVMutableArray_For_GMutableSpan.
+ */
+
+void GVMutableArray_For_GMutableSpan::get_impl(const int64_t index, void *r_value) const
+{
+ type_->copy_to_initialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
+}
+
+void GVMutableArray_For_GMutableSpan::get_to_uninitialized_impl(const int64_t index,
+ void *r_value) const
+{
+ type_->copy_to_uninitialized(POINTER_OFFSET(data_, element_size_ * index), r_value);
+}
+
+void GVMutableArray_For_GMutableSpan::set_by_copy_impl(const int64_t index, const void *value)
+{
+ type_->copy_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index));
+}
+
+void GVMutableArray_For_GMutableSpan::set_by_move_impl(const int64_t index, void *value)
+{
+ type_->move_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index));
+}
+
+void GVMutableArray_For_GMutableSpan::set_by_relocate_impl(const int64_t index, void *value)
+{
+ type_->relocate_to_initialized(value, POINTER_OFFSET(data_, element_size_ * index));
+}
+
+bool GVMutableArray_For_GMutableSpan::is_span_impl() const
+{
+ return true;
+}
+
+GSpan GVMutableArray_For_GMutableSpan::get_internal_span_impl() const
+{
+ return GSpan(*type_, data_, size_);
+}
+
+/* --------------------------------------------------------------------
+ * GVArray_For_SingleValueRef.
+ */
+
+void GVArray_For_SingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const
{
type_->copy_to_initialized(value_, r_value);
}
-void GVArrayForSingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index),
- void *r_value) const
+void GVArray_For_SingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index),
+ void *r_value) const
{
type_->copy_to_uninitialized(value_, r_value);
}
-bool GVArrayForSingleValueRef::is_span_impl() const
+bool GVArray_For_SingleValueRef::is_span_impl() const
{
return size_ == 1;
}
-GSpan GVArrayForSingleValueRef::get_span_impl() const
+GSpan GVArray_For_SingleValueRef::get_internal_span_impl() const
{
return GSpan{*type_, value_, 1};
}
-bool GVArrayForSingleValueRef::is_single_impl() const
+bool GVArray_For_SingleValueRef::is_single_impl() const
{
return true;
}
-void GVArrayForSingleValueRef::get_single_impl(void *r_value) const
+void GVArray_For_SingleValueRef::get_internal_single_impl(void *r_value) const
{
type_->copy_to_initialized(value_, r_value);
}
+/* --------------------------------------------------------------------
+ * GVArray_For_SingleValue.
+ */
+
+GVArray_For_SingleValue::GVArray_For_SingleValue(const CPPType &type,
+ const int64_t size,
+ const void *value)
+ : GVArray_For_SingleValueRef(type, size)
+{
+ value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__);
+ type.copy_to_uninitialized(value, (void *)value_);
+}
+
+GVArray_For_SingleValue::~GVArray_For_SingleValue()
+{
+ type_->destruct((void *)value_);
+ MEM_freeN((void *)value_);
+}
+
+/* --------------------------------------------------------------------
+ * GVArray_GSpan.
+ */
+
+GVArray_GSpan::GVArray_GSpan(const GVArray &varray) : GSpan(varray.type()), varray_(varray)
+{
+ size_ = varray_.size();
+ if (varray_.is_span()) {
+ data_ = varray_.get_internal_span().data();
+ }
+ else {
+ owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__);
+ varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_);
+ data_ = owned_data_;
+ }
+}
+
+GVArray_GSpan::~GVArray_GSpan()
+{
+ if (owned_data_ != nullptr) {
+ type_->destruct_n(owned_data_, size_);
+ MEM_freeN(owned_data_);
+ }
+}
+
+/* --------------------------------------------------------------------
+ * GVMutableArray_GSpan.
+ */
+
+GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray &varray, const bool copy_values_to_span)
+ : GMutableSpan(varray.type()), varray_(varray)
+{
+ size_ = varray_.size();
+ if (varray_.is_span()) {
+ data_ = varray_.get_internal_span().data();
+ }
+ else {
+ owned_data_ = MEM_mallocN_aligned(type_->size() * size_, type_->alignment(), __func__);
+ if (copy_values_to_span) {
+ varray_.materialize_to_uninitialized(IndexRange(size_), owned_data_);
+ }
+ else {
+ type_->construct_default_n(owned_data_, size_);
+ }
+ data_ = owned_data_;
+ }
+}
+
+GVMutableArray_GSpan::~GVMutableArray_GSpan()
+{
+ if (show_not_saved_warning_) {
+ if (!save_has_been_called_) {
+ std::cout << "Warning: Call `apply()` to make sure that changes persist in all cases.\n";
+ }
+ }
+ if (owned_data_ != nullptr) {
+ type_->destruct_n(owned_data_, size_);
+ MEM_freeN(owned_data_);
+ }
+}
+
+void GVMutableArray_GSpan::save()
+{
+ save_has_been_called_ = true;
+ if (data_ != owned_data_) {
+ return;
+ }
+ const int64_t element_size = type_->size();
+ for (int64_t i : IndexRange(size_)) {
+ varray_.set_by_copy(i, POINTER_OFFSET(owned_data_, element_size * i));
+ }
+}
+
+void GVMutableArray_GSpan::disable_not_applied_warning()
+{
+ show_not_saved_warning_ = false;
+}
+
} // namespace blender::fn
diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/functions/intern/generic_virtual_vector_array.cc
index f6504cee41e..aa3d90883c6 100644
--- a/source/blender/functions/intern/generic_virtual_vector_array.cc
+++ b/source/blender/functions/intern/generic_virtual_vector_array.cc
@@ -18,48 +18,48 @@
namespace blender::fn {
-void GVArrayForGVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const
+void GVArray_For_GVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const
{
vector_array_.get_vector_element(index_, index_in_vector, r_value);
}
-void GVArrayForGVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector,
- void *r_value) const
+void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector,
+ void *r_value) const
{
type_->construct_default(r_value);
vector_array_.get_vector_element(index_, index_in_vector, r_value);
}
-int64_t GVVectorArrayForSingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const
+int64_t GVVectorArray_For_SingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const
{
return array_.size();
}
-void GVVectorArrayForSingleGVArray::get_vector_element_impl(const int64_t UNUSED(index),
- const int64_t index_in_vector,
- void *r_value) const
+void GVVectorArray_For_SingleGVArray::get_vector_element_impl(const int64_t UNUSED(index),
+ const int64_t index_in_vector,
+ void *r_value) const
{
array_.get(index_in_vector, r_value);
}
-bool GVVectorArrayForSingleGVArray::is_single_vector_impl() const
+bool GVVectorArray_For_SingleGVArray::is_single_vector_impl() const
{
return true;
}
-int64_t GVVectorArrayForSingleGSpan::get_vector_size_impl(const int64_t UNUSED(index)) const
+int64_t GVVectorArray_For_SingleGSpan::get_vector_size_impl(const int64_t UNUSED(index)) const
{
return span_.size();
}
-void GVVectorArrayForSingleGSpan::get_vector_element_impl(const int64_t UNUSED(index),
- const int64_t index_in_vector,
- void *r_value) const
+void GVVectorArray_For_SingleGSpan::get_vector_element_impl(const int64_t UNUSED(index),
+ const int64_t index_in_vector,
+ void *r_value) const
{
type_->copy_to_initialized(span_[index_in_vector], r_value);
}
-bool GVVectorArrayForSingleGSpan::is_single_vector_impl() const
+bool GVVectorArray_For_SingleGSpan::is_single_vector_impl() const
{
return true;
}
diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc
index 86ac4f6a179..9a0cb0c35ce 100644
--- a/source/blender/functions/intern/multi_function_network_evaluation.cc
+++ b/source/blender/functions/intern/multi_function_network_evaluation.cc
@@ -974,11 +974,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputS
if (any_value->type == ValueType::OwnSingle) {
OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
if (value->is_single_allocated) {
- return scope.construct<GVArrayForSingleValueRef>(
+ return scope.construct<GVArray_For_SingleValueRef>(
__func__, value->span.type(), min_array_size_, value->span.data());
}
- return scope.construct<GVArrayForGSpan>(__func__, value->span);
+ return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
if (any_value->type == ValueType::InputSingle) {
InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
@@ -987,11 +987,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__full(const MFInputS
if (any_value->type == ValueType::OutputSingle) {
OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
BLI_assert(value->is_computed);
- return scope.construct<GVArrayForGSpan>(__func__, value->span);
+ return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
BLI_assert(false);
- return scope.construct<GVArrayForEmpty>(__func__, CPPType::get<float>());
+ return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>());
}
const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInputSocket &socket,
@@ -1004,7 +1004,7 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInpu
if (any_value->type == ValueType::OwnSingle) {
OwnSingleValue *value = static_cast<OwnSingleValue *>(any_value);
BLI_assert(value->span.size() == 1);
- return scope.construct<GVArrayForGSpan>(__func__, value->span);
+ return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
if (any_value->type == ValueType::InputSingle) {
InputSingleValue *value = static_cast<InputSingleValue *>(any_value);
@@ -1015,11 +1015,11 @@ const GVArray &MFNetworkEvaluationStorage::get_single_input__single(const MFInpu
OutputSingleValue *value = static_cast<OutputSingleValue *>(any_value);
BLI_assert(value->is_computed);
BLI_assert(value->span.size() == 1);
- return scope.construct<GVArrayForGSpan>(__func__, value->span);
+ return scope.construct<GVArray_For_GSpan>(__func__, value->span);
}
BLI_assert(false);
- return scope.construct<GVArrayForEmpty>(__func__, CPPType::get<float>());
+ return scope.construct<GVArray_For_Empty>(__func__, CPPType::get<float>());
}
const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
@@ -1033,10 +1033,10 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
if (value->vector_array->size() == 1) {
GSpan span = (*value->vector_array)[0];
- return scope.construct<GVVectorArrayForSingleGSpan>(__func__, span, min_array_size_);
+ return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, span, min_array_size_);
}
- return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
+ return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
if (any_value->type == ValueType::InputVector) {
InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
@@ -1044,11 +1044,11 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__full(
}
if (any_value->type == ValueType::OutputVector) {
OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
- return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
+ return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
BLI_assert(false);
- return scope.construct<GVVectorArrayForSingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
+ return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
}
const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
@@ -1061,7 +1061,7 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
if (any_value->type == ValueType::OwnVector) {
OwnVectorValue *value = static_cast<OwnVectorValue *>(any_value);
BLI_assert(value->vector_array->size() == 1);
- return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
+ return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
if (any_value->type == ValueType::InputVector) {
InputVectorValue *value = static_cast<InputVectorValue *>(any_value);
@@ -1071,11 +1071,11 @@ const GVVectorArray &MFNetworkEvaluationStorage::get_vector_input__single(
if (any_value->type == ValueType::OutputVector) {
OutputVectorValue *value = static_cast<OutputVectorValue *>(any_value);
BLI_assert(value->vector_array->size() == 1);
- return scope.construct<GVVectorArrayForGVectorArray>(__func__, *value->vector_array);
+ return scope.construct<GVVectorArray_For_GVectorArray>(__func__, *value->vector_array);
}
BLI_assert(false);
- return scope.construct<GVVectorArrayForSingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
+ return scope.construct<GVVectorArray_For_SingleGSpan>(__func__, GSpan(CPPType::get<float>()), 0);
}
/** \} */
diff --git a/source/blender/functions/tests/FN_multi_function_network_test.cc b/source/blender/functions/tests/FN_multi_function_network_test.cc
index 51e116b5983..7b9738e5ca4 100644
--- a/source/blender/functions/tests/FN_multi_function_network_test.cc
+++ b/source/blender/functions/tests/FN_multi_function_network_test.cc
@@ -223,7 +223,7 @@ TEST(multi_function_network, Test2)
Array<int> output_value_2(5, -1);
MFParamsBuilder params(network_fn, 5);
- GVVectorArrayForSingleGSpan inputs_1{input_value_1.as_span(), 5};
+ GVVectorArray_For_SingleGSpan inputs_1{input_value_1.as_span(), 5};
params.add_readonly_vector_input(inputs_1);
params.add_readonly_single_input(&input_value_2);
params.add_vector_output(output_value_1);
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 282d71f6a87..f57515c0e93 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1308,6 +1308,11 @@ typedef struct NodeGeometryMeshLine {
uint8_t count_mode;
} NodeGeometryMeshLine;
+typedef struct NodeSwitch {
+ /* NodeSwitch. */
+ uint8_t input_type;
+} NodeSwitch;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index ab74282eb64..cf3e31f7d9a 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -1911,7 +1911,7 @@ typedef struct SpaceSpreadsheet {
/**
* List of #SpreadsheetContext.
* This is a path to the data that is displayed in the spreadsheet.
- * It can be set explicitely by an action of the user (e.g. clicking the preview icon in a
+ * It can be set explicitly by an action of the user (e.g. clicking the preview icon in a
* geometry node) or it can be derived from context automatically based on some heuristic.
*/
ListBase context_path;
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 657af98f5fe..3c641c6ec1a 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -148,6 +148,8 @@ static const EnumPropertyItem rna_enum_override_library_property_operation_items
# include "DEG_depsgraph_build.h"
# include "DEG_depsgraph_query.h"
+# include "ED_asset.h"
+
# include "WM_api.h"
void rna_ID_override_library_property_operation_refname_get(PointerRNA *ptr, char *value)
@@ -575,6 +577,22 @@ static ID *rna_ID_copy(ID *id, Main *bmain)
return newid;
}
+static void rna_ID_mark_asset(ID *id, bContext *C)
+{
+ if (ED_asset_mark_id(C, id)) {
+ WM_main_add_notifier(NC_ID | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_ASSET | NA_ADDED, NULL);
+ }
+}
+
+static void rna_ID_clear_asset(ID *id)
+{
+ if (ED_asset_clear_id(id)) {
+ WM_main_add_notifier(NC_ID | NA_EDITED, NULL);
+ WM_main_add_notifier(NC_ASSET | NA_REMOVED, NULL);
+ }
+}
+
static ID *rna_ID_override_create(ID *id, Main *bmain, bool remap_local_usages)
{
if (!ID_IS_OVERRIDABLE_LIBRARY(id)) {
@@ -1716,6 +1734,18 @@ static void rna_def_ID(BlenderRNA *brna)
parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID");
RNA_def_function_return(func, parm);
+ func = RNA_def_function(srna, "mark_asset", "rna_ID_mark_asset");
+ RNA_def_function_ui_description(
+ func,
+ "Enable easier reuse of the data-block through the Asset Browser, with the help of "
+ "customizable metadata (like previews, descriptions and tags)");
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+
+ func = RNA_def_function(srna, "clear_asset", "rna_ID_clear_asset");
+ RNA_def_function_ui_description(
+ func,
+ "Delete all asset metadata and turn the asset data-block back into a normal data-block");
+
func = RNA_def_function(srna, "override_create", "rna_ID_override_create");
RNA_def_function_ui_description(func,
"Create an overridden local copy of this linked data-block (not "
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index b0254ce2ef3..1da711f260c 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -65,6 +65,20 @@
const EnumPropertyItem rna_enum_node_socket_in_out_items[] = {
{SOCK_IN, "IN", 0, "Input", ""}, {SOCK_OUT, "OUT", 0, "Output", ""}, {0, NULL, 0, NULL, NULL}};
+static const EnumPropertyItem node_socket_data_type_items[] = {
+ {SOCK_FLOAT, "FLOAT", 0, "Float", ""},
+ {SOCK_INT, "INT", 0, "Int", ""},
+ {SOCK_BOOLEAN, "BOOLEAN", 0, "Boolean", ""},
+ {SOCK_VECTOR, "VECTOR", 0, "Vector", ""},
+ {SOCK_STRING, "STRING", 0, "String", ""},
+ {SOCK_RGBA, "RGBA", 0, "Color", ""},
+ {SOCK_OBJECT, "OBJECT", 0, "Object", ""},
+ {SOCK_IMAGE, "IMAGE", 0, "Image", ""},
+ {SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""},
+ {SOCK_COLLECTION, "COLLECTION", 0, "Collection", ""},
+ {0, NULL, 0, NULL, NULL},
+};
+
#ifndef RNA_RUNTIME
static const EnumPropertyItem rna_enum_node_socket_display_shape_items[] = {
{SOCK_DISPLAY_SHAPE_CIRCLE, "CIRCLE", 0, "Circle", ""},
@@ -1913,6 +1927,29 @@ static const EnumPropertyItem *itemf_function_check(
return item_array;
}
+static bool switch_type_supported(const EnumPropertyItem *item)
+{
+ return ELEM(item->value,
+ SOCK_FLOAT,
+ SOCK_INT,
+ SOCK_BOOLEAN,
+ SOCK_VECTOR,
+ SOCK_STRING,
+ SOCK_RGBA,
+ SOCK_GEOMETRY,
+ SOCK_OBJECT,
+ SOCK_COLLECTION);
+}
+
+static const EnumPropertyItem *rna_GeometryNodeSwitch_type_itemf(bContext *UNUSED(C),
+ PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop),
+ bool *r_free)
+{
+ *r_free = true;
+ return itemf_function_check(node_socket_data_type_items, switch_type_supported);
+}
+
static bool attribute_clamp_type_supported(const EnumPropertyItem *item)
{
return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR);
@@ -9630,6 +9667,19 @@ static void def_geo_mesh_line(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_switch(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeSwitch", "storage");
+ prop = RNA_def_property(srna, "input_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "input_type");
+ RNA_def_property_enum_items(prop, node_socket_data_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeSwitch_type_itemf");
+ RNA_def_property_ui_text(prop, "Input Type", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
/* -------------------------------------------------------------------------- */
static void rna_def_shader_node(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 6b93a1c223c..3edfd5c44f4 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -84,7 +84,7 @@ const EnumPropertyItem rna_enum_object_mode_items[] = {
{OB_MODE_PAINT_GPENCIL,
"PAINT_GPENCIL",
ICON_GREASEPENCIL,
- "Draw",
+ "Draw Mode",
"Paint Grease Pencil Strokes"},
{OB_MODE_WEIGHT_GPENCIL,
"WEIGHT_GPENCIL",
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 8168f0dba73..7a966b660b4 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -180,6 +180,7 @@ set(SRC
geometry/nodes/node_geo_points_to_volume.cc
geometry/nodes/node_geo_subdivide.cc
geometry/nodes/node_geo_subdivision_surface.cc
+ geometry/nodes/node_geo_switch.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
geometry/nodes/node_geo_volume_to_mesh.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index b84c80e916c..74d77787eea 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -69,6 +69,7 @@ void register_node_type_geo_points_to_volume(void);
void register_node_type_geo_sample_texture(void);
void register_node_type_geo_subdivide(void);
void register_node_type_geo_subdivision_surface(void);
+void register_node_type_geo_switch(void);
void register_node_type_geo_transform(void);
void register_node_type_geo_triangulate(void);
void register_node_type_geo_volume_to_mesh(void);
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index 5d1a217db9b..f2582600c7d 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -33,29 +33,28 @@ struct ModifierData;
namespace blender::nodes {
-using bke::BooleanReadAttribute;
-using bke::BooleanWriteAttribute;
-using bke::Color4fReadAttribute;
-using bke::Color4fWriteAttribute;
-using bke::Float2ReadAttribute;
-using bke::Float2WriteAttribute;
-using bke::Float3ReadAttribute;
-using bke::Float3WriteAttribute;
-using bke::FloatReadAttribute;
-using bke::FloatWriteAttribute;
using bke::geometry_set_realize_instances;
-using bke::Int32ReadAttribute;
-using bke::Int32WriteAttribute;
+using bke::OutputAttribute;
+using bke::OutputAttribute_Typed;
using bke::PersistentDataHandleMap;
using bke::PersistentObjectHandle;
-using bke::ReadAttribute;
-using bke::ReadAttributePtr;
-using bke::WriteAttribute;
-using bke::WriteAttributePtr;
+using bke::ReadAttributeLookup;
+using bke::WriteAttributeLookup;
using fn::CPPType;
using fn::GMutablePointer;
+using fn::GMutableSpan;
using fn::GPointer;
+using fn::GSpan;
using fn::GValueMap;
+using fn::GVArray;
+using fn::GVArray_GSpan;
+using fn::GVArray_Span;
+using fn::GVArray_Typed;
+using fn::GVArrayPtr;
+using fn::GVMutableArray;
+using fn::GVMutableArray_GSpan;
+using fn::GVMutableArray_Typed;
+using fn::GVMutableArrayPtr;
class GeoNodeExecParams {
private:
@@ -217,20 +216,21 @@ class GeoNodeExecParams {
* \note This will add an error message if the string socket is active and
* the input attribute does not exist.
*/
- ReadAttributePtr get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const CustomDataType type,
- const void *default_value) const;
+ GVArrayPtr get_input_attribute(const StringRef name,
+ const GeometryComponent &component,
+ const AttributeDomain domain,
+ const CustomDataType type,
+ const void *default_value) const;
template<typename T>
- bke::TypedReadAttribute<T> get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const T &default_value) const
+ GVArray_Typed<T> get_input_attribute(const StringRef name,
+ const GeometryComponent &component,
+ const AttributeDomain domain,
+ const T &default_value) const
{
const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>());
- return this->get_input_attribute(name, component, domain, type, &default_value);
+ GVArrayPtr varray = this->get_input_attribute(name, component, domain, type, &default_value);
+ return GVArray_Typed<T>(std::move(varray));
}
/**
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index bf6bf34325a..12e14768c35 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -310,6 +310,7 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", Me
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MAP_RANGE, def_geo_attribute_map_range, "ATTRIBUTE_MAP_RANGE", AttributeMapRange, "Attribute Map Range", "")
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "ATTRIBUTE_CLAMP", AttributeClamp, "Attribute Clamp", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
+DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "")
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/nodes/NOD_type_conversions.hh
index 34225208fe6..ec4859f0657 100644
--- a/source/blender/nodes/NOD_type_conversions.hh
+++ b/source/blender/nodes/NOD_type_conversions.hh
@@ -72,6 +72,10 @@ class DataTypeConversions {
const CPPType &to_type,
const void *from_value,
void *to_value) const;
+
+ fn::GVArrayPtr try_convert(fn::GVArrayPtr varray, const CPPType &to_type) const;
+
+ fn::GVMutableArrayPtr try_convert(fn::GVMutableArrayPtr varray, const CPPType &to_type) const;
};
const DataTypeConversions &get_implicit_type_conversions();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
index f10b81a33b4..c4d37a82617 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_align_rotation_to_vector.cc
@@ -50,10 +50,10 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout,
namespace blender::nodes {
-static void align_rotations_auto_pivot(const Float3ReadAttribute &vectors,
- const FloatReadAttribute &factors,
+static void align_rotations_auto_pivot(const VArray<float3> &vectors,
+ const VArray<float> &factors,
const float3 local_main_axis,
- MutableSpan<float3> rotations)
+ const MutableSpan<float3> rotations)
{
for (const int i : IndexRange(vectors.size())) {
const float3 vector = vectors[i];
@@ -93,11 +93,11 @@ static void align_rotations_auto_pivot(const Float3ReadAttribute &vectors,
}
}
-static void align_rotations_fixed_pivot(const Float3ReadAttribute &vectors,
- const FloatReadAttribute &factors,
+static void align_rotations_fixed_pivot(const VArray<float3> &vectors,
+ const VArray<float> &factors,
const float3 local_main_axis,
const float3 local_pivot_axis,
- MutableSpan<float3> rotations)
+ const MutableSpan<float3> rotations)
{
if (local_main_axis == local_pivot_axis) {
/* Can't compute any meaningful rotation angle in this case. */
@@ -144,30 +144,30 @@ static void align_rotations_on_component(GeometryComponent &component,
const NodeGeometryAlignRotationToVector &storage = *(const NodeGeometryAlignRotationToVector *)
node.storage;
- OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
- "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
- if (!rotation_attribute) {
+ OutputAttribute_Typed<float3> rotations = component.attribute_try_get_for_output<float3>(
+ "rotation", ATTR_DOMAIN_POINT, {0, 0, 0});
+ if (!rotations) {
return;
}
- MutableSpan<float3> rotations = rotation_attribute->get_span<float3>();
- FloatReadAttribute factors = params.get_input_attribute<float>(
+ GVArray_Typed<float> factors = params.get_input_attribute<float>(
"Factor", component, ATTR_DOMAIN_POINT, 1.0f);
- Float3ReadAttribute vectors = params.get_input_attribute<float3>(
+ GVArray_Typed<float3> vectors = params.get_input_attribute<float3>(
"Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1});
float3 local_main_axis{0, 0, 0};
local_main_axis[storage.axis] = 1;
if (storage.pivot_axis == GEO_NODE_ALIGN_ROTATION_TO_VECTOR_PIVOT_AXIS_AUTO) {
- align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations);
+ align_rotations_auto_pivot(vectors, factors, local_main_axis, rotations.as_span());
}
else {
float3 local_pivot_axis{0, 0, 0};
local_pivot_axis[storage.pivot_axis - 1] = 1;
- align_rotations_fixed_pivot(vectors, factors, local_main_axis, local_pivot_axis, rotations);
+ align_rotations_fixed_pivot(
+ vectors, factors, local_main_axis, local_pivot_axis, rotations.as_span());
}
- rotation_attribute.apply_span_and_save();
+ rotations.save();
}
static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
index 95fa24c8bac..e7677ed41e1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
@@ -112,10 +112,13 @@ template<> inline Color4f clamp_value(const Color4f val, const Color4f min, cons
}
template<typename T>
-static void clamp_attribute(Span<T> read_span, MutableSpan<T> span, const T min, const T max)
+static void clamp_attribute(const VArray<T> &inputs,
+ const MutableSpan<T> outputs,
+ const T min,
+ const T max)
{
- for (const int i : span.index_range()) {
- span[i] = clamp_value<T>(read_span[i], min, max);
+ for (const int i : IndexRange(outputs.size())) {
+ outputs[i] = clamp_value<T>(inputs[i], min, max);
}
}
@@ -123,13 +126,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef source_name,
StringRef result_name)
{
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
+ ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name);
if (source_attribute) {
- return source_attribute->domain();
+ return source_attribute.domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -154,10 +157,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
const AttributeDomain domain = get_result_domain(component, attribute_name, result_name);
const int operation = static_cast<int>(storage.operation);
- ReadAttributePtr attribute_input = component.attribute_try_get_for_read(
+ GVArrayPtr attribute_input = component.attribute_try_get_for_read(
attribute_name, domain, data_type);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
+ OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, domain, data_type);
if (!attribute_result) {
@@ -169,8 +172,6 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
switch (data_type) {
case CD_PROP_FLOAT3: {
- Span<float3> read_span = attribute_input->get_span<float3>();
- MutableSpan<float3> span = attribute_result->get_span_for_write_only<float3>();
float3 min = params.get_input<float3>("Min");
float3 max = params.get_input<float3>("Max");
if (operation == NODE_CLAMP_RANGE) {
@@ -184,38 +185,35 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
std::swap(min.z, max.z);
}
}
- clamp_attribute<float3>(read_span, span, min, max);
+ MutableSpan<float3> results = attribute_result.as_span<float3>();
+ clamp_attribute<float3>(attribute_input->typed<float3>(), results, min, max);
break;
}
case CD_PROP_FLOAT: {
- Span<float> read_span = attribute_input->get_span<float>();
- MutableSpan<float> span = attribute_result->get_span_for_write_only<float>();
const float min = params.get_input<float>("Min_001");
const float max = params.get_input<float>("Max_001");
+ MutableSpan<float> results = attribute_result.as_span<float>();
if (operation == NODE_CLAMP_RANGE && min > max) {
- clamp_attribute<float>(read_span, span, max, min);
+ clamp_attribute<float>(attribute_input->typed<float>(), results, max, min);
}
else {
- clamp_attribute<float>(read_span, span, min, max);
+ clamp_attribute<float>(attribute_input->typed<float>(), results, min, max);
}
break;
}
case CD_PROP_INT32: {
- Span<int> read_span = attribute_input->get_span<int>();
- MutableSpan<int> span = attribute_result->get_span_for_write_only<int>();
const int min = params.get_input<int>("Min_002");
const int max = params.get_input<int>("Max_002");
+ MutableSpan<int> results = attribute_result.as_span<int>();
if (operation == NODE_CLAMP_RANGE && min > max) {
- clamp_attribute<int>(read_span, span, max, min);
+ clamp_attribute<int>(attribute_input->typed<int>(), results, max, min);
}
else {
- clamp_attribute<int>(read_span, span, min, max);
+ clamp_attribute<int>(attribute_input->typed<int>(), results, min, max);
}
break;
}
case CD_PROP_COLOR: {
- Span<Color4f> read_span = attribute_input->get_span<Color4f>();
- MutableSpan<Color4f> span = attribute_result->get_span_for_write_only<Color4f>();
Color4f min = params.get_input<Color4f>("Min_003");
Color4f max = params.get_input<Color4f>("Max_003");
if (operation == NODE_CLAMP_RANGE) {
@@ -232,7 +230,8 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
std::swap(min.a, max.a);
}
}
- clamp_attribute<Color4f>(read_span, span, min, max);
+ MutableSpan<Color4f> results = attribute_result.as_span<Color4f>();
+ clamp_attribute<Color4f>(attribute_input->typed<Color4f>(), results, min, max);
break;
}
default: {
@@ -241,7 +240,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
}
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_clamp_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
index 2b913beb670..af65fe110e9 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
@@ -47,15 +47,15 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
/* Otherwise use the input attribute's domain if it exists. */
- ReadAttributePtr input_attribute = component.attribute_try_get_for_read(input_name);
+ ReadAttributeLookup input_attribute = component.attribute_try_get_for_read(input_name);
if (input_attribute) {
- return input_attribute->domain();
+ return input_attribute.domain;
}
return ATTR_DOMAIN_POINT;
@@ -71,27 +71,25 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
/* Always output a color attribute for now. We might want to allow users to customize.
* Using the type of an existing attribute could work, but does not have a real benefit
* currently. */
- const CustomDataType result_type = CD_PROP_COLOR;
const AttributeDomain result_domain = get_result_domain(component, input_name, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
- result_name, result_domain, result_type);
+ OutputAttribute_Typed<Color4f> attribute_result =
+ component.attribute_try_get_for_output_only<Color4f>(result_name, result_domain);
if (!attribute_result) {
return;
}
- FloatReadAttribute attribute_in = component.attribute_get_for_read<float>(
+ GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>(
input_name, result_domain, 0.0f);
- Span<float> data_in = attribute_in.get_span();
- MutableSpan<Color4f> data_out = attribute_result->get_span_for_write_only<Color4f>();
+ MutableSpan<Color4f> results = attribute_result.as_span();
ColorBand *color_ramp = &node_storage->color_ramp;
- for (const int i : data_in.index_range()) {
- BKE_colorband_evaluate(color_ramp, data_in[i], data_out[i]);
+ for (const int i : IndexRange(attribute_in.size())) {
+ BKE_colorband_evaluate(color_ramp, attribute_in[i], results[i]);
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
index e9e07d34c17..c3db26c7299 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_combine_xyz.cc
@@ -77,9 +77,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -94,27 +94,24 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa
}
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
- result_name, result_domain, CD_PROP_FLOAT3);
+ OutputAttribute_Typed<float3> attribute_result =
+ component.attribute_try_get_for_output_only<float3>(result_name, result_domain);
if (!attribute_result) {
return;
}
- FloatReadAttribute attribute_x = params.get_input_attribute<float>(
+ GVArray_Typed<float> attribute_x = params.get_input_attribute<float>(
"X", component, result_domain, 0.0f);
- FloatReadAttribute attribute_y = params.get_input_attribute<float>(
+ GVArray_Typed<float> attribute_y = params.get_input_attribute<float>(
"Y", component, result_domain, 0.0f);
- FloatReadAttribute attribute_z = params.get_input_attribute<float>(
+ GVArray_Typed<float> attribute_z = params.get_input_attribute<float>(
"Z", component, result_domain, 0.0f);
- MutableSpan<float3> results = attribute_result->get_span_for_write_only<float3>();
- for (const int i : results.index_range()) {
+ for (const int i : IndexRange(attribute_result->size())) {
const float x = attribute_x[i];
const float y = attribute_y[i];
const float z = attribute_z[i];
- const float3 result = float3(x, y, z);
- results[i] = result;
+ attribute_result->set(i, {x, y, z});
}
- attribute_result.apply_span_and_save();
}
static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
index fe4045c39a6..22855787ab0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
@@ -81,21 +81,18 @@ static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *n
nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage));
}
-static void do_math_operation(const FloatReadAttribute &input_a,
- const FloatReadAttribute &input_b,
+static void do_math_operation(const VArray<float> &input_a,
+ const VArray<float> &input_b,
const FloatCompareOperation operation,
MutableSpan<bool> span_result)
{
const int size = input_a.size();
- Span<float> span_a = input_a.get_span();
- Span<float> span_b = input_b.get_span();
-
if (try_dispatch_float_math_fl_fl_to_bool(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
for (const int i : IndexRange(size)) {
- const float a = span_a[i];
- const float b = span_b[i];
+ const float a = input_a[i];
+ const float b = input_b[i];
const bool out = math_function(a, b);
span_result[i] = out;
}
@@ -107,8 +104,8 @@ static void do_math_operation(const FloatReadAttribute &input_a,
BLI_assert(false);
}
-static void do_equal_operation_float(const FloatReadAttribute &input_a,
- const FloatReadAttribute &input_b,
+static void do_equal_operation_float(const VArray<float> &input_a,
+ const VArray<float> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -120,8 +117,8 @@ static void do_equal_operation_float(const FloatReadAttribute &input_a,
}
}
-static void do_equal_operation_float3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
+static void do_equal_operation_float3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -134,8 +131,8 @@ static void do_equal_operation_float3(const Float3ReadAttribute &input_a,
}
}
-static void do_equal_operation_color4f(const Color4fReadAttribute &input_a,
- const Color4fReadAttribute &input_b,
+static void do_equal_operation_color4f(const VArray<Color4f> &input_a,
+ const VArray<Color4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -148,8 +145,8 @@ static void do_equal_operation_color4f(const Color4fReadAttribute &input_a,
}
}
-static void do_equal_operation_bool(const BooleanReadAttribute &input_a,
- const BooleanReadAttribute &input_b,
+static void do_equal_operation_bool(const VArray<bool> &input_a,
+ const VArray<bool> &input_b,
const float UNUSED(threshold),
MutableSpan<bool> span_result)
{
@@ -161,8 +158,8 @@ static void do_equal_operation_bool(const BooleanReadAttribute &input_a,
}
}
-static void do_not_equal_operation_float(const FloatReadAttribute &input_a,
- const FloatReadAttribute &input_b,
+static void do_not_equal_operation_float(const VArray<float> &input_a,
+ const VArray<float> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -174,8 +171,8 @@ static void do_not_equal_operation_float(const FloatReadAttribute &input_a,
}
}
-static void do_not_equal_operation_float3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
+static void do_not_equal_operation_float3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -188,8 +185,8 @@ static void do_not_equal_operation_float3(const Float3ReadAttribute &input_a,
}
}
-static void do_not_equal_operation_color4f(const Color4fReadAttribute &input_a,
- const Color4fReadAttribute &input_b,
+static void do_not_equal_operation_color4f(const VArray<Color4f> &input_a,
+ const VArray<Color4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
@@ -202,8 +199,8 @@ static void do_not_equal_operation_color4f(const Color4fReadAttribute &input_a,
}
}
-static void do_not_equal_operation_bool(const BooleanReadAttribute &input_a,
- const BooleanReadAttribute &input_b,
+static void do_not_equal_operation_bool(const VArray<bool> &input_a,
+ const VArray<bool> &input_b,
const float UNUSED(threshold),
MutableSpan<bool> span_result)
{
@@ -237,9 +234,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -254,20 +251,19 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
node_storage->operation);
const std::string result_name = params.get_input<std::string>("Result");
- const CustomDataType result_type = CD_PROP_BOOL;
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
- result_name, result_domain, result_type);
+ OutputAttribute_Typed<bool> attribute_result = component.attribute_try_get_for_output_only<bool>(
+ result_name, result_domain);
if (!attribute_result) {
return;
}
const CustomDataType input_data_type = get_data_type(component, params, *node_storage);
- ReadAttributePtr attribute_a = params.get_input_attribute(
+ GVArrayPtr attribute_a = params.get_input_attribute(
"A", component, result_domain, input_data_type, nullptr);
- ReadAttributePtr attribute_b = params.get_input_attribute(
+ GVArrayPtr attribute_b = params.get_input_attribute(
"B", component, result_domain, input_data_type, nullptr);
if (!attribute_a || !attribute_b) {
@@ -275,7 +271,7 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
return;
}
- MutableSpan<bool> result_span = attribute_result->get_span_for_write_only<bool>();
+ MutableSpan<bool> result_span = attribute_result.as_span();
/* Use specific types for correct equality operations, but for other operations we use implicit
* conversions and float comparison. In other words, the comparison is not element-wise. */
@@ -283,38 +279,47 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
const float threshold = params.get_input<float>("Threshold");
if (operation == NODE_FLOAT_COMPARE_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
- do_equal_operation_float(*attribute_a, *attribute_b, threshold, result_span);
+ do_equal_operation_float(
+ attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
- do_equal_operation_float3(*attribute_a, *attribute_b, threshold, result_span);
+ do_equal_operation_float3(
+ attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
- do_equal_operation_color4f(*attribute_a, *attribute_b, threshold, result_span);
+ do_equal_operation_color4f(
+ attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
- do_equal_operation_bool(*attribute_a, *attribute_b, threshold, result_span);
+ do_equal_operation_bool(
+ attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span);
}
}
else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) {
if (input_data_type == CD_PROP_FLOAT) {
- do_not_equal_operation_float(*attribute_a, *attribute_b, threshold, result_span);
+ do_not_equal_operation_float(
+ attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_FLOAT3) {
- do_not_equal_operation_float3(*attribute_a, *attribute_b, threshold, result_span);
+ do_not_equal_operation_float3(
+ attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
- do_not_equal_operation_color4f(*attribute_a, *attribute_b, threshold, result_span);
+ do_not_equal_operation_color4f(
+ attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
- do_not_equal_operation_bool(*attribute_a, *attribute_b, threshold, result_span);
+ do_not_equal_operation_bool(
+ attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span);
}
}
}
else {
- do_math_operation(*attribute_a, *attribute_b, operation, result_span);
+ do_math_operation(
+ attribute_a->typed<float>(), attribute_b->typed<float>(), operation, result_span);
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_compare_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc
index 19c3aaa9c85..bb46c5c84cd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_convert.cc
@@ -55,13 +55,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef source_name,
StringRef result_name)
{
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
+ ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name);
if (source_attribute) {
- return source_attribute->domain();
+ return source_attribute.domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -75,14 +75,14 @@ static bool conversion_can_be_skipped(const GeometryComponent &component,
if (source_name != result_name) {
return false;
}
- ReadAttributePtr read_attribute = component.attribute_try_get_for_read(source_name);
+ ReadAttributeLookup read_attribute = component.attribute_try_get_for_read(source_name);
if (!read_attribute) {
return false;
}
- if (read_attribute->domain() != result_domain) {
+ if (read_attribute.domain != result_domain) {
return false;
}
- if (read_attribute->cpp_type() != *bke::custom_data_type_to_cpp_type(result_type)) {
+ if (read_attribute.varray->type() != *bke::custom_data_type_to_cpp_type(result_type)) {
return false;
}
return true;
@@ -104,7 +104,7 @@ static void attribute_convert_calc(GeometryComponent &component,
return;
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(
+ GVArrayPtr source_attribute = component.attribute_try_get_for_read(
source_name, result_domain, result_type);
if (!source_attribute) {
params.error_message_add(NodeWarningType::Error,
@@ -112,25 +112,22 @@ static void attribute_convert_calc(GeometryComponent &component,
return;
}
- OutputAttributePtr result_attribute = component.attribute_try_get_for_output(
+ OutputAttribute result_attribute = component.attribute_try_get_for_output_only(
result_name, result_domain, result_type);
if (!result_attribute) {
return;
}
- fn::GSpan source_span = source_attribute->get_span();
- fn::GMutableSpan result_span = result_attribute->get_span_for_write_only();
- if (source_span.is_empty() || result_span.is_empty()) {
- return;
- }
+ GVArray_GSpan source_span{*source_attribute};
+ GMutableSpan result_span = result_attribute.as_span();
+
BLI_assert(source_span.size() == result_span.size());
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(result_type);
BLI_assert(cpp_type != nullptr);
cpp_type->copy_to_initialized_n(source_span.data(), result_span.data(), result_span.size());
-
- result_attribute.apply_span_and_save();
+ result_attribute.save();
}
static void geo_node_attribute_convert_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
index 7b4483a31a1..8287313e400 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
@@ -72,9 +72,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef attribute_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(attribute_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -93,7 +93,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
get_result_domain(component, attribute_name) :
domain;
- OutputAttributePtr attribute = component.attribute_try_get_for_output(
+ OutputAttribute attribute = component.attribute_try_get_for_output_only(
attribute_name, result_domain, data_type);
if (!attribute) {
return;
@@ -102,38 +102,34 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
switch (data_type) {
case CD_PROP_FLOAT: {
const float value = params.get_input<float>("Value_001");
- MutableSpan<float> attribute_span = attribute->get_span_for_write_only<float>();
- attribute_span.fill(value);
+ attribute->fill(&value);
break;
}
case CD_PROP_FLOAT3: {
const float3 value = params.get_input<float3>("Value");
- MutableSpan<float3> attribute_span = attribute->get_span_for_write_only<float3>();
- attribute_span.fill(value);
+ attribute->fill(&value);
break;
}
case CD_PROP_COLOR: {
const Color4f value = params.get_input<Color4f>("Value_002");
- MutableSpan<Color4f> attribute_span = attribute->get_span_for_write_only<Color4f>();
- attribute_span.fill(value);
+ attribute->fill(&value);
break;
}
case CD_PROP_BOOL: {
const bool value = params.get_input<bool>("Value_003");
- MutableSpan<bool> attribute_span = attribute->get_span_for_write_only<bool>();
- attribute_span.fill(value);
+ attribute->fill(&value);
break;
}
case CD_PROP_INT32: {
const int value = params.get_input<int>("Value_004");
- MutableSpan<int> attribute_span = attribute->get_span_for_write_only<int>();
- attribute_span.fill(value);
+ attribute->fill(&value);
+ break;
}
default:
break;
}
- attribute.apply_span_and_save();
+ attribute.save();
}
static void geo_node_attribute_fill_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
index fdbdadf90b6..4a98d6caed2 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc
@@ -192,8 +192,8 @@ static float map_smootherstep(const float value,
return min_to + factor_mapped * (max_to - min_to);
}
-static void map_range_float(FloatReadAttribute attribute_input,
- FloatWriteAttribute attribute_result,
+static void map_range_float(const VArray<float> &attribute_input,
+ MutableSpan<float> results,
const GeoNodeExecParams &params)
{
const bNode &node = params.node();
@@ -204,32 +204,31 @@ static void map_range_float(FloatReadAttribute attribute_input,
const float min_to = params.get_input<float>("To Min");
const float max_to = params.get_input<float>("To Max");
- Span<float> span = attribute_input.get_span();
- MutableSpan<float> result_span = attribute_result.get_span();
+ VArray_Span<float> span{attribute_input};
switch (interpolation_type) {
case NODE_MAP_RANGE_LINEAR: {
for (int i : span.index_range()) {
- result_span[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
+ results[i] = map_linear(span[i], min_from, max_from, min_to, max_to);
}
break;
}
case NODE_MAP_RANGE_STEPPED: {
const float steps = params.get_input<float>("Steps");
for (int i : span.index_range()) {
- result_span[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
+ results[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps);
}
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
for (int i : span.index_range()) {
- result_span[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
+ results[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to);
}
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
for (int i : span.index_range()) {
- result_span[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
+ results[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to);
}
break;
}
@@ -241,14 +240,14 @@ static void map_range_float(FloatReadAttribute attribute_input,
const float clamp_min = min_to < max_to ? min_to : max_to;
const float clamp_max = min_to < max_to ? max_to : min_to;
- for (int i : result_span.index_range()) {
- result_span[i] = std::clamp(result_span[i], clamp_min, clamp_max);
+ for (int i : results.index_range()) {
+ results[i] = std::clamp(results[i], clamp_min, clamp_max);
}
}
}
-static void map_range_float3(Float3ReadAttribute attribute_input,
- Float3WriteAttribute attribute_result,
+static void map_range_float3(const VArray<float3> &attribute_input,
+ const MutableSpan<float3> results,
const GeoNodeExecParams &params)
{
const bNode &node = params.node();
@@ -259,43 +258,39 @@ static void map_range_float3(Float3ReadAttribute attribute_input,
const float3 min_to = params.get_input<float3>("To Min_001");
const float3 max_to = params.get_input<float3>("To Max_001");
- Span<float3> span = attribute_input.get_span();
- MutableSpan<float3> result_span = attribute_result.get_span();
+ VArray_Span<float3> span{attribute_input};
switch (interpolation_type) {
case NODE_MAP_RANGE_LINEAR: {
for (int i : span.index_range()) {
- result_span[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
- result_span[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
- result_span[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
+ results[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
+ results[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
+ results[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
}
break;
}
case NODE_MAP_RANGE_STEPPED: {
const float3 steps = params.get_input<float3>("Steps_001");
for (int i : span.index_range()) {
- result_span[i].x = map_stepped(
- span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x);
- result_span[i].y = map_stepped(
- span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y);
- result_span[i].z = map_stepped(
- span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z);
+ results[i].x = map_stepped(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x);
+ results[i].y = map_stepped(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y);
+ results[i].z = map_stepped(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z);
}
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
for (int i : span.index_range()) {
- result_span[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
- result_span[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
- result_span[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
+ results[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
+ results[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
+ results[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
}
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
for (int i : span.index_range()) {
- result_span[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
- result_span[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
- result_span[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
+ results[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x);
+ results[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y);
+ results[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z);
}
break;
}
@@ -313,8 +308,8 @@ static void map_range_float3(Float3ReadAttribute attribute_input,
clamp_min.z = min_to.z < max_to.z ? min_to.z : max_to.z;
clamp_max.z = min_to.z < max_to.z ? max_to.z : min_to.z;
- for (int i : result_span.index_range()) {
- clamp_v3_v3v3(result_span[i], clamp_min, clamp_max);
+ for (int i : results.index_range()) {
+ clamp_v3_v3v3(results[i], clamp_min, clamp_max);
}
}
}
@@ -323,13 +318,13 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef source_name,
StringRef result_name)
{
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
- ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name);
+ ReadAttributeLookup source_attribute = component.attribute_try_get_for_read(source_name);
if (source_attribute) {
- return source_attribute->domain();
+ return source_attribute.domain;
}
return ATTR_DOMAIN_POINT;
}
@@ -349,8 +344,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
const AttributeDomain domain = get_result_domain(component, input_name, result_name);
- ReadAttributePtr attribute_input = component.attribute_try_get_for_read(
- input_name, domain, data_type);
+ GVArrayPtr attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type);
if (!attribute_input) {
params.error_message_add(NodeWarningType::Error,
@@ -358,7 +352,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
return;
}
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
+ OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, domain, data_type);
if (!attribute_result) {
params.error_message_add(NodeWarningType::Error,
@@ -369,18 +363,19 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP
switch (data_type) {
case CD_PROP_FLOAT: {
- map_range_float(*attribute_input, *attribute_result, params);
+ map_range_float(attribute_input->typed<float>(), attribute_result.as_span<float>(), params);
break;
}
case CD_PROP_FLOAT3: {
- map_range_float3(*attribute_input, *attribute_result, params);
+ map_range_float3(
+ attribute_input->typed<float3>(), attribute_result.as_span<float3>(), params);
break;
}
default:
BLI_assert_unreachable();
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_map_range_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
index 5ee31e78be2..99ba6acd94d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
@@ -149,9 +149,9 @@ static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node
operation_use_input_c(operation));
}
-static void do_math_operation(Span<float> span_a,
- Span<float> span_b,
- Span<float> span_c,
+static void do_math_operation(const VArray<float> &span_a,
+ const VArray<float> &span_b,
+ const VArray<float> &span_c,
MutableSpan<float> span_result,
const NodeMathOperation operation)
{
@@ -165,8 +165,8 @@ static void do_math_operation(Span<float> span_a,
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation(Span<float> span_a,
- Span<float> span_b,
+static void do_math_operation(const VArray<float> &span_a,
+ const VArray<float> &span_b,
MutableSpan<float> span_result,
const NodeMathOperation operation)
{
@@ -180,7 +180,7 @@ static void do_math_operation(Span<float> span_a,
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation(Span<float> span_input,
+static void do_math_operation(const VArray<float> &span_input,
MutableSpan<float> span_result,
const NodeMathOperation operation)
{
@@ -200,9 +200,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -224,56 +224,39 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
const std::string result_name = params.get_input<std::string>("Result");
/* The result type of this node is always float. */
- const CustomDataType result_type = CD_PROP_FLOAT;
const AttributeDomain result_domain = get_result_domain(
component, params, operation, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
- result_name, result_domain, result_type);
+ OutputAttribute_Typed<float> attribute_result =
+ component.attribute_try_get_for_output_only<float>(result_name, result_domain);
if (!attribute_result) {
return;
}
- ReadAttributePtr attribute_a = params.get_input_attribute(
- "A", component, result_domain, result_type, nullptr);
- if (!attribute_a) {
- return;
- }
+ GVArray_Typed<float> attribute_a = params.get_input_attribute<float>(
+ "A", component, result_domain, 0.0f);
- /* Note that passing the data with `get_span<float>()` works
+ MutableSpan<float> result_span = attribute_result.as_span();
+
+ /* Note that passing the data with `get_internal_span<float>()` works
* because the attributes were accessed with #CD_PROP_FLOAT. */
if (operation_use_input_b(operation)) {
- ReadAttributePtr attribute_b = params.get_input_attribute(
- "B", component, result_domain, result_type, nullptr);
- if (!attribute_b) {
- return;
- }
+ GVArray_Typed<float> attribute_b = params.get_input_attribute<float>(
+ "B", component, result_domain, 0.0f);
if (operation_use_input_c(operation)) {
- ReadAttributePtr attribute_c = params.get_input_attribute(
- "C", component, result_domain, result_type, nullptr);
- if (!attribute_c) {
- return;
- }
- do_math_operation(attribute_a->get_span<float>(),
- attribute_b->get_span<float>(),
- attribute_c->get_span<float>(),
- attribute_result->get_span_for_write_only<float>(),
- operation);
+ GVArray_Typed<float> attribute_c = params.get_input_attribute<float>(
+ "C", component, result_domain, 0.0f);
+ do_math_operation(attribute_a, attribute_b, attribute_c, result_span, operation);
}
else {
- do_math_operation(attribute_a->get_span<float>(),
- attribute_b->get_span<float>(),
- attribute_result->get_span_for_write_only<float>(),
- operation);
+ do_math_operation(attribute_a, attribute_b, result_span, operation);
}
}
else {
- do_math_operation(attribute_a->get_span<float>(),
- attribute_result->get_span_for_write_only<float>(),
- operation);
+ do_math_operation(attribute_a, result_span, operation);
}
- attribute_result.apply_span_and_save();
+ attribute_result.save();
}
static void geo_node_attribute_math_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
index 9d8cd3dfa82..e7f0de8f28e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
@@ -58,10 +58,10 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C),
namespace blender::nodes {
static void do_mix_operation_float(const int blend_mode,
- const FloatReadAttribute &factors,
- const FloatReadAttribute &inputs_a,
- const FloatReadAttribute &inputs_b,
- FloatWriteAttribute results)
+ const VArray<float> &factors,
+ const VArray<float> &inputs_a,
+ const VArray<float> &inputs_b,
+ VMutableArray<float> &results)
{
const int size = results.size();
for (const int i : IndexRange(size)) {
@@ -75,10 +75,10 @@ static void do_mix_operation_float(const int blend_mode,
}
static void do_mix_operation_float3(const int blend_mode,
- const FloatReadAttribute &factors,
- const Float3ReadAttribute &inputs_a,
- const Float3ReadAttribute &inputs_b,
- Float3WriteAttribute results)
+ const VArray<float> &factors,
+ const VArray<float3> &inputs_a,
+ const VArray<float3> &inputs_b,
+ VMutableArray<float3> &results)
{
const int size = results.size();
for (const int i : IndexRange(size)) {
@@ -91,10 +91,10 @@ static void do_mix_operation_float3(const int blend_mode,
}
static void do_mix_operation_color4f(const int blend_mode,
- const FloatReadAttribute &factors,
- const Color4fReadAttribute &inputs_a,
- const Color4fReadAttribute &inputs_b,
- Color4fWriteAttribute results)
+ const VArray<float> &factors,
+ const VArray<Color4f> &inputs_a,
+ const VArray<Color4f> &inputs_b,
+ VMutableArray<Color4f> &results)
{
const int size = results.size();
for (const int i : IndexRange(size)) {
@@ -108,22 +108,31 @@ static void do_mix_operation_color4f(const int blend_mode,
static void do_mix_operation(const CustomDataType result_type,
int blend_mode,
- const FloatReadAttribute &attribute_factor,
- const ReadAttribute &attribute_a,
- const ReadAttribute &attribute_b,
- WriteAttribute &attribute_result)
+ const VArray<float> &attribute_factor,
+ const GVArray &attribute_a,
+ const GVArray &attribute_b,
+ GVMutableArray &attribute_result)
{
if (result_type == CD_PROP_FLOAT) {
- do_mix_operation_float(
- blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result);
+ do_mix_operation_float(blend_mode,
+ attribute_factor,
+ attribute_a.typed<float>(),
+ attribute_b.typed<float>(),
+ attribute_result.typed<float>());
}
else if (result_type == CD_PROP_FLOAT3) {
- do_mix_operation_float3(
- blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result);
+ do_mix_operation_float3(blend_mode,
+ attribute_factor,
+ attribute_a.typed<float3>(),
+ attribute_b.typed<float3>(),
+ attribute_result.typed<float3>());
}
else if (result_type == CD_PROP_COLOR) {
- do_mix_operation_color4f(
- blend_mode, attribute_factor, attribute_a, attribute_b, attribute_result);
+ do_mix_operation_color4f(blend_mode,
+ attribute_factor,
+ attribute_a.typed<Color4f>(),
+ attribute_b.typed<Color4f>(),
+ attribute_result.typed<Color4f>());
}
}
@@ -132,9 +141,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -158,17 +167,17 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa
const AttributeDomain result_domain = get_result_domain(component, params, result_name);
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
+ OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
}
- FloatReadAttribute attribute_factor = params.get_input_attribute<float>(
+ GVArray_Typed<float> attribute_factor = params.get_input_attribute<float>(
"Factor", component, result_domain, 0.5f);
- ReadAttributePtr attribute_a = params.get_input_attribute(
+ GVArrayPtr attribute_a = params.get_input_attribute(
"A", component, result_domain, result_type, nullptr);
- ReadAttributePtr attribute_b = params.get_input_attribute(
+ GVArrayPtr attribute_b = params.get_input_attribute(
"B", component, result_domain, result_type, nullptr);
do_mix_operation(result_type,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
index f09a9bf056e..8e9892f00b6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
@@ -62,7 +62,7 @@ namespace blender::nodes {
static void proximity_calc(MutableSpan<float> distance_span,
MutableSpan<float3> location_span,
- Span<float3> positions,
+ const VArray<float3> &positions,
BVHTreeFromMesh &tree_data_mesh,
BVHTreeFromPointCloud &tree_data_pointcloud,
const bool bvh_mesh_success,
@@ -169,19 +169,18 @@ static void attribute_calc_proximity(GeometryComponent &component,
const AttributeDomain result_domain = ATTR_DOMAIN_POINT;
const std::string distance_attribute_name = params.get_input<std::string>("Distance");
- OutputAttributePtr distance_attribute = component.attribute_try_get_for_output(
- distance_attribute_name, result_domain, CD_PROP_FLOAT);
+ OutputAttribute_Typed<float> distance_attribute =
+ component.attribute_try_get_for_output_only<float>(distance_attribute_name, result_domain);
const std::string location_attribute_name = params.get_input<std::string>("Position");
- OutputAttributePtr location_attribute = component.attribute_try_get_for_output(
- location_attribute_name, result_domain, CD_PROP_FLOAT3);
-
- ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position");
- BLI_assert(position_attribute->custom_data_type() == CD_PROP_FLOAT3);
+ OutputAttribute_Typed<float3> location_attribute =
+ component.attribute_try_get_for_output_only<float3>(location_attribute_name, result_domain);
+ ReadAttributeLookup position_attribute = component.attribute_try_get_for_read("position");
if (!position_attribute || (!distance_attribute && !location_attribute)) {
return;
}
+ BLI_assert(position_attribute.varray->type().is<float3>());
const bNode &node = params.node();
const NodeGeometryAttributeProximity &storage = *(const NodeGeometryAttributeProximity *)
@@ -204,18 +203,15 @@ static void attribute_calc_proximity(GeometryComponent &component,
tree_data_pointcloud);
}
- Span<float3> position_span = position_attribute->get_span<float3>();
-
- MutableSpan<float> distance_span = distance_attribute ?
- distance_attribute->get_span_for_write_only<float>() :
- MutableSpan<float>();
- MutableSpan<float3> location_span = location_attribute ?
- location_attribute->get_span_for_write_only<float3>() :
- MutableSpan<float3>();
+ GVArray_Typed<float3> positions{*position_attribute.varray};
+ MutableSpan<float> distance_span = distance_attribute ? distance_attribute.as_span() :
+ MutableSpan<float>();
+ MutableSpan<float3> location_span = location_attribute ? location_attribute.as_span() :
+ MutableSpan<float3>();
proximity_calc(distance_span,
location_span,
- position_span,
+ positions,
tree_data_mesh,
tree_data_pointcloud,
bvh_mesh_success,
@@ -231,10 +227,10 @@ static void attribute_calc_proximity(GeometryComponent &component,
}
if (distance_attribute) {
- distance_attribute.apply_span_and_save();
+ distance_attribute.save();
}
if (location_attribute) {
- location_attribute.apply_span_and_save();
+ location_attribute.save();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
index 28263287a10..e86fa3ae0ed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc
@@ -173,12 +173,12 @@ Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &compo
const int domain_size = component.attribute_domain_size(domain);
/* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */
- ReadAttributePtr hash_attribute = component.attribute_try_get_for_read("id", domain);
+ GVArrayPtr hash_attribute = component.attribute_try_get_for_read("id", domain);
Array<uint32_t> hashes(domain_size);
if (hash_attribute) {
BLI_assert(hashes.size() == hash_attribute->size());
- const CPPType &cpp_type = hash_attribute->cpp_type();
- fn::GSpan items = hash_attribute->get_span();
+ const CPPType &cpp_type = hash_attribute->type();
+ GVArray_GSpan items{*hash_attribute};
for (const int i : hashes.index_range()) {
hashes[i] = cpp_type.hash(items[i]);
}
@@ -199,9 +199,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef attribute_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(attribute_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(attribute_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
/* Otherwise use the input domain chosen in the interface. */
@@ -228,15 +228,13 @@ static void randomize_attribute_on_component(GeometryComponent &component,
const AttributeDomain domain = get_result_domain(component, params, attribute_name);
- OutputAttributePtr attribute = component.attribute_try_get_for_output(
+ OutputAttribute attribute = component.attribute_try_get_for_output(
attribute_name, domain, data_type);
if (!attribute) {
return;
}
- fn::GMutableSpan span = (operation == GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE) ?
- attribute->get_span_for_write_only() :
- attribute->get_span();
+ GMutableSpan span = attribute.as_span();
Array<uint32_t> hashes = get_geometry_element_ids_as_uints(component, domain);
@@ -269,8 +267,8 @@ static void randomize_attribute_on_component(GeometryComponent &component,
}
}
- attribute.apply_span_and_save();
-} // namespace blender::nodes
+ attribute.save();
+}
static void geo_node_random_attribute_exec(GeoNodeExecParams params)
{
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
index d0b2595b5b9..5b3fd75342a 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
@@ -53,15 +53,16 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef map_attribute_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_attribute_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(
+ result_attribute_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
/* Otherwise use the name of the map attribute. */
- ReadAttributePtr map_attribute = component.attribute_try_get_for_read(map_attribute_name);
+ ReadAttributeLookup map_attribute = component.attribute_try_get_for_read(map_attribute_name);
if (map_attribute) {
- return map_attribute->domain();
+ return map_attribute.domain;
}
/* The node won't execute in this case, but we still have to return a value. */
@@ -85,16 +86,16 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
const AttributeDomain result_domain = get_result_domain(
component, result_attribute_name, mapping_name);
- OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
- result_attribute_name, result_domain, CD_PROP_COLOR);
+ OutputAttribute_Typed<Color4f> attribute_out =
+ component.attribute_try_get_for_output_only<Color4f>(result_attribute_name, result_domain);
if (!attribute_out) {
return;
}
- Float3ReadAttribute mapping_attribute = component.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>(
mapping_name, result_domain, {0, 0, 0});
- MutableSpan<Color4f> colors = attribute_out->get_span<Color4f>();
+ MutableSpan<Color4f> colors = attribute_out.as_span();
for (const int i : IndexRange(mapping_attribute.size())) {
TexResult texture_result = {0};
const float3 position = mapping_attribute[i];
@@ -103,7 +104,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
BKE_texture_get_value(nullptr, texture, remapped_position, &texture_result, false);
colors[i] = {texture_result.tr, texture_result.tg, texture_result.tb, texture_result.ta};
}
- attribute_out.apply_span_and_save();
+ attribute_out.save();
}
static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
index 656dc51149e..daf61b6bf57 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_separate_xyz.cc
@@ -77,17 +77,17 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
{
/* Use the highest priority domain from any existing attribute outputs. */
Vector<AttributeDomain, 3> output_domains;
- ReadAttributePtr attribute_x = component.attribute_try_get_for_read(result_name_x);
- ReadAttributePtr attribute_y = component.attribute_try_get_for_read(result_name_y);
- ReadAttributePtr attribute_z = component.attribute_try_get_for_read(result_name_z);
+ ReadAttributeLookup attribute_x = component.attribute_try_get_for_read(result_name_x);
+ ReadAttributeLookup attribute_y = component.attribute_try_get_for_read(result_name_y);
+ ReadAttributeLookup attribute_z = component.attribute_try_get_for_read(result_name_z);
if (attribute_x) {
- output_domains.append(attribute_x->domain());
+ output_domains.append(attribute_x.domain);
}
if (attribute_y) {
- output_domains.append(attribute_y->domain());
+ output_domains.append(attribute_y.domain);
}
if (attribute_z) {
- output_domains.append(attribute_z->domain());
+ output_domains.append(attribute_z.domain);
}
if (output_domains.size() > 0) {
return bke::attribute_domain_highest_priority(output_domains);
@@ -107,37 +107,32 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa
}
/* The node is only for float3 to float conversions. */
- const CustomDataType input_type = CD_PROP_FLOAT3;
- const CustomDataType result_type = CD_PROP_FLOAT;
const AttributeDomain result_domain = get_result_domain(
component, params, result_name_x, result_name_y, result_name_z);
- ReadAttributePtr attribute_input = params.get_input_attribute(
- "Vector", component, result_domain, input_type, nullptr);
- if (!attribute_input) {
- return;
- }
- const Span<float3> input_span = attribute_input->get_span<float3>();
+ GVArray_Typed<float3> attribute_input = params.get_input_attribute<float3>(
+ "Vector", component, result_domain, {0, 0, 0});
+ VArray_Span<float3> input_span{*attribute_input};
- OutputAttributePtr attribute_result_x = component.attribute_try_get_for_output(
- result_name_x, result_domain, result_type);
- OutputAttributePtr attribute_result_y = component.attribute_try_get_for_output(
- result_name_y, result_domain, result_type);
- OutputAttributePtr attribute_result_z = component.attribute_try_get_for_output(
- result_name_z, result_domain, result_type);
+ OutputAttribute_Typed<float> attribute_result_x =
+ component.attribute_try_get_for_output_only<float>(result_name_x, result_domain);
+ OutputAttribute_Typed<float> attribute_result_y =
+ component.attribute_try_get_for_output_only<float>(result_name_y, result_domain);
+ OutputAttribute_Typed<float> attribute_result_z =
+ component.attribute_try_get_for_output_only<float>(result_name_z, result_domain);
/* Only extract the components for the outputs with a given attribute. */
if (attribute_result_x) {
- extract_input(0, input_span, attribute_result_x->get_span_for_write_only<float>());
- attribute_result_x.apply_span_and_save();
+ extract_input(0, input_span, attribute_result_x.as_span());
+ attribute_result_x.save();
}
if (attribute_result_y) {
- extract_input(1, input_span, attribute_result_y->get_span_for_write_only<float>());
- attribute_result_y.apply_span_and_save();
+ extract_input(1, input_span, attribute_result_y.as_span());
+ attribute_result_y.save();
}
if (attribute_result_z) {
- extract_input(2, input_span, attribute_result_z->get_span_for_write_only<float>());
- attribute_result_z.apply_span_and_save();
+ extract_input(2, input_span, attribute_result_z.as_span());
+ attribute_result_z.save();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
index 1ae095a27d2..86fbc9dc6d0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
@@ -168,16 +168,16 @@ static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNod
operation_use_input_c(operation));
}
-static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float3> span_b = input_b.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float3> span_b{input_b};
+ VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -189,25 +189,25 @@ static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
- const Float3ReadAttribute &input_c,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
+ const VArray<float3> &input_c,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float3> span_b = input_b.get_span();
- Span<float3> span_c = input_c.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float3> span_b{input_b};
+ VArray_Span<float3> span_c{input_c};
+ VMutableArray_Span<float3> span_result{result};
bool success = try_dispatch_float_math_fl3_fl3_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -220,25 +220,25 @@ static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &inpu
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_fl3_fl_to_fl3(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
- const FloatReadAttribute &input_c,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
+ const VArray<float> &input_c,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float3> span_b = input_b.get_span();
- Span<float> span_c = input_c.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float3> span_b{input_b};
+ VArray_Span<float> span_c{input_c};
+ VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl3_fl_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -251,23 +251,23 @@ static void do_math_operation_fl3_fl3_fl_to_fl3(const Float3ReadAttribute &input
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a,
- const Float3ReadAttribute &input_b,
- FloatWriteAttribute result,
+static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a,
+ const VArray<float3> &input_b,
+ VMutableArray<float> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float3> span_b = input_b.get_span();
- MutableSpan<float> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float3> span_b{input_b};
+ VMutableArray_Span<float> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl3_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -279,23 +279,23 @@ static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a,
- const FloatReadAttribute &input_b,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a,
+ const VArray<float> &input_b,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- Span<float> span_b = input_b.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VArray_Span<float> span_b{input_b};
+ VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_fl_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -307,21 +307,21 @@ static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a,
- Float3WriteAttribute result,
+static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a,
+ VMutableArray<float3> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- MutableSpan<float3> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VMutableArray_Span<float3> span_result{result, false};
bool success = try_dispatch_float_math_fl3_to_fl3(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -332,21 +332,21 @@ static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
-static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a,
- FloatWriteAttribute result,
+static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a,
+ VMutableArray<float> &result,
const NodeVectorMathOperation operation)
{
const int size = input_a.size();
- Span<float3> span_a = input_a.get_span();
- MutableSpan<float> span_result = result.get_span_for_write_only();
+ VArray_Span<float3> span_a{input_a};
+ VMutableArray_Span<float> span_result{result, false};
bool success = try_dispatch_float_math_fl3_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
@@ -357,7 +357,7 @@ static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a,
}
});
- result.apply_span();
+ span_result.save();
/* The operation is not supported by this node currently. */
BLI_assert(success);
@@ -370,9 +370,9 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
+ ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
if (result_attribute) {
- return result_attribute->domain();
+ return result_attribute.domain;
}
/* Otherwise use the highest priority domain from existing input attributes, or the default. */
@@ -406,13 +406,13 @@ static void attribute_vector_math_calc(GeometryComponent &component,
const AttributeDomain result_domain = get_result_domain(
component, params, operation, result_name);
- ReadAttributePtr attribute_a = params.get_input_attribute(
+ GVArrayPtr attribute_a = params.get_input_attribute(
"A", component, result_domain, read_type_a, nullptr);
if (!attribute_a) {
return;
}
- ReadAttributePtr attribute_b;
- ReadAttributePtr attribute_c;
+ GVArrayPtr attribute_b;
+ GVArrayPtr attribute_c;
if (use_input_b) {
attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr);
if (!attribute_b) {
@@ -427,7 +427,7 @@ static void attribute_vector_math_calc(GeometryComponent &component,
}
/* Get result attribute first, in case it has to overwrite one of the existing attributes. */
- OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
+ OutputAttribute attribute_result = component.attribute_try_get_for_output_only(
result_name, result_domain, result_type);
if (!attribute_result) {
return;
@@ -445,17 +445,27 @@ static void attribute_vector_math_calc(GeometryComponent &component,
case NODE_VECTOR_MATH_MODULO:
case NODE_VECTOR_MATH_MINIMUM:
case NODE_VECTOR_MATH_MAXIMUM:
- do_math_operation_fl3_fl3_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation);
+ do_math_operation_fl3_fl3_to_fl3(attribute_a->typed<float3>(),
+ attribute_b->typed<float3>(),
+ attribute_result->typed<float3>(),
+ operation);
break;
case NODE_VECTOR_MATH_DOT_PRODUCT:
case NODE_VECTOR_MATH_DISTANCE:
- do_math_operation_fl3_fl3_to_fl(*attribute_a, *attribute_b, *attribute_result, operation);
+ do_math_operation_fl3_fl3_to_fl(attribute_a->typed<float3>(),
+ attribute_b->typed<float3>(),
+ attribute_result->typed<float>(),
+ operation);
break;
case NODE_VECTOR_MATH_LENGTH:
- do_math_operation_fl3_to_fl(*attribute_a, *attribute_result, operation);
+ do_math_operation_fl3_to_fl(
+ attribute_a->typed<float3>(), attribute_result->typed<float>(), operation);
break;
case NODE_VECTOR_MATH_SCALE:
- do_math_operation_fl3_fl_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation);
+ do_math_operation_fl3_fl_to_fl3(attribute_a->typed<float3>(),
+ attribute_b->typed<float>(),
+ attribute_result->typed<float3>(),
+ operation);
break;
case NODE_VECTOR_MATH_NORMALIZE:
case NODE_VECTOR_MATH_FLOOR:
@@ -465,16 +475,23 @@ static void attribute_vector_math_calc(GeometryComponent &component,
case NODE_VECTOR_MATH_SINE:
case NODE_VECTOR_MATH_COSINE:
case NODE_VECTOR_MATH_TANGENT:
- do_math_operation_fl3_to_fl3(*attribute_a, *attribute_result, operation);
+ do_math_operation_fl3_to_fl3(
+ attribute_a->typed<float3>(), attribute_result->typed<float3>(), operation);
break;
case NODE_VECTOR_MATH_WRAP:
case NODE_VECTOR_MATH_FACEFORWARD:
- do_math_operation_fl3_fl3_fl3_to_fl3(
- *attribute_a, *attribute_b, *attribute_c, *attribute_result, operation);
+ do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a->typed<float3>(),
+ attribute_b->typed<float3>(),
+ attribute_c->typed<float3>(),
+ attribute_result->typed<float3>(),
+ operation);
break;
case NODE_VECTOR_MATH_REFRACT:
- do_math_operation_fl3_fl3_fl_to_fl3(
- *attribute_a, *attribute_b, *attribute_c, *attribute_result, operation);
+ do_math_operation_fl3_fl3_fl_to_fl3(attribute_a->typed<float3>(),
+ attribute_b->typed<float3>(),
+ attribute_c->typed<float>(),
+ attribute_result->typed<float3>(),
+ operation);
break;
}
attribute_result.save();
diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
index 96455f080e7..b6fa4c0d48f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc
@@ -39,15 +39,12 @@ static void compute_min_max_from_position_and_transform(const GeometryComponent
float3 &r_min,
float3 &r_max)
{
- ReadAttributePtr position_attribute = component.attribute_try_get_for_read("position");
- if (!position_attribute) {
- BLI_assert(component.attribute_domain_size(ATTR_DOMAIN_POINT) == 0);
- return;
- }
- Span<float3> positions = position_attribute->get_span<float3>();
+ GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
+ "position", ATTR_DOMAIN_POINT, {0, 0, 0});
for (const float4x4 &transform : transforms) {
- for (const float3 &position : positions) {
+ for (const int i : positions.index_range()) {
+ const float3 position = positions[i];
const float3 transformed_position = transform * position;
minmax_v3v3_v3(r_min, r_max, transformed_position);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
index 52512769a47..857b60dfb93 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc
@@ -149,10 +149,10 @@ static void determine_final_data_type_and_domain(Span<const GeometryComponent *>
Vector<CustomDataType> data_types;
Vector<AttributeDomain> domains;
for (const GeometryComponent *component : components) {
- ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name);
+ ReadAttributeLookup attribute = component->attribute_try_get_for_read(attribute_name);
if (attribute) {
- data_types.append(attribute->custom_data_type());
- domains.append(attribute->domain());
+ data_types.append(bke::cpp_type_to_custom_data_type(attribute.varray->type()));
+ domains.append(attribute.domain);
}
}
@@ -164,7 +164,7 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
StringRef attribute_name,
const CustomDataType data_type,
const AttributeDomain domain,
- fn::GMutableSpan dst_span)
+ GMutableSpan dst_span)
{
const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(data_type);
BLI_assert(cpp_type != nullptr);
@@ -175,10 +175,10 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components,
if (domain_size == 0) {
continue;
}
- ReadAttributePtr read_attribute = component->attribute_get_for_read(
+ GVArrayPtr read_attribute = component->attribute_get_for_read(
attribute_name, domain, data_type, nullptr);
- fn::GSpan src_span = read_attribute->get_span();
+ GVArray_GSpan src_span{*read_attribute};
const void *src_buffer = src_span.data();
void *dst_buffer = dst_span[offset];
cpp_type->copy_to_initialized_n(src_buffer, dst_buffer, domain_size);
@@ -201,16 +201,14 @@ static void join_attributes(Span<const GeometryComponent *> src_components,
AttributeDomain domain;
determine_final_data_type_and_domain(src_components, attribute_name, &data_type, &domain);
- OutputAttributePtr write_attribute = result.attribute_try_get_for_output(
+ OutputAttribute write_attribute = result.attribute_try_get_for_output_only(
attribute_name, domain, data_type);
- if (!write_attribute ||
- &write_attribute->cpp_type() != bke::custom_data_type_to_cpp_type(data_type) ||
- write_attribute->domain() != domain) {
+ if (!write_attribute) {
continue;
}
- fn::GMutableSpan dst_span = write_attribute->get_span_for_write_only();
+ GMutableSpan dst_span = write_attribute.as_span();
fill_new_attribute(src_components, attribute_name, data_type, domain, dst_span);
- write_attribute.apply_span_and_save();
+ write_attribute.save();
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index 761d5d6c388..2806472286e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -194,9 +194,9 @@ static void calculate_uvs(Mesh *mesh,
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
- "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
- MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
+ OutputAttribute_Typed<float2> uv_attribute =
+ mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.as_span();
Array<float2> circle(verts_num);
float angle = 0.0f;
@@ -271,7 +271,7 @@ static void calculate_uvs(Mesh *mesh,
}
}
- uv_attribute.apply_span_and_save();
+ uv_attribute.save();
}
Mesh *create_cylinder_or_cone_mesh(const float radius_top,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 14c57bc7135..5a4bab86421 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -44,9 +44,9 @@ static void calculate_uvs(
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
- "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
- MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
+ OutputAttribute_Typed<float2> uv_attribute =
+ mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.as_span();
const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x;
const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y;
@@ -56,7 +56,7 @@ static void calculate_uvs(
uvs[i].y = (co.y + size_y * 0.5f) * dy;
}
- uv_attribute.apply_span_and_save();
+ uv_attribute.save();
}
static Mesh *create_grid_mesh(const int verts_x,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index fd95cdc81f7..cc93e71a5dd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -224,9 +224,9 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r
{
MeshComponent mesh_component;
mesh_component.replace(mesh, GeometryOwnershipType::Editable);
- OutputAttributePtr uv_attribute = mesh_component.attribute_try_get_for_output(
- "uv_map", ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2, nullptr);
- MutableSpan<float2> uvs = uv_attribute->get_span_for_write_only<float2>();
+ OutputAttribute_Typed<float2> uv_attribute =
+ mesh_component.attribute_try_get_for_output_only<float2>("uv_map", ATTR_DOMAIN_CORNER);
+ MutableSpan<float2> uvs = uv_attribute.as_span();
int loop_index = 0;
const float dy = 1.0f / rings;
@@ -256,7 +256,7 @@ static void calculate_sphere_uvs(Mesh *mesh, const float segments, const float r
uvs[loop_index++] = float2(segment / segments, 1.0f - dy);
}
- uv_attribute.apply_span_and_save();
+ uv_attribute.save();
}
static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const int rings)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
index 74cca8a2f3c..28d5d9a96f7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -28,6 +28,7 @@
#include "BKE_geometry_set_instances.hh"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
+#include "BKE_mesh_sample.hh"
#include "BKE_pointcloud.h"
#include "UI_interface.h"
@@ -91,7 +92,7 @@ static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
static void sample_mesh_surface(const Mesh &mesh,
const float4x4 &transform,
const float base_density,
- const FloatReadAttribute *density_factors,
+ const VArray<float> *density_factors,
const int seed,
Vector<float3> &r_positions,
Vector<float3> &r_bary_coords,
@@ -113,9 +114,9 @@ static void sample_mesh_surface(const Mesh &mesh,
float looptri_density_factor = 1.0f;
if (density_factors != nullptr) {
- const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]);
- const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]);
- const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]);
+ const float v0_density_factor = std::max(0.0f, density_factors->get(v0_loop));
+ const float v1_density_factor = std::max(0.0f, density_factors->get(v1_loop));
+ const float v2_density_factor = std::max(0.0f, density_factors->get(v2_loop));
looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f;
}
const float area = area_tri_v3(v0_pos, v1_pos, v2_pos);
@@ -203,7 +204,7 @@ BLI_NOINLINE static void update_elimination_mask_for_close_points(
BLI_NOINLINE static void update_elimination_mask_based_on_density_factors(
const Mesh &mesh,
- const FloatReadAttribute &density_factors,
+ const VArray<float> &density_factors,
Span<float3> bary_coords,
Span<int> looptri_indices,
MutableSpan<bool> elimination_mask)
@@ -249,99 +250,27 @@ BLI_NOINLINE static void eliminate_points_based_on_mask(Span<bool> elimination_m
}
}
-template<typename T>
-BLI_NOINLINE static void interpolate_attribute_point(const Mesh &mesh,
- const Span<float3> bary_coords,
- const Span<int> looptri_indices,
- const Span<T> data_in,
- MutableSpan<T> data_out)
-{
- BLI_assert(data_in.size() == mesh.totvert);
- Span<MLoopTri> looptris = get_mesh_looptris(mesh);
-
- for (const int i : bary_coords.index_range()) {
- const int looptri_index = looptri_indices[i];
- const MLoopTri &looptri = looptris[looptri_index];
- const float3 &bary_coord = bary_coords[i];
-
- const int v0_index = mesh.mloop[looptri.tri[0]].v;
- const int v1_index = mesh.mloop[looptri.tri[1]].v;
- const int v2_index = mesh.mloop[looptri.tri[2]].v;
-
- const T &v0 = data_in[v0_index];
- const T &v1 = data_in[v1_index];
- const T &v2 = data_in[v2_index];
-
- const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
- data_out[i] = interpolated_value;
- }
-}
-
-template<typename T>
-BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh,
- const Span<float3> bary_coords,
- const Span<int> looptri_indices,
- const Span<T> data_in,
- MutableSpan<T> data_out)
-{
- BLI_assert(data_in.size() == mesh.totloop);
- Span<MLoopTri> looptris = get_mesh_looptris(mesh);
-
- for (const int i : bary_coords.index_range()) {
- const int looptri_index = looptri_indices[i];
- const MLoopTri &looptri = looptris[looptri_index];
- const float3 &bary_coord = bary_coords[i];
-
- const int loop_index_0 = looptri.tri[0];
- const int loop_index_1 = looptri.tri[1];
- const int loop_index_2 = looptri.tri[2];
-
- const T &v0 = data_in[loop_index_0];
- const T &v1 = data_in[loop_index_1];
- const T &v2 = data_in[loop_index_2];
-
- const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
- data_out[i] = interpolated_value;
- }
-}
-
-template<typename T>
-BLI_NOINLINE static void interpolate_attribute_face(const Mesh &mesh,
- const Span<int> looptri_indices,
- const Span<T> data_in,
- MutableSpan<T> data_out)
-{
- BLI_assert(data_in.size() == mesh.totpoly);
- Span<MLoopTri> looptris = get_mesh_looptris(mesh);
-
- for (const int i : data_out.index_range()) {
- const int looptri_index = looptri_indices[i];
- const MLoopTri &looptri = looptris[looptri_index];
- const int poly_index = looptri.poly;
- data_out[i] = data_in[poly_index];
- }
-}
-
-template<typename T>
BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
Span<float3> bary_coords,
Span<int> looptri_indices,
const AttributeDomain source_domain,
- Span<T> source_span,
- MutableSpan<T> output_span)
+ const GVArray &source_data,
+ GMutableSpan output_data)
{
switch (source_domain) {
case ATTR_DOMAIN_POINT: {
- interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, source_span, output_span);
+ bke::mesh_surface_sample::sample_point_attribute(
+ mesh, looptri_indices, bary_coords, source_data, output_data);
break;
}
case ATTR_DOMAIN_CORNER: {
- interpolate_attribute_corner<T>(
- mesh, bary_coords, looptri_indices, source_span, output_span);
+ bke::mesh_surface_sample::sample_corner_attribute(
+ mesh, looptri_indices, bary_coords, source_data, output_data);
break;
}
case ATTR_DOMAIN_FACE: {
- interpolate_attribute_face<T>(mesh, looptri_indices, source_span, output_span);
+ bke::mesh_surface_sample::sample_face_attribute(
+ mesh, looptri_indices, source_data, output_data);
break;
}
default: {
@@ -363,13 +292,13 @@ BLI_NOINLINE static void interpolate_existing_attributes(
StringRef attribute_name = entry.key;
const CustomDataType output_data_type = entry.value.data_type;
/* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */
- OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
+ OutputAttribute attribute_out = component.attribute_try_get_for_output_only(
attribute_name, ATTR_DOMAIN_POINT, output_data_type);
if (!attribute_out) {
continue;
}
- fn::GMutableSpan out_span = attribute_out->get_span_for_write_only();
+ GMutableSpan out_span = attribute_out.as_span();
int i_instance = 0;
for (const GeometryInstanceGroup &set_group : set_groups) {
@@ -380,44 +309,41 @@ BLI_NOINLINE static void interpolate_existing_attributes(
/* Use a dummy read without specifying a domain or data type in order to
* get the existing attribute's domain. Interpolation is done manually based
* on the bary coords in #interpolate_attribute. */
- ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read(
+ ReadAttributeLookup dummy_attribute = source_component.attribute_try_get_for_read(
attribute_name);
if (!dummy_attribute) {
i_instance += set_group.transforms.size();
continue;
}
- const AttributeDomain source_domain = dummy_attribute->domain();
- ReadAttributePtr source_attribute = source_component.attribute_get_for_read(
+ const AttributeDomain source_domain = dummy_attribute.domain;
+ GVArrayPtr source_attribute = source_component.attribute_get_for_read(
attribute_name, source_domain, output_data_type, nullptr);
if (!source_attribute) {
i_instance += set_group.transforms.size();
continue;
}
- fn::GSpan source_span = source_attribute->get_span();
+
+ for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
+ const int offset = instance_start_offsets[i_instance];
+ Span<float3> bary_coords = bary_coords_array[i_instance];
+ Span<int> looptri_indices = looptri_indices_array[i_instance];
+
+ GMutableSpan instance_span = out_span.slice(offset, bary_coords.size());
+ interpolate_attribute(
+ mesh, bary_coords, looptri_indices, source_domain, *source_attribute, instance_span);
+
+ i_instance++;
+ }
attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) {
using T = decltype(dummy);
- for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
- const int offset = instance_start_offsets[i_instance];
- Span<float3> bary_coords = bary_coords_array[i_instance];
- Span<int> looptri_indices = looptri_indices_array[i_instance];
-
- MutableSpan<T> instance_span = out_span.typed<T>().slice(offset, bary_coords.size());
- interpolate_attribute<T>(mesh,
- bary_coords,
- looptri_indices,
- source_domain,
- source_span.typed<T>(),
- instance_span);
-
- i_instance++;
- }
+ GVArray_Span<T> source_span{*source_attribute};
});
}
- attribute_out.apply_span_and_save();
+ attribute_out.save();
}
}
@@ -427,16 +353,16 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
Span<Vector<float3>> bary_coords_array,
Span<Vector<int>> looptri_indices_array)
{
- OutputAttributePtr id_attribute = component.attribute_try_get_for_output(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- OutputAttributePtr normal_attribute = component.attribute_try_get_for_output(
- "normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
- OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
- "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ OutputAttribute_Typed<int> id_attribute = component.attribute_try_get_for_output_only<int>(
+ "id", ATTR_DOMAIN_POINT);
+ OutputAttribute_Typed<float3> normal_attribute =
+ component.attribute_try_get_for_output_only<float3>("normal", ATTR_DOMAIN_POINT);
+ OutputAttribute_Typed<float3> rotation_attribute =
+ component.attribute_try_get_for_output_only<float3>("rotation", ATTR_DOMAIN_POINT);
- MutableSpan<int> result_ids = id_attribute->get_span_for_write_only<int>();
- MutableSpan<float3> result_normals = normal_attribute->get_span_for_write_only<float3>();
- MutableSpan<float3> result_rotations = rotation_attribute->get_span_for_write_only<float3>();
+ MutableSpan<int> result_ids = id_attribute.as_span();
+ MutableSpan<float3> result_normals = normal_attribute.as_span();
+ MutableSpan<float3> result_rotations = rotation_attribute.as_span();
int i_instance = 0;
for (const GeometryInstanceGroup &set_group : sets) {
@@ -480,9 +406,9 @@ BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup>
}
}
- id_attribute.apply_span_and_save();
- normal_attribute.apply_span_and_save();
- rotation_attribute.apply_span_and_save();
+ id_attribute.save();
+ normal_attribute.save();
+ rotation_attribute.save();
}
BLI_NOINLINE static void add_remaining_point_attributes(
@@ -520,7 +446,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
for (const GeometryInstanceGroup &set_group : set_groups) {
const GeometrySet &set = set_group.geometry_set;
const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
- const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
+ GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>(
density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
const Mesh &mesh = *component.get_for_read();
for (const float4x4 &transform : set_group.transforms) {
@@ -530,7 +456,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups,
sample_mesh_surface(mesh,
transform,
density,
- &density_factors,
+ &*density_factors,
seed,
positions,
bary_coords,
@@ -589,7 +515,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group
const GeometrySet &set = set_group.geometry_set;
const MeshComponent &component = *set.get_component_for_read<MeshComponent>();
const Mesh &mesh = *component.get_for_read();
- const FloatReadAttribute density_factors = component.attribute_get_for_read<float>(
+ const GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>(
density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f);
for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
index 20022e8d29d..65b7d068003 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc
@@ -174,13 +174,13 @@ static void add_instances_from_geometry_component(InstancesComponent &instances,
Array<std::optional<InstancedData>> instances_data = get_instanced_data(
params, src_geometry, domain_size);
- Float3ReadAttribute positions = src_geometry.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> positions = src_geometry.attribute_get_for_read<float3>(
"position", domain, {0, 0, 0});
- Float3ReadAttribute rotations = src_geometry.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> rotations = src_geometry.attribute_get_for_read<float3>(
"rotation", domain, {0, 0, 0});
- Float3ReadAttribute scales = src_geometry.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> scales = src_geometry.attribute_get_for_read<float3>(
"scale", domain, {1, 1, 1});
- Int32ReadAttribute ids = src_geometry.attribute_get_for_read<int>("id", domain, -1);
+ GVArray_Typed<int> ids = src_geometry.attribute_get_for_read<int>("id", domain, -1);
for (const int i : IndexRange(domain_size)) {
if (instances_data[i].has_value()) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
index 2e7fce6ea30..73d489949ad 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_rotate.cc
@@ -60,8 +60,8 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C),
namespace blender::nodes {
static void point_rotate__axis_angle__object_space(const int domain_size,
- const Float3ReadAttribute &axis,
- const FloatReadAttribute &angles,
+ const VArray<float3> &axis,
+ const VArray<float> &angles,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -76,8 +76,8 @@ static void point_rotate__axis_angle__object_space(const int domain_size,
}
static void point_rotate__axis_angle__point_space(const int domain_size,
- const Float3ReadAttribute &axis,
- const FloatReadAttribute &angles,
+ const VArray<float3> &axis,
+ const VArray<float> &angles,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -92,7 +92,7 @@ static void point_rotate__axis_angle__point_space(const int domain_size,
}
static void point_rotate__euler__object_space(const int domain_size,
- const Float3ReadAttribute &eulers,
+ const VArray<float3> &eulers,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -107,7 +107,7 @@ static void point_rotate__euler__object_space(const int domain_size,
}
static void point_rotate__euler__point_space(const int domain_size,
- const Float3ReadAttribute &eulers,
+ const VArray<float3> &eulers,
MutableSpan<float3> rotations)
{
for (const int i : IndexRange(domain_size)) {
@@ -127,19 +127,19 @@ static void point_rotate_on_component(GeometryComponent &component,
const bNode &node = params.node();
const NodeGeometryRotatePoints &storage = *(const NodeGeometryRotatePoints *)node.storage;
- OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
- "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ OutputAttribute_Typed<float3> rotation_attribute =
+ component.attribute_try_get_for_output<float3>("rotation", ATTR_DOMAIN_POINT, {0, 0, 0});
if (!rotation_attribute) {
return;
}
- MutableSpan<float3> rotations = rotation_attribute->get_span<float3>();
+ MutableSpan<float3> rotations = rotation_attribute.as_span();
const int domain_size = rotations.size();
if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) {
- Float3ReadAttribute axis = params.get_input_attribute<float3>(
+ GVArray_Typed<float3> axis = params.get_input_attribute<float3>(
"Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1});
- FloatReadAttribute angles = params.get_input_attribute<float>(
+ GVArray_Typed<float> angles = params.get_input_attribute<float>(
"Angle", component, ATTR_DOMAIN_POINT, 0);
if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
@@ -150,7 +150,7 @@ static void point_rotate_on_component(GeometryComponent &component,
}
}
else {
- Float3ReadAttribute eulers = params.get_input_attribute<float3>(
+ GVArray_Typed<float3> eulers = params.get_input_attribute<float3>(
"Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) {
@@ -161,7 +161,7 @@ static void point_rotate_on_component(GeometryComponent &component,
}
}
- rotation_attribute.apply_span_and_save();
+ rotation_attribute.save();
}
static void geo_node_point_rotate_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
index 113e2c620f6..2ef21fb085b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_scale.cc
@@ -50,7 +50,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
* for the factor. But for it's simpler to simply always use float3, since that is usually
* expected anyway. */
static const float3 scale_default = float3(1.0f);
- OutputAttributePtr scale_attribute = component.attribute_try_get_for_output(
+ OutputAttribute_Typed<float3> scale_attribute = component.attribute_try_get_for_output(
"scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, &scale_default);
if (!scale_attribute) {
return;
@@ -63,27 +63,27 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co
const CustomDataType data_type = (input_type == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ? CD_PROP_FLOAT :
CD_PROP_FLOAT3;
- ReadAttributePtr attribute = params.get_input_attribute(
+ GVArrayPtr attribute = params.get_input_attribute(
"Factor", component, ATTR_DOMAIN_POINT, data_type, nullptr);
if (!attribute) {
return;
}
- MutableSpan<float3> scale_span = scale_attribute->get_span<float3>();
+ MutableSpan<float3> scale_span = scale_attribute.as_span();
if (data_type == CD_PROP_FLOAT) {
- Span<float> factors = attribute->get_span<float>();
+ GVArray_Typed<float> factors{*attribute};
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * factors[i];
}
}
else if (data_type == CD_PROP_FLOAT3) {
- Span<float3> factors = attribute->get_span<float3>();
+ GVArray_Typed<float3> factors{*attribute};
for (const int i : scale_span.index_range()) {
scale_span[i] = scale_span[i] * factors[i];
}
}
- scale_attribute.apply_span_and_save();
+ scale_attribute.save();
}
static void geo_node_point_scale_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
index 522dea4aa0e..6541d982629 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
@@ -58,27 +58,27 @@ static void copy_attributes_based_on_mask(const GeometryComponent &in_component,
const bool invert)
{
for (const std::string &name : in_component.attribute_names()) {
- ReadAttributePtr attribute = in_component.attribute_try_get_for_read(name);
- const CustomDataType data_type = attribute->custom_data_type();
+ ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(name);
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type());
/* Only copy point attributes. Theoretically this could interpolate attributes on other
* domains to the point domain, but that would conflict with attributes that are built-in
* on other domains, which causes creating the attributes to fail. */
- if (attribute->domain() != ATTR_DOMAIN_POINT) {
+ if (attribute.domain != ATTR_DOMAIN_POINT) {
continue;
}
- OutputAttributePtr result_attribute = result_component.attribute_try_get_for_output(
+ OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only(
name, ATTR_DOMAIN_POINT, data_type);
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
- Span<T> span = attribute->get_span<T>();
- MutableSpan<T> out_span = result_attribute->get_span_for_write_only<T>();
+ GVArray_Span<T> span{*attribute.varray};
+ MutableSpan<T> out_span = result_attribute.as_span<T>();
copy_data_based_on_mask(span, masks, invert, out_span);
});
- result_attribute.apply_span_and_save();
+ result_attribute.save();
}
}
@@ -107,9 +107,9 @@ static void separate_points_from_component(const GeometryComponent &in_component
return;
}
- const BooleanReadAttribute mask_attribute = in_component.attribute_get_for_read<bool>(
+ const GVArray_Typed<bool> mask_attribute = in_component.attribute_get_for_read<bool>(
mask_name, ATTR_DOMAIN_POINT, false);
- Span<bool> masks = mask_attribute.get_span();
+ VArray_Span<bool> masks{mask_attribute};
const int total = masks.count(!invert);
if (total == 0) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
index 8c7387f7d9b..44203228899 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc
@@ -42,24 +42,19 @@ namespace blender::nodes {
static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
{
- OutputAttributePtr position_attribute = component.attribute_try_get_for_output(
- "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ OutputAttribute_Typed<float3> position_attribute =
+ component.attribute_try_get_for_output<float3>("position", ATTR_DOMAIN_POINT, {0, 0, 0});
if (!position_attribute) {
return;
}
- ReadAttributePtr attribute = params.get_input_attribute(
- "Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
- if (!attribute) {
- return;
- }
+ GVArray_Typed<float3> attribute = params.get_input_attribute<float3>(
+ "Translation", component, ATTR_DOMAIN_POINT, {0, 0, 0});
- Span<float3> data = attribute->get_span<float3>();
- MutableSpan<float3> scale_span = position_attribute->get_span<float3>();
- for (const int i : scale_span.index_range()) {
- scale_span[i] = scale_span[i] + data[i];
+ for (const int i : IndexRange(attribute.size())) {
+ position_attribute->set(i, position_attribute->get(i) + attribute[i]);
}
- position_attribute.apply_span_and_save();
+ position_attribute.save();
}
static void geo_node_point_translate_exec(GeoNodeExecParams params)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
index a9eb136597e..d73c83b4caf 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc
@@ -147,13 +147,15 @@ static void gather_point_data_from_component(const GeoNodeExecParams &params,
Vector<float3> &r_positions,
Vector<float> &r_radii)
{
- Float3ReadAttribute positions = component.attribute_get_for_read<float3>(
+ GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>(
"position", ATTR_DOMAIN_POINT, {0, 0, 0});
- FloatReadAttribute radii = params.get_input_attribute<float>(
+ GVArray_Typed<float> radii = params.get_input_attribute<float>(
"Radius", component, ATTR_DOMAIN_POINT, 0.0f);
- r_positions.extend(positions.get_span());
- r_radii.extend(radii.get_span());
+ for (const int i : IndexRange(positions.size())) {
+ r_positions.append(positions[i]);
+ r_radii.append(radii[i]);
+ }
}
static void convert_to_grid_index_space(const float voxel_size,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
new file mode 100644
index 00000000000..6736e963184
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#include "node_geometry_util.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+static bNodeSocketTemplate geo_node_switch_in[] = {
+ {SOCK_BOOLEAN, N_("Switch")},
+
+ {SOCK_FLOAT, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_FLOAT, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_INT, N_("A"), 0, 0, 0, 0, -100000, 100000},
+ {SOCK_INT, N_("B"), 0, 0, 0, 0, -100000, 100000},
+ {SOCK_BOOLEAN, N_("A")},
+ {SOCK_BOOLEAN, N_("B")},
+ {SOCK_VECTOR, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_VECTOR, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_RGBA, N_("A"), 0.8, 0.8, 0.8, 1.0},
+ {SOCK_RGBA, N_("B"), 0.8, 0.8, 0.8, 1.0},
+ {SOCK_STRING, N_("A")},
+ {SOCK_STRING, N_("B")},
+ {SOCK_GEOMETRY, N_("A")},
+ {SOCK_GEOMETRY, N_("B")},
+ {SOCK_OBJECT, N_("A")},
+ {SOCK_OBJECT, N_("B")},
+ {SOCK_COLLECTION, N_("A")},
+ {SOCK_COLLECTION, N_("B")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_switch_out[] = {
+ {SOCK_FLOAT, N_("Output")},
+ {SOCK_INT, N_("Output")},
+ {SOCK_BOOLEAN, N_("Output")},
+ {SOCK_VECTOR, N_("Output")},
+ {SOCK_RGBA, N_("Output")},
+ {SOCK_STRING, N_("Output")},
+ {SOCK_GEOMETRY, N_("Output")},
+ {SOCK_OBJECT, N_("Output")},
+ {SOCK_COLLECTION, N_("Output")},
+ {-1, ""},
+};
+
+static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE);
+}
+
+static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
+ data->input_type = SOCK_FLOAT;
+ node->storage = data;
+}
+
+namespace blender::nodes {
+
+template<typename T>
+void output_input(GeoNodeExecParams &params,
+ const bool input,
+ const StringRef input_suffix,
+ const StringRef output_identifier)
+{
+ if (input) {
+ params.set_output(output_identifier, params.extract_input<T>("B" + input_suffix));
+ }
+ else {
+ params.set_output(output_identifier, params.extract_input<T>("A" + input_suffix));
+ }
+}
+
+static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeSwitch *node_storage = (NodeSwitch *)node->storage;
+ int index = 0;
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) {
+ nodeSetSocketAvailability(
+ socket, index == 0 || socket->type == (eNodeSocketDatatype)node_storage->input_type);
+ index++;
+ }
+ LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+ nodeSetSocketAvailability(socket,
+ socket->type == (eNodeSocketDatatype)node_storage->input_type);
+ }
+}
+
+static void geo_node_switch_exec(GeoNodeExecParams params)
+{
+ const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage;
+ const bool input = params.extract_input<bool>("Switch");
+ switch ((eNodeSocketDatatype)storage.input_type) {
+ case SOCK_FLOAT: {
+ output_input<float>(params, input, "", "Output");
+ break;
+ }
+ case SOCK_INT: {
+ output_input<int>(params, input, "_001", "Output_001");
+ break;
+ }
+ case SOCK_BOOLEAN: {
+ output_input<bool>(params, input, "_002", "Output_002");
+ break;
+ }
+ case SOCK_VECTOR: {
+ output_input<float3>(params, input, "_003", "Output_003");
+ break;
+ }
+ case SOCK_RGBA: {
+ output_input<Color4f>(params, input, "_004", "Output_004");
+ break;
+ }
+ case SOCK_STRING: {
+ output_input<std::string>(params, input, "_005", "Output_005");
+ break;
+ }
+ case SOCK_GEOMETRY: {
+ output_input<GeometrySet>(params, input, "_006", "Output_006");
+ break;
+ }
+ case SOCK_OBJECT: {
+ output_input<bke::PersistentObjectHandle>(params, input, "_007", "Output_007");
+ break;
+ }
+ case SOCK_COLLECTION: {
+ output_input<bke::PersistentCollectionHandle>(params, input, "_008", "Output_008");
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_switch()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_switch_in, geo_node_switch_out);
+ node_type_init(&ntype, geo_node_switch_init);
+ node_type_update(&ntype, blender::nodes::geo_node_switch_update);
+ node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage);
+ ntype.geometry_node_execute = blender::nodes::geo_node_switch_exec;
+ ntype.draw_buttons = geo_node_switch_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index a4fb99a988e..2648336f0c0 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -22,6 +22,7 @@
#include "NOD_geometry_exec.hh"
#include "NOD_type_callbacks.hh"
+#include "NOD_type_conversions.hh"
#include "node_geometry_util.hh"
@@ -53,22 +54,29 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name
return nullptr;
}
-ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
- const GeometryComponent &component,
- const AttributeDomain domain,
- const CustomDataType type,
- const void *default_value) const
+GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name,
+ const GeometryComponent &component,
+ const AttributeDomain domain,
+ const CustomDataType type,
+ const void *default_value) const
{
const bNodeSocket *found_socket = this->find_available_socket(name);
BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */
+ const CPPType *cpp_type = bke::custom_data_type_to_cpp_type(type);
+ const int64_t domain_size = component.attribute_domain_size(domain);
+
+ if (default_value == nullptr) {
+ default_value = cpp_type->default_value();
+ }
+
if (found_socket == nullptr) {
- return component.attribute_get_constant_for_read(domain, type, default_value);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
}
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
/* Try getting the attribute without the default value. */
- ReadAttributePtr attribute = component.attribute_try_get_for_read(name, domain, type);
+ GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, type);
if (attribute) {
return attribute;
}
@@ -80,25 +88,29 @@ ReadAttributePtr GeoNodeExecParams::get_input_attribute(const StringRef name,
this->error_message_add(NodeWarningType::Error,
TIP_("No attribute with name \"") + name + "\"");
}
- return component.attribute_get_constant_for_read(domain, type, default_value);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
}
+ const DataTypeConversions &conversions = get_implicit_type_conversions();
if (found_socket->type == SOCK_FLOAT) {
const float value = this->get_input<float>(found_socket->identifier);
- return component.attribute_get_constant_for_read_converted(
- domain, CD_PROP_FLOAT, type, &value);
+ BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
+ conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_VECTOR) {
const float3 value = this->get_input<float3>(found_socket->identifier);
- return component.attribute_get_constant_for_read_converted(
- domain, CD_PROP_FLOAT3, type, &value);
+ BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
+ conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
if (found_socket->type == SOCK_RGBA) {
const Color4f value = this->get_input<Color4f>(found_socket->identifier);
- return component.attribute_get_constant_for_read_converted(
- domain, CD_PROP_COLOR, type, &value);
+ BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer);
+ conversions.convert_to_uninitialized(CPPType::get<Color4f>(), *cpp_type, &value, buffer);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer);
}
BLI_assert(false);
- return component.attribute_get_constant_for_read(domain, type, default_value);
+ return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value);
}
CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
@@ -114,11 +126,11 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type(
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
- ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
+ ReadAttributeLookup attribute = component.attribute_try_get_for_read(name);
if (!attribute) {
return default_type;
}
- return attribute->custom_data_type();
+ return bke::cpp_type_to_custom_data_type(attribute.varray->type());
}
if (found_socket->type == SOCK_FLOAT) {
return CD_PROP_FLOAT;
@@ -157,9 +169,9 @@ AttributeDomain GeoNodeExecParams::get_highest_priority_input_domain(
if (found_socket->type == SOCK_STRING) {
const std::string name = this->get_input<std::string>(found_socket->identifier);
- ReadAttributePtr attribute = component.attribute_try_get_for_read(name);
+ ReadAttributeLookup attribute = component.attribute_try_get_for_read(name);
if (attribute) {
- input_domains.append(attribute->domain());
+ input_domains.append(attribute.domain);
}
}
}
diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc
index 1c1b7c7feb5..63f7b8a9ee8 100644
--- a/source/blender/nodes/intern/type_conversions.cc
+++ b/source/blender/nodes/intern/type_conversions.cc
@@ -24,6 +24,9 @@
namespace blender::nodes {
+using fn::GVArrayPtr;
+using fn::GVMutableArray;
+using fn::GVMutableArrayPtr;
using fn::MFDataType;
template<typename From, typename To, To (*ConversionF)(const From &)>
@@ -227,6 +230,11 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type,
const void *from_value,
void *to_value) const
{
+ if (from_type == to_type) {
+ from_type.copy_to_uninitialized(from_value, to_value);
+ return;
+ }
+
const ConversionFunctions *functions = this->get_conversion_functions(
MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type));
BLI_assert(functions != nullptr);
@@ -234,4 +242,108 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type,
functions->convert_single_to_uninitialized(from_value, to_value);
}
+class GVArray_For_ConvertedGVArray : public GVArray {
+ private:
+ GVArrayPtr varray_;
+ const CPPType &from_type_;
+ ConversionFunctions old_to_new_conversions_;
+
+ public:
+ GVArray_For_ConvertedGVArray(GVArrayPtr varray,
+ const CPPType &to_type,
+ const DataTypeConversions &conversions)
+ : GVArray(to_type, varray->size()), varray_(std::move(varray)), from_type_(varray_->type())
+ {
+ old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type);
+ }
+
+ private:
+ void get_impl(const int64_t index, void *r_value) const override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ varray_->get(index, buffer);
+ old_to_new_conversions_.convert_single_to_initialized(buffer, r_value);
+ from_type_.destruct(buffer);
+ }
+
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ varray_->get(index, buffer);
+ old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value);
+ from_type_.destruct(buffer);
+ }
+};
+
+class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArray {
+ private:
+ GVMutableArrayPtr varray_;
+ const CPPType &from_type_;
+ ConversionFunctions old_to_new_conversions_;
+ ConversionFunctions new_to_old_conversions_;
+
+ public:
+ GVMutableArray_For_ConvertedGVMutableArray(GVMutableArrayPtr varray,
+ const CPPType &to_type,
+ const DataTypeConversions &conversions)
+ : GVMutableArray(to_type, varray->size()),
+ varray_(std::move(varray)),
+ from_type_(varray_->type())
+ {
+ old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type);
+ new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_);
+ }
+
+ private:
+ void get_impl(const int64_t index, void *r_value) const override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ varray_->get(index, buffer);
+ old_to_new_conversions_.convert_single_to_initialized(buffer, r_value);
+ from_type_.destruct(buffer);
+ }
+
+ void get_to_uninitialized_impl(const int64_t index, void *r_value) const override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ varray_->get(index, buffer);
+ old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value);
+ from_type_.destruct(buffer);
+ }
+
+ void set_by_move_impl(const int64_t index, void *value) override
+ {
+ BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer);
+ new_to_old_conversions_.convert_single_to_uninitialized(value, buffer);
+ varray_->set_by_relocate(index, buffer);
+ }
+};
+
+fn::GVArrayPtr DataTypeConversions::try_convert(fn::GVArrayPtr varray,
+ const CPPType &to_type) const
+{
+ const CPPType &from_type = varray->type();
+ if (from_type == to_type) {
+ return varray;
+ }
+ if (!this->is_convertible(from_type, to_type)) {
+ return {};
+ }
+ return std::make_unique<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this);
+}
+
+fn::GVMutableArrayPtr DataTypeConversions::try_convert(fn::GVMutableArrayPtr varray,
+ const CPPType &to_type) const
+{
+ const CPPType &from_type = varray->type();
+ if (from_type == to_type) {
+ return varray;
+ }
+ if (!this->is_convertible(from_type, to_type)) {
+ return {};
+ }
+ return std::make_unique<GVMutableArray_For_ConvertedGVMutableArray>(
+ std::move(varray), to_type, *this);
+}
+
} // namespace blender::nodes
diff --git a/source/blender/python/gpu/gpu_py_buffer.c b/source/blender/python/gpu/gpu_py_buffer.c
index d0965e83e33..e36e3b42617 100644
--- a/source/blender/python/gpu/gpu_py_buffer.c
+++ b/source/blender/python/gpu/gpu_py_buffer.c
@@ -37,17 +37,90 @@
#include "gpu_py_buffer.h"
-// #define PYGPU_BUFFER_PROTOCOL
+//#define PYGPU_BUFFER_PROTOCOL
+#define MAX_DIMENSIONS 64
/* -------------------------------------------------------------------- */
/** \name Utility Functions
* \{ */
-static bool pygpu_buffer_dimensions_compare(int ndim,
- const Py_ssize_t *shape_a,
- const Py_ssize_t *shape_b)
+static Py_ssize_t pygpu_buffer_dimensions_tot_elem(const Py_ssize_t *shape, Py_ssize_t shape_len)
+{
+ Py_ssize_t tot = shape[0];
+ for (int i = 1; i < shape_len; i++) {
+ tot *= shape[i];
+ }
+
+ return tot;
+}
+
+static bool pygpu_buffer_dimensions_tot_len_compare(const Py_ssize_t *shape_a,
+ const Py_ssize_t shape_a_len,
+ const Py_ssize_t *shape_b,
+ const Py_ssize_t shape_b_len)
+{
+ if (pygpu_buffer_dimensions_tot_elem(shape_a, shape_a_len) !=
+ pygpu_buffer_dimensions_tot_elem(shape_b, shape_b_len)) {
+ PyErr_Format(PyExc_BufferError, "array size does not match");
+ return false;
+ }
+
+ return true;
+}
+
+static bool pygpu_buffer_pyobj_as_shape(PyObject *shape_obj,
+ Py_ssize_t r_shape[MAX_DIMENSIONS],
+ Py_ssize_t *r_shape_len)
{
- return (bool)memcmp(shape_a, shape_b, ndim * sizeof(Py_ssize_t));
+ Py_ssize_t shape_len = 0;
+ if (PyLong_Check(shape_obj)) {
+ shape_len = 1;
+ if (((r_shape[0] = PyLong_AsLong(shape_obj)) < 1)) {
+ PyErr_SetString(PyExc_AttributeError, "dimension must be greater than or equal to 1");
+ return false;
+ }
+ }
+ else if (PySequence_Check(shape_obj)) {
+ shape_len = PySequence_Size(shape_obj);
+ if (shape_len > MAX_DIMENSIONS) {
+ PyErr_SetString(PyExc_AttributeError,
+ "too many dimensions, max is " STRINGIFY(MAX_DIMENSIONS));
+ return false;
+ }
+ if (shape_len < 1) {
+ PyErr_SetString(PyExc_AttributeError, "sequence must have at least one dimension");
+ return false;
+ }
+
+ for (int i = 0; i < shape_len; i++) {
+ PyObject *ob = PySequence_GetItem(shape_obj, i);
+ if (!PyLong_Check(ob)) {
+ PyErr_Format(PyExc_TypeError,
+ "invalid dimension %i, expected an int, not a %.200s",
+ i,
+ Py_TYPE(ob)->tp_name);
+ Py_DECREF(ob);
+ return false;
+ }
+
+ r_shape[i] = PyLong_AsLong(ob);
+ Py_DECREF(ob);
+
+ if (r_shape[i] < 1) {
+ PyErr_SetString(PyExc_AttributeError, "dimension must be greater than or equal to 1");
+ return false;
+ }
+ }
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "invalid second argument argument expected a sequence "
+ "or an int, not a %.200s",
+ Py_TYPE(shape_obj)->tp_name);
+ }
+
+ *r_shape_len = shape_len;
+ return true;
}
static const char *pygpu_buffer_formatstr(eGPUDataFormat data_format)
@@ -174,7 +247,7 @@ static PyObject *pygpu_buffer_to_list_recursive(BPyGPUBuffer *self)
return list;
}
-static PyObject *pygpu_buffer_dimensions(BPyGPUBuffer *self, void *UNUSED(arg))
+static PyObject *pygpu_buffer_dimensions_get(BPyGPUBuffer *self, void *UNUSED(arg))
{
PyObject *list = PyList_New(self->shape_len);
int i;
@@ -186,6 +259,30 @@ static PyObject *pygpu_buffer_dimensions(BPyGPUBuffer *self, void *UNUSED(arg))
return list;
}
+static int pygpu_buffer_dimensions_set(BPyGPUBuffer *self, PyObject *value, void *UNUSED(type))
+{
+ Py_ssize_t shape[MAX_DIMENSIONS];
+ Py_ssize_t shape_len = 0;
+
+ if (!pygpu_buffer_pyobj_as_shape(value, shape, &shape_len)) {
+ return -1;
+ }
+
+ if (!pygpu_buffer_dimensions_tot_len_compare(shape, shape_len, self->shape, self->shape_len)) {
+ return -1;
+ }
+
+ size_t size = shape_len * sizeof(*self->shape);
+ if (shape_len != self->shape_len) {
+ MEM_freeN(self->shape);
+ self->shape = MEM_mallocN(size, __func__);
+ }
+
+ self->shape_len = shape_len;
+ memcpy(self->shape, shape, size);
+ return 0;
+}
+
static int pygpu_buffer__tp_traverse(BPyGPUBuffer *self, visitproc visit, void *arg)
{
Py_VISIT(self->parent);
@@ -280,14 +377,13 @@ static int pygpu_buffer_ass_slice(BPyGPUBuffer *self,
return err;
}
-#define MAX_DIMENSIONS 64
static PyObject *pygpu_buffer__tp_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject *kwds)
{
PyObject *length_ob, *init = NULL;
BPyGPUBuffer *buffer = NULL;
Py_ssize_t shape[MAX_DIMENSIONS];
- Py_ssize_t i, shape_len = 0;
+ Py_ssize_t shape_len = 0;
if (kwds && PyDict_Size(kwds)) {
PyErr_SetString(PyExc_TypeError, "Buffer(): takes no keyword args");
@@ -300,49 +396,7 @@ static PyObject *pygpu_buffer__tp_new(PyTypeObject *UNUSED(type), PyObject *args
return NULL;
}
- if (PyLong_Check(length_ob)) {
- shape_len = 1;
- if (((shape[0] = PyLong_AsLong(length_ob)) < 1)) {
- PyErr_SetString(PyExc_AttributeError, "dimension must be greater than or equal to 1");
- return NULL;
- }
- }
- else if (PySequence_Check(length_ob)) {
- shape_len = PySequence_Size(length_ob);
- if (shape_len > MAX_DIMENSIONS) {
- PyErr_SetString(PyExc_AttributeError,
- "too many dimensions, max is " STRINGIFY(MAX_DIMENSIONS));
- return NULL;
- }
- if (shape_len < 1) {
- PyErr_SetString(PyExc_AttributeError, "sequence must have at least one dimension");
- return NULL;
- }
-
- for (i = 0; i < shape_len; i++) {
- PyObject *ob = PySequence_GetItem(length_ob, i);
- if (!PyLong_Check(ob)) {
- PyErr_Format(PyExc_TypeError,
- "invalid dimension %i, expected an int, not a %.200s",
- i,
- Py_TYPE(ob)->tp_name);
- Py_DECREF(ob);
- return NULL;
- }
- shape[i] = PyLong_AsLong(ob);
- Py_DECREF(ob);
-
- if (shape[i] < 1) {
- PyErr_SetString(PyExc_AttributeError, "dimension must be greater than or equal to 1");
- return NULL;
- }
- }
- }
- else {
- PyErr_Format(PyExc_TypeError,
- "invalid second argument argument expected a sequence "
- "or an int, not a %.200s",
- Py_TYPE(length_ob)->tp_name);
+ if (!pygpu_buffer_pyobj_as_shape(length_ob, shape, &shape_len)) {
return NULL;
}
@@ -354,11 +408,7 @@ static PyObject *pygpu_buffer__tp_new(PyTypeObject *UNUSED(type), PyObject *args
return NULL;
}
- if (shape_len != pybuffer.ndim ||
- !pygpu_buffer_dimensions_compare(shape_len, shape, pybuffer.shape)) {
- PyErr_Format(PyExc_TypeError, "array size does not match");
- }
- else {
+ if (pygpu_buffer_dimensions_tot_len_compare(shape, shape_len, pybuffer.shape, pybuffer.ndim)) {
buffer = pygpu_buffer_make_from_data(
init, pygpu_dataformat.value_found, pybuffer.ndim, shape, pybuffer.buf);
}
@@ -518,7 +568,11 @@ static PyMethodDef pygpu_buffer__tp_methods[] = {
};
static PyGetSetDef pygpu_buffer_getseters[] = {
- {"dimensions", (getter)pygpu_buffer_dimensions, NULL, NULL, NULL},
+ {"dimensions",
+ (getter)pygpu_buffer_dimensions_get,
+ (setter)pygpu_buffer_dimensions_set,
+ NULL,
+ NULL},
{NULL, NULL, NULL, NULL, NULL},
};
@@ -625,13 +679,7 @@ static size_t pygpu_buffer_calc_size(const int format,
const int shape_len,
const Py_ssize_t *shape)
{
- size_t r_size = GPU_texture_dataformat_size(format);
-
- for (int i = 0; i < shape_len; i++) {
- r_size *= shape[i];
- }
-
- return r_size;
+ return pygpu_buffer_dimensions_tot_elem(shape, shape_len) * GPU_texture_dataformat_size(format);
}
size_t bpygpu_Buffer_size(BPyGPUBuffer *buffer)
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 9ac8d4d9f47..2be2105d327 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -79,6 +79,7 @@ set(SRC
bpy_rna_driver.c
bpy_rna_gizmo.c
bpy_rna_id_collection.c
+ bpy_rna_operator.c
bpy_rna_types_capi.c
bpy_rna_ui.c
bpy_traceback.c
@@ -118,6 +119,7 @@ set(SRC
bpy_rna_driver.h
bpy_rna_gizmo.h
bpy_rna_id_collection.h
+ bpy_rna_operator.h
bpy_rna_types_capi.h
bpy_rna_ui.h
bpy_traceback.h
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 5f31e0bb74d..4144063cf5c 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -167,6 +167,14 @@ void bpy_context_clear(bContext *UNUSED(C), const PyGILState_STATE *gilstate)
}
}
+static void bpy_context_end(bContext *C)
+{
+ if (UNLIKELY(C == NULL)) {
+ return;
+ }
+ CTX_wm_operator_poll_msg_clear(C);
+}
+
/**
* Use for `CTX_*_set(..)` functions need to set values which are later read back as expected.
* In this case we don't want the Python context to override the values as it causes problems
@@ -524,6 +532,9 @@ void BPY_python_end(void)
/* finalizing, no need to grab the state, except when we are a module */
gilstate = PyGILState_Ensure();
+ /* Clear Python values in the context so freeing the context after Python exits doesn't crash. */
+ bpy_context_end(BPY_context_get());
+
/* Decrement user counts of all callback functions. */
BPY_rna_props_clear_all();
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index 94ad6a8ef78..4a5e2552598 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -244,12 +244,16 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
}
if (WM_operator_poll_context((bContext *)C, ot, context) == false) {
- const char *msg = CTX_wm_operator_poll_msg_get(C);
+ bool msg_free = false;
+ const char *msg = CTX_wm_operator_poll_msg_get(C, &msg_free);
PyErr_Format(PyExc_RuntimeError,
"Operator bpy.ops.%.200s.poll() %.200s",
opname,
msg ? msg : "failed, context is incorrect");
- CTX_wm_operator_poll_msg_set(C, NULL); /* better set to NULL else it could be used again */
+ CTX_wm_operator_poll_msg_clear(C);
+ if (msg_free) {
+ MEM_freeN((void *)msg);
+ }
error_val = -1;
}
else {
diff --git a/source/blender/python/intern/bpy_rna_operator.c b/source/blender/python/intern/bpy_rna_operator.c
new file mode 100644
index 00000000000..6e0db3eca49
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_operator.c
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ *
+ * This file extends `bpy.types.Operator` with C/Python API methods and attributes.
+ */
+
+#include <Python.h>
+
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+
+#include "../generic/python_utildefines.h"
+
+#include "BPY_extern.h"
+#include "bpy_capi_utils.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Operator `poll_message_set` Method
+ * \{ */
+
+static char *pyop_poll_message_get_fn(bContext *UNUSED(C), void *user_data)
+{
+ PyGILState_STATE gilstate = PyGILState_Ensure();
+
+ PyObject *py_args = user_data;
+ PyObject *py_func_or_msg = PyTuple_GET_ITEM(py_args, 0);
+
+ if (PyUnicode_Check(py_func_or_msg)) {
+ return BLI_strdup(PyUnicode_AsUTF8(py_func_or_msg));
+ }
+
+ PyObject *py_args_after_first = PyTuple_GetSlice(py_args, 1, PY_SSIZE_T_MAX);
+ PyObject *py_msg = PyObject_CallObject(py_func_or_msg, py_args_after_first);
+ Py_DECREF(py_args_after_first);
+
+ char *msg = NULL;
+ bool error = false;
+
+ /* NULL for no string. */
+ if (py_msg == NULL) {
+ error = true;
+ }
+ else {
+ if (py_msg == Py_None) {
+ /* pass */
+ }
+ else if (PyUnicode_Check(py_msg)) {
+ msg = BLI_strdup(PyUnicode_AsUTF8(py_msg));
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "poll_message_set(function, ...): expected string or None, got %.200s",
+ Py_TYPE(py_msg)->tp_name);
+ error = true;
+ }
+ Py_DECREF(py_msg);
+ }
+
+ if (error) {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ PyGILState_Release(gilstate);
+ return msg;
+}
+
+static void pyop_poll_message_free_fn(bContext *UNUSED(C), void *user_data)
+{
+ /* Handles the GIL. */
+ BPY_DECREF(user_data);
+}
+
+PyDoc_STRVAR(BPY_rna_operator_poll_message_set_doc,
+ ".. method:: poll_message_set(message, ...)\n"
+ "\n"
+ " Set the message to show in the tool-tip when poll fails.\n"
+ "\n"
+ " When message is callable, "
+ "additional user defined positional arguments are passed to the message function.\n"
+ "\n"
+ " :param message: The message or a function that returns the message.\n"
+ " :type message: string or a callable that returns a string or None.\n");
+
+static PyObject *BPY_rna_operator_poll_message_set(PyObject *UNUSED(self), PyObject *args)
+{
+ const ssize_t args_len = PyTuple_GET_SIZE(args);
+ if (args_len == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "poll_message_set(message, ...): requires a message argument");
+ return NULL;
+ }
+
+ PyObject *py_func_or_msg = PyTuple_GET_ITEM(args, 0);
+
+ if (PyUnicode_Check(py_func_or_msg)) {
+ if (args_len > 1) {
+ PyErr_SetString(PyExc_ValueError,
+ "poll_message_set(message): does not support additional arguments");
+ return NULL;
+ }
+ }
+ else if (PyCallable_Check(py_func_or_msg)) {
+ /* pass */
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "poll_message_set(message, ...): "
+ "expected at least 1 string or callable argument, got %.200s",
+ Py_TYPE(py_func_or_msg)->tp_name);
+ return NULL;
+ }
+
+ bContext *C = BPY_context_get();
+ struct bContextPollMsgDyn_Params params = {
+ .get_fn = pyop_poll_message_get_fn,
+ .free_fn = pyop_poll_message_free_fn,
+ .user_data = Py_INCREF_RET(args),
+ };
+
+ CTX_wm_operator_poll_msg_set_dynamic(C, &params);
+
+ Py_RETURN_NONE;
+}
+
+PyMethodDef BPY_rna_operator_poll_message_set_method_def = {
+ "poll_message_set",
+ (PyCFunction)BPY_rna_operator_poll_message_set,
+ METH_VARARGS | METH_STATIC,
+ BPY_rna_operator_poll_message_set_doc,
+};
+
+/** \} */
diff --git a/source/blender/python/intern/bpy_rna_operator.h b/source/blender/python/intern/bpy_rna_operator.h
new file mode 100644
index 00000000000..8040d8a492a
--- /dev/null
+++ b/source/blender/python/intern/bpy_rna_operator.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup pythonintern
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern PyMethodDef BPY_rna_operator_poll_message_set_method_def;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c
index 9b15e84663d..2f6e197d1e2 100644
--- a/source/blender/python/intern/bpy_rna_types_capi.c
+++ b/source/blender/python/intern/bpy_rna_types_capi.c
@@ -41,6 +41,8 @@
#include "bpy_rna_types_capi.h"
#include "bpy_rna_ui.h"
+#include "bpy_rna_operator.h"
+
#include "../generic/py_capi_utils.h"
#include "RNA_access.h"
@@ -87,6 +89,17 @@ static struct PyMethodDef pyrna_uilayout_methods[] = {
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Operator
+ * \{ */
+
+static struct PyMethodDef pyrna_operator_methods[] = {
+ {NULL, NULL, 0, NULL}, /* #BPY_rna_operator_poll_message_set */
+ {NULL, NULL, 0, NULL},
+};
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Window Manager Clipboard Property
*
* Avoid using the RNA API because this value may change between checking its length
@@ -228,6 +241,11 @@ void BPY_rna_types_extend_capi(void)
/* Space */
pyrna_struct_type_extend_capi(&RNA_Space, pyrna_space_methods, NULL);
+ /* wmOperator */
+ ARRAY_SET_ITEMS(pyrna_operator_methods, BPY_rna_operator_poll_message_set_method_def);
+ BLI_assert(ARRAY_SIZE(pyrna_operator_methods) == 2);
+ pyrna_struct_type_extend_capi(&RNA_Operator, pyrna_operator_methods, NULL);
+
/* WindowManager */
pyrna_struct_type_extend_capi(
&RNA_WindowManager, pyrna_windowmanager_methods, pyrna_windowmanager_getset);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index d54925272de..1d99b605205 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -132,17 +132,21 @@ struct wmWindowManager;
extern "C" {
#endif
+typedef void (*wmGenericUserDataFreeFn)(void *data);
+
typedef struct wmGenericUserData {
void *data;
/** When NULL, use #MEM_freeN. */
- void (*free_fn)(void *data);
+ wmGenericUserDataFreeFn free_fn;
bool use_free;
} wmGenericUserData;
+typedef void (*wmGenericCallbackFn)(struct bContext *C, void *user_data);
+
typedef struct wmGenericCallback {
- void (*exec)(struct bContext *C, void *user_data);
+ wmGenericCallbackFn exec;
void *user_data;
- void (*free_user_data)(void *user_data);
+ wmGenericUserDataFreeFn free_user_data;
} wmGenericCallback;
/* ************** wmOperatorType ************************ */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 0d1f4cc4830..5dfbd393c14 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -1048,7 +1048,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
wmWindowManager *wm = CTX_wm_manager(C);
int retval = OPERATOR_CANCELLED;
- CTX_wm_operator_poll_msg_set(C, NULL);
+ CTX_wm_operator_poll_msg_clear(C);
if (op == NULL || op->type == NULL) {
return retval;
@@ -1469,7 +1469,7 @@ static int wm_operator_call_internal(bContext *C,
{
int retval;
- CTX_wm_operator_poll_msg_set(C, NULL);
+ CTX_wm_operator_poll_msg_clear(C);
/* Dummy test. */
if (ot) {
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index bbcb0669cce..614824ef7e2 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -2157,21 +2157,9 @@ static void wm_homefile_read_after_dialog_callback(bContext *C, void *user_data)
C, "WM_OT_read_homefile", WM_OP_EXEC_DEFAULT, (IDProperty *)user_data);
}
-static void wm_free_operator_properties_callback(void *user_data)
-{
- IDProperty *properties = (IDProperty *)user_data;
- IDP_FreeProperty(properties);
-}
-
static int wm_homefile_read_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- if (U.uiflag & USER_SAVE_PROMPT &&
- wm_file_or_image_is_modified(CTX_data_main(C), CTX_wm_manager(C))) {
- wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
- callback->exec = wm_homefile_read_after_dialog_callback;
- callback->user_data = IDP_CopyProperty(op->properties);
- callback->free_user_data = wm_free_operator_properties_callback;
- wm_close_file_dialog(C, callback);
+ if (wm_operator_close_file_dialog_if_needed(C, op, wm_homefile_read_after_dialog_callback)) {
return OPERATOR_INTERFACE;
}
return wm_homefile_read_exec(C, op);
@@ -2331,13 +2319,7 @@ static int wm_open_mainfile__discard_changes(bContext *C, wmOperator *op)
set_next_operator_state(op, OPEN_MAINFILE_STATE_OPEN);
}
- if (U.uiflag & USER_SAVE_PROMPT &&
- wm_file_or_image_is_modified(CTX_data_main(C), CTX_wm_manager(C))) {
- wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
- callback->exec = wm_open_mainfile_after_dialog_callback;
- callback->user_data = IDP_CopyProperty(op->properties);
- callback->free_user_data = wm_free_operator_properties_callback;
- wm_close_file_dialog(C, callback);
+ if (wm_operator_close_file_dialog_if_needed(C, op, wm_open_mainfile_after_dialog_callback)) {
return OPERATOR_INTERFACE;
}
return wm_open_mainfile_dispatch(C, op);
@@ -2637,12 +2619,25 @@ static int wm_recover_last_session_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-static int wm_recover_last_session_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static void wm_recover_last_session_after_dialog_callback(bContext *C, void *user_data)
+{
+ WM_operator_name_call_with_properties(
+ C, "WM_OT_recover_last_session", WM_OP_EXEC_DEFAULT, (IDProperty *)user_data);
+}
+
+static int wm_recover_last_session_invoke(bContext *C,
+ wmOperator *op,
+ const wmEvent *UNUSED(event))
{
/* Keep the current setting instead of using the preferences since a file selector
* doesn't give us the option to change the setting. */
wm_open_init_use_scripts(op, false);
- return WM_operator_confirm(C, op, event);
+
+ if (wm_operator_close_file_dialog_if_needed(
+ C, op, wm_recover_last_session_after_dialog_callback)) {
+ return OPERATOR_INTERFACE;
+ }
+ return wm_recover_last_session_exec(C, op);
}
void WM_OT_recover_last_session(wmOperatorType *ot)
@@ -3456,4 +3451,31 @@ void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action)
}
}
+static void wm_free_operator_properties_callback(void *user_data)
+{
+ IDProperty *properties = (IDProperty *)user_data;
+ IDP_FreeProperty(properties);
+}
+
+/**
+ * \return True if the dialog was created, the calling operator should return #OPERATOR_INTERFACE
+ * then.
+ */
+bool wm_operator_close_file_dialog_if_needed(bContext *C,
+ wmOperator *op,
+ wmGenericCallbackFn post_action_fn)
+{
+ if (U.uiflag & USER_SAVE_PROMPT &&
+ wm_file_or_image_is_modified(CTX_data_main(C), CTX_wm_manager(C))) {
+ wmGenericCallback *callback = MEM_callocN(sizeof(*callback), __func__);
+ callback->exec = post_action_fn;
+ callback->user_data = IDP_CopyProperty(op->properties);
+ callback->free_user_data = wm_free_operator_properties_callback;
+ wm_close_file_dialog(C, callback);
+ return true;
+ }
+
+ return false;
+}
+
/** \} */
diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h
index d54090a6025..533084e96e8 100644
--- a/source/blender/windowmanager/wm_files.h
+++ b/source/blender/windowmanager/wm_files.h
@@ -45,6 +45,7 @@ void wm_homefile_read(struct bContext *C,
void wm_file_read_report(bContext *C, struct Main *bmain);
void wm_close_file_dialog(bContext *C, struct wmGenericCallback *post_action);
+bool wm_operator_close_file_dialog_if_needed(bContext *C, wmOperator *op, wmGenericCallbackFn exec_fn);
bool wm_file_or_image_is_modified(const Main *bmain, const wmWindowManager *wm);
void WM_OT_save_homefile(struct wmOperatorType *ot);