diff options
Diffstat (limited to 'source/blender/blenkernel')
139 files changed, 4899 insertions, 3070 deletions
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh index 1e61e477759..6284cce9dc0 100644 --- a/source/blender/blenkernel/BKE_attribute.hh +++ b/source/blender/blenkernel/BKE_attribute.hh @@ -2,6 +2,8 @@ #pragma once +#include <optional> + #include "BLI_color.hh" #include "BLI_function_ref.hh" #include "BLI_generic_span.hh" @@ -71,8 +73,13 @@ struct AttributeKind { */ struct AttributeInit { enum class Type { - Default, + /** #AttributeInitConstruct. */ + Construct, + /** #AttributeInitDefaultValue. */ + DefaultValue, + /** #AttributeInitVArray. */ VArray, + /** #AttributeInitMoveArray. */ MoveArray, }; Type type; @@ -82,11 +89,20 @@ struct AttributeInit { }; /** - * Create an attribute using the default value for the data type. - * The default values may depend on the attribute provider implementation. + * Default construct new attribute values. Does nothing for trivial types. This should be used + * if all attribute element values will be set by the caller after creating the attribute. */ -struct AttributeInitDefault : public AttributeInit { - AttributeInitDefault() : AttributeInit(Type::Default) +struct AttributeInitConstruct : public AttributeInit { + AttributeInitConstruct() : AttributeInit(Type::Construct) + { + } +}; + +/** + * Create an attribute using the default value for the data type (almost always "zero"). + */ +struct AttributeInitDefaultValue : public AttributeInit { + AttributeInitDefaultValue() : AttributeInit(Type::DefaultValue) { } }; @@ -94,14 +110,11 @@ struct AttributeInitDefault : public AttributeInit { /** * Create an attribute by copying data from an existing virtual array. The virtual array * must have the same type as the newly created attribute. - * - * Note that this can be used to fill the new attribute with the default */ struct AttributeInitVArray : public AttributeInit { - blender::GVArray varray; + GVArray varray; - AttributeInitVArray(blender::GVArray varray) - : AttributeInit(Type::VArray), varray(std::move(varray)) + AttributeInitVArray(GVArray varray) : AttributeInit(Type::VArray), varray(std::move(varray)) { } }; @@ -117,10 +130,10 @@ struct AttributeInitVArray : public AttributeInit { * The array must be allocated with MEM_*, since `attribute_try_create` will free the array if it * can't be used directly, and that is generally how Blender expects custom data to be allocated. */ -struct AttributeInitMove : public AttributeInit { +struct AttributeInitMoveArray : public AttributeInit { void *data = nullptr; - AttributeInitMove(void *data) : AttributeInit(Type::MoveArray), data(data) + AttributeInitMoveArray(void *data) : AttributeInit(Type::MoveArray), data(data) { } }; @@ -150,7 +163,7 @@ template<typename T> struct AttributeReader { }; /** - * Result when looking up an attribute from some geometry with read an write access. After writing + * Result when looking up an attribute from some geometry with read and write access. After writing * to the attribute, the #finish method has to be called. This may invalidate caches based on this * attribute. */ @@ -577,7 +590,7 @@ class MutableAttributeAccessor : public AttributeAccessor { const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, - const AttributeInit &initializer = AttributeInitDefault()); + const AttributeInit &initializer = AttributeInitDefaultValue()); /** * Same as above, but returns a type that makes it easier to work with the attribute as a span. @@ -588,7 +601,7 @@ class MutableAttributeAccessor : public AttributeAccessor { const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type, - const AttributeInit &initializer = AttributeInitDefault()); + const AttributeInit &initializer = AttributeInitDefaultValue()); /** * Same as above, but should be used when the type is known at compile time. @@ -597,7 +610,7 @@ class MutableAttributeAccessor : public AttributeAccessor { AttributeWriter<T> lookup_or_add_for_write( const AttributeIDRef &attribute_id, const eAttrDomain domain, - const AttributeInit &initializer = AttributeInitDefault()) + const AttributeInit &initializer = AttributeInitDefaultValue()) { const CPPType &cpp_type = CPPType::get<T>(); const eCustomDataType data_type = cpp_type_to_custom_data_type(cpp_type); @@ -611,7 +624,7 @@ class MutableAttributeAccessor : public AttributeAccessor { SpanAttributeWriter<T> lookup_or_add_for_write_span( const AttributeIDRef &attribute_id, const eAttrDomain domain, - const AttributeInit &initializer = AttributeInitDefault()) + const AttributeInit &initializer = AttributeInitDefaultValue()) { AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>( attribute_id, domain, initializer); diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh index 01c2ef988f2..770937688d7 100644 --- a/source/blender/blenkernel/BKE_attribute_math.hh +++ b/source/blender/blenkernel/BKE_attribute_math.hh @@ -188,10 +188,28 @@ template<typename T> class SimpleMixer { * \param default_value: Output value for an element that has not been affected by a #mix_in. */ SimpleMixer(MutableSpan<T> buffer, T default_value = {}) + : SimpleMixer(buffer, buffer.index_range(), default_value) + { + } + + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + SimpleMixer(MutableSpan<T> buffer, const IndexMask mask, T default_value = {}) : buffer_(buffer), default_value_(default_value), total_weights_(buffer.size(), 0.0f) { BLI_STATIC_ASSERT(std::is_trivial_v<T>, ""); - memset(buffer_.data(), 0, sizeof(T) * buffer_.size()); + mask.foreach_index([&](const int64_t i) { buffer_[i] = default_value_; }); + } + + /** + * Set a #value into the element with the given #index. + */ + void set(const int64_t index, const T &value, const float weight = 1.0f) + { + BLI_assert(weight >= 0.0f); + buffer_[index] = value * weight; + total_weights_[index] = weight; } /** @@ -209,7 +227,12 @@ template<typename T> class SimpleMixer { */ void finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(IndexMask(buffer_.size())); + } + + void finalize(const IndexMask mask) + { + mask.foreach_index([&](const int64_t i) { const float weight = total_weights_[i]; if (weight > 0.0f) { buffer_[i] *= 1.0f / weight; @@ -217,7 +240,7 @@ template<typename T> class SimpleMixer { else { buffer_[i] = default_value_; } - } + }); } }; @@ -237,9 +260,25 @@ class BooleanPropagationMixer { /** * \param buffer: Span where the interpolated values should be stored. */ - BooleanPropagationMixer(MutableSpan<bool> buffer) : buffer_(buffer) + BooleanPropagationMixer(MutableSpan<bool> buffer) + : BooleanPropagationMixer(buffer, buffer.index_range()) + { + } + + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + BooleanPropagationMixer(MutableSpan<bool> buffer, const IndexMask mask) : buffer_(buffer) + { + mask.foreach_index([&](const int64_t i) { buffer_[i] = false; }); + } + + /** + * Set a #value into the element with the given #index. + */ + void set(const int64_t index, const bool value, [[maybe_unused]] const float weight = 1.0f) { - buffer_.fill(false); + buffer_[index] = value; } /** @@ -256,6 +295,10 @@ class BooleanPropagationMixer { void finalize() { } + + void finalize(const IndexMask /*mask*/) + { + } }; /** @@ -277,8 +320,27 @@ class SimpleMixerWithAccumulationType { public: SimpleMixerWithAccumulationType(MutableSpan<T> buffer, T default_value = {}) + : SimpleMixerWithAccumulationType(buffer, buffer.index_range(), default_value) + { + } + + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + SimpleMixerWithAccumulationType(MutableSpan<T> buffer, + const IndexMask mask, + T default_value = {}) : buffer_(buffer), default_value_(default_value), accumulation_buffer_(buffer.size()) { + mask.foreach_index([&](const int64_t index) { buffer_[index] = default_value_; }); + } + + void set(const int64_t index, const T &value, const float weight = 1.0f) + { + const AccumulationT converted_value = static_cast<AccumulationT>(value); + Item &item = accumulation_buffer_[index]; + item.value = converted_value * weight; + item.weight = weight; } void mix_in(const int64_t index, const T &value, const float weight = 1.0f) @@ -291,7 +353,12 @@ class SimpleMixerWithAccumulationType { void finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(buffer_.index_range()); + } + + void finalize(const IndexMask mask) + { + mask.foreach_index([&](const int64_t i) { const Item &item = accumulation_buffer_[i]; if (item.weight > 0.0f) { const float weight_inv = 1.0f / item.weight; @@ -301,7 +368,7 @@ class SimpleMixerWithAccumulationType { else { buffer_[i] = default_value_; } - } + }); } }; @@ -314,8 +381,16 @@ class ColorGeometry4fMixer { public: ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, + IndexMask mask, + ColorGeometry4f default_color = ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); + void set(int64_t index, const ColorGeometry4f &color, float weight = 1.0f); void mix_in(int64_t index, const ColorGeometry4f &color, float weight = 1.0f); void finalize(); + void finalize(IndexMask mask); }; class ColorGeometry4bMixer { @@ -328,8 +403,16 @@ class ColorGeometry4bMixer { public: ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, ColorGeometry4b default_color = ColorGeometry4b(0, 0, 0, 255)); + /** + * \param mask: Only initialize these indices. Other indices in the buffer will be invalid. + */ + ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, + IndexMask mask, + ColorGeometry4b default_color = ColorGeometry4b(0, 0, 0, 255)); + void set(int64_t index, const ColorGeometry4b &color, float weight = 1.0f); void mix_in(int64_t index, const ColorGeometry4b &color, float weight = 1.0f); void finalize(); + void finalize(IndexMask mask); }; template<typename T> struct DefaultMixerStruct { @@ -381,12 +464,12 @@ template<> struct DefaultMixerStruct<int8_t> { using type = SimpleMixerWithAccumulationType<int8_t, float, float_to_int8_t>; }; -template<typename T> struct DefaultPropatationMixerStruct { +template<typename T> struct DefaultPropagationMixerStruct { /* Use void by default. This can be checked for in `if constexpr` statements. */ using type = typename DefaultMixerStruct<T>::type; }; -template<> struct DefaultPropatationMixerStruct<bool> { +template<> struct DefaultPropagationMixerStruct<bool> { using type = BooleanPropagationMixer; }; @@ -396,7 +479,7 @@ template<> struct DefaultPropatationMixerStruct<bool> { * (the default mixing for booleans). */ template<typename T> -using DefaultPropatationMixer = typename DefaultPropatationMixerStruct<T>::type; +using DefaultPropagationMixer = typename DefaultPropagationMixerStruct<T>::type; /* Utility to get a good default mixer for a given type. This is `void` when there is no default * mixer for the given type. */ diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 9cfbc5355d7..ee9c7a964d9 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -17,15 +17,15 @@ extern "C" { */ /* Blender major and minor version. */ -#define BLENDER_VERSION 303 +#define BLENDER_VERSION 304 /* Blender patch version for bugfix releases. */ #define BLENDER_VERSION_PATCH 0 /** Blender release cycle stage: alpha/beta/rc/release. */ -#define BLENDER_VERSION_CYCLE rc +#define BLENDER_VERSION_CYCLE alpha /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 6 +#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_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index fd559abf7f2..43ad340103a 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -33,7 +33,7 @@ void BKE_cachefile_eval(struct Main *bmain, bool BKE_cachefile_filepath_get(const struct Main *bmain, const struct Depsgraph *depsgrah, const struct CacheFile *cache_file, - char r_filename[1024]); + char r_filepath[1024]); double BKE_cachefile_time_offset(const struct CacheFile *cache_file, double time, double fps); @@ -53,10 +53,12 @@ void BKE_cachefile_reader_free(struct CacheFile *cache_file, struct CacheReader bool BKE_cache_file_uses_render_procedural(const struct CacheFile *cache_file, struct Scene *scene); -/* Add a layer to the cache_file. Return NULL if the filename is already that of an existing layer - * or if the number of layers exceeds the maximum allowed layer count. */ +/** + * Add a layer to the cache_file. Return NULL if the `filepath` is already that of an existing + * layer or if the number of layers exceeds the maximum allowed layer count. + */ struct CacheFileLayer *BKE_cachefile_add_layer(struct CacheFile *cache_file, - const char filename[1024]); + const char filepath[1024]); struct CacheFileLayer *BKE_cachefile_get_active_layer(struct CacheFile *cache_file); diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index 2b9b13d1d2b..4b0fc293b54 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -97,7 +97,7 @@ class CurvesGeometryRuntime { mutable Span<float3> evaluated_positions_span; /** - * Cache of lengths along each evaluated curve for for each evaluated point. If a curve is + * Cache of lengths along each evaluated curve for each evaluated point. If a curve is * cyclic, it needs one more length value to correspond to the last segment, so in order to * make slicing this array for a curve fast, an extra float is stored for every curve. */ @@ -150,7 +150,13 @@ class CurvesGeometry : public ::CurvesGeometry { * Accessors. */ + /** + * The total number of control points in all curves. + */ int points_num() const; + /** + * The number of curves in the data-block. + */ int curves_num() const; IndexRange points_range() const; IndexRange curves_range() const; @@ -553,7 +559,7 @@ void calculate_evaluated_offsets(Span<int8_t> handle_types_left, int resolution, MutableSpan<int> evaluated_offsets); -/** See #insert. */ +/** Knot insertion result, see #insert. */ struct Insertion { float3 handle_prev; float3 left_handle; @@ -563,8 +569,12 @@ struct Insertion { }; /** - * Compute the Bezier segment insertion for the given parameter on the segment, returning - * the position and handles of the new point and the updated existing handle positions. + * Compute the insertion of a control point and handles in a Bezier segment without changing its + * shape. + * \param parameter: Factor in from 0 to 1 defining the insertion point within the segment. + * \return Inserted point parameters including position, and both new and updated handles for + * neighboring control points. + * * <pre> * handle_prev handle_next * x-----------------x diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index fec376fd415..44a4f4b5395 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -11,7 +11,9 @@ #include "BLI_sys_types.h" #include "BLI_utildefines.h" #ifdef __cplusplus +# include "BLI_set.hh" # include "BLI_span.hh" +# include "BLI_string_ref.hh" # include "BLI_vector.hh" #endif @@ -53,14 +55,17 @@ extern const CustomData_MeshMasks CD_MASK_EVERYTHING; typedef enum eCDAllocType { /** Use the data pointer. */ CD_ASSIGN = 0, - /** Allocate blank memory. */ - CD_CALLOC = 1, - /** Allocate and set to default. */ - CD_DEFAULT = 2, + /** Allocate and set to default, which is usually just zeroed memory. */ + CD_SET_DEFAULT = 2, /** Use data pointers, set layer flag NOFREE. */ CD_REFERENCE = 3, /** Do a full copy of all layers, only allowed if source has same number of elements. */ CD_DUPLICATE = 4, + /** + * Default construct new layer values. Does nothing for trivial types. This should be used + * if all layer values will be set by the caller after creating the layer. + */ + CD_CONSTRUCT = 5, } eCDAllocType; #define CD_TYPE_AS_MASK(_type) (eCustomDataMask)((eCustomDataMask)1 << (eCustomDataMask)(_type)) @@ -141,6 +146,15 @@ void CustomData_copy(const struct CustomData *source, eCDAllocType alloctype, int totelem); +/** + * Like #CustomData_copy but skips copying layers that are stored as flags on #BMesh. + */ +void CustomData_copy_mesh_to_bmesh(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem); + /* BMESH_TODO, not really a public function but readfile.c needs it */ void CustomData_update_typemap(struct CustomData *data); @@ -155,6 +169,15 @@ bool CustomData_merge(const struct CustomData *source, int totelem); /** + * Like #CustomData_copy but skips copying layers that are stored as flags on #BMesh. + */ +bool CustomData_merge_mesh_to_bmesh(const struct CustomData *source, + struct CustomData *dest, + eCustomDataMask mask, + eCDAllocType alloctype, + int totelem); + +/** * Reallocate custom data to a new element count. * Only affects on data layers which are owned by the CustomData itself, * referenced data is kept unchanged, @@ -397,7 +420,7 @@ void *CustomData_bmesh_get_n(const struct CustomData *data, void *block, int typ */ void *CustomData_bmesh_get_layer_n(const struct CustomData *data, void *block, int n); -bool CustomData_set_layer_name(const struct CustomData *data, int type, int n, const char *name); +bool CustomData_set_layer_name(struct CustomData *data, int type, int n, const char *name); const char *CustomData_get_layer_name(const struct CustomData *data, int type, int n); /** @@ -431,6 +454,12 @@ int CustomData_get_stencil_layer(const struct CustomData *data, int type); const char *CustomData_get_active_layer_name(const struct CustomData *data, int type); /** + * Returns name of the default layer of the given type or NULL + * if no such active layer is defined. + */ +const char *CustomData_get_render_layer_name(const struct CustomData *data, int type); + +/** * Copies the data from source to the data element at index in the first layer of type * no effect if there is no layer of type. */ @@ -697,7 +726,8 @@ void CustomData_data_transfer(const struct MeshPairRemap *me_remap, * the struct. */ void CustomData_blend_write_prepare(CustomData &data, - blender::Vector<CustomDataLayer, 16> &layers_to_write); + blender::Vector<CustomDataLayer, 16> &layers_to_write, + const blender::Set<std::string> &skip_names = {}); /** * \param layers_to_write: Layers created by #CustomData_blend_write_prepare. diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 7a21e85e310..6551e732300 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -24,8 +24,6 @@ enum { DL_SURF = 2, /** Triangles. */ DL_INDEX3 = 4, - /** Quads, with support for triangles (when values of the 3rd and 4th indices match). */ - DL_INDEX4 = 5, // DL_VERTCOL = 6, /* UNUSED */ /** Isolated points. */ DL_VERTS = 7, @@ -61,17 +59,13 @@ typedef struct DispList { int totindex; /* indexed array drawing surfaces */ } DispList; -void BKE_displist_copy(struct ListBase *lbn, const struct ListBase *lb); DispList *BKE_displist_find(struct ListBase *lb, int type); -void BKE_displist_normals_add(struct ListBase *lb); -void BKE_displist_count(const struct ListBase *lb, int *totvert, int *totface, int *tottri); void BKE_displist_free(struct ListBase *lb); void BKE_displist_make_curveTypes(struct Depsgraph *depsgraph, const struct Scene *scene, struct Object *ob, bool for_render); -void BKE_displist_make_mball(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); void BKE_curve_calc_modifiers_pre(struct Depsgraph *depsgraph, const struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h index b6b1bdab109..a1b97222019 100644 --- a/source/blender/blenkernel/BKE_fcurve_driver.h +++ b/source/blender/blenkernel/BKE_fcurve_driver.h @@ -85,7 +85,6 @@ void driver_free_variable_ex(struct ChannelDriver *driver, struct DriverVar *dva void driver_change_variable_type(struct DriverVar *dvar, int type); /** * Validate driver variable name (after being renamed). - * */ void driver_variable_name_validate(struct DriverVar *dvar); /** diff --git a/source/blender/blenkernel/BKE_geometry_fields.hh b/source/blender/blenkernel/BKE_geometry_fields.hh index 7c504826044..62aac5a4120 100644 --- a/source/blender/blenkernel/BKE_geometry_fields.hh +++ b/source/blender/blenkernel/BKE_geometry_fields.hh @@ -8,47 +8,186 @@ * Common field utilities and field definitions for geometry components. */ +#include "BKE_attribute.h" #include "BKE_geometry_set.hh" #include "FN_field.hh" +struct Mesh; +struct PointCloud; + namespace blender::bke { -class GeometryComponentFieldContext : public fn::FieldContext { +class CurvesGeometry; +class GeometryFieldInput; + +class MeshFieldContext : public fn::FieldContext { + private: + const Mesh &mesh_; + const eAttrDomain domain_; + + public: + MeshFieldContext(const Mesh &mesh, const eAttrDomain domain); + const Mesh &mesh() const + { + return mesh_; + } + + eAttrDomain domain() const + { + return domain_; + } +}; + +class CurvesFieldContext : public fn::FieldContext { + private: + const CurvesGeometry &curves_; + const eAttrDomain domain_; + + public: + CurvesFieldContext(const CurvesGeometry &curves, const eAttrDomain domain); + + const CurvesGeometry &curves() const + { + return curves_; + } + + eAttrDomain domain() const + { + return domain_; + } +}; + +class PointCloudFieldContext : public fn::FieldContext { + private: + const PointCloud &pointcloud_; + + public: + PointCloudFieldContext(const PointCloud &pointcloud) : pointcloud_(pointcloud) + { + } + + const PointCloud &pointcloud() const + { + return pointcloud_; + } +}; + +class InstancesFieldContext : public fn::FieldContext { + private: + const InstancesComponent &instances_; + + public: + InstancesFieldContext(const InstancesComponent &instances) : instances_(instances) + { + } + + const InstancesComponent &instances() const + { + return instances_; + } +}; + +/** + * A field context that can represent meshes, curves, point clouds, or instances, + * used for field inputs that can work for multiple geometry types. + */ +class GeometryFieldContext : public fn::FieldContext { private: - const GeometryComponent &component_; + /** + * Store the geometry as a void pointer instead of a #GeometryComponent to allow referencing data + * that doesn't correspond directly to a geometry component type, in this case #CurvesGeometry + * instead of #Curves. + */ + const void *geometry_; + const GeometryComponentType type_; const eAttrDomain domain_; + friend GeometryFieldInput; + public: - GeometryComponentFieldContext(const GeometryComponent &component, const eAttrDomain domain) - : component_(component), domain_(domain) + GeometryFieldContext(const GeometryComponent &component, eAttrDomain domain); + GeometryFieldContext(const void *geometry, GeometryComponentType type, eAttrDomain domain); + + const void *geometry() const { + return geometry_; } - const GeometryComponent &geometry_component() const + GeometryComponentType type() const { - return component_; + return type_; } eAttrDomain domain() const { return domain_; } + + std::optional<AttributeAccessor> attributes() const; + const Mesh *mesh() const; + const CurvesGeometry *curves() const; + const PointCloud *pointcloud() const; + const InstancesComponent *instances() const; + + private: + GeometryFieldContext(const Mesh &mesh, eAttrDomain domain); + GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain); + GeometryFieldContext(const PointCloud &points); + GeometryFieldContext(const InstancesComponent &instances); }; class GeometryFieldInput : public fn::FieldInput { public: using fn::FieldInput::FieldInput; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; + virtual GVArray get_varray_for_context(const GeometryFieldContext &context, + IndexMask mask) const = 0; +}; +class MeshFieldInput : public fn::FieldInput { + public: + using fn::FieldInput::FieldInput; GVArray get_varray_for_context(const fn::FieldContext &context, IndexMask mask, ResourceScope &scope) const override; + virtual GVArray get_varray_for_context(const Mesh &mesh, + eAttrDomain domain, + IndexMask mask) const = 0; +}; - virtual GVArray get_varray_for_context(const GeometryComponent &component, +class CurvesFieldInput : public fn::FieldInput { + public: + using fn::FieldInput::FieldInput; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; + virtual GVArray get_varray_for_context(const CurvesGeometry &curves, eAttrDomain domain, IndexMask mask) const = 0; }; +class PointCloudFieldInput : public fn::FieldInput { + public: + using fn::FieldInput::FieldInput; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; + virtual GVArray get_varray_for_context(const PointCloud &pointcloud, IndexMask mask) const = 0; +}; + +class InstancesFieldInput : public fn::FieldInput { + public: + using fn::FieldInput::FieldInput; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; + virtual GVArray get_varray_for_context(const InstancesComponent &instances, + IndexMask mask) const = 0; +}; + class AttributeFieldInput : public GeometryFieldInput { private: std::string name_; @@ -72,8 +211,7 @@ class AttributeFieldInput : public GeometryFieldInput { return name_; } - GVArray get_varray_for_context(const GeometryComponent &component, - eAttrDomain domain, + GVArray get_varray_for_context(const GeometryFieldContext &context, IndexMask mask) const override; std::string socket_inspection_name() const override; @@ -89,8 +227,7 @@ class IDAttributeFieldInput : public GeometryFieldInput { category_ = Category::Generated; } - GVArray get_varray_for_context(const GeometryComponent &component, - eAttrDomain domain, + GVArray get_varray_for_context(const GeometryFieldContext &context, IndexMask mask) const override; std::string socket_inspection_name() const override; @@ -99,12 +236,9 @@ class IDAttributeFieldInput : public GeometryFieldInput { bool is_equal_to(const fn::FieldNode &other) const override; }; -VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain); +VArray<float3> curve_normals_varray(const CurvesGeometry &curves, const eAttrDomain domain); -VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, - const Mesh &mesh, - const IndexMask mask, - eAttrDomain domain); +VArray<float3> mesh_normals_varray(const Mesh &mesh, const IndexMask mask, eAttrDomain domain); class NormalFieldInput : public GeometryFieldInput { public: @@ -113,8 +247,7 @@ class NormalFieldInput : public GeometryFieldInput { category_ = Category::Generated; } - GVArray get_varray_for_context(const GeometryComponent &component, - const eAttrDomain domain, + GVArray get_varray_for_context(const GeometryFieldContext &context, IndexMask mask) const override; std::string socket_inspection_name() const override; @@ -152,8 +285,7 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput { return fn::Field<T>{field_input}; } - GVArray get_varray_for_context(const GeometryComponent &component, - eAttrDomain domain, + GVArray get_varray_for_context(const GeometryFieldContext &context, IndexMask mask) const override; std::string socket_inspection_name() const override; @@ -162,10 +294,10 @@ class AnonymousAttributeFieldInput : public GeometryFieldInput { bool is_equal_to(const fn::FieldNode &other) const override; }; -class CurveLengthFieldInput final : public GeometryFieldInput { +class CurveLengthFieldInput final : public CurvesFieldInput { public: CurveLengthFieldInput(); - GVArray get_varray_for_context(const GeometryComponent &component, + GVArray get_varray_for_context(const CurvesGeometry &curves, eAttrDomain domain, IndexMask mask) const final; uint64_t hash() const override; diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index be2ec3e3dca..a5c4d5e1365 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -505,7 +505,7 @@ class CurveComponentLegacy : public GeometryComponent { /** * A geometry component that stores a group of curves, corresponding the #Curves data-block type - * and the #CurvesGeometry type. Attributes are are stored on the control point domain and the + * and the #CurvesGeometry type. Attributes are stored on the control point domain and the * curve domain. */ class CurveComponent : public GeometryComponent { diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index ad3b1971ca9..39ef738c631 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -488,7 +488,8 @@ struct bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *r const struct bGPDlayer *gpl, struct bGPDstroke *gps, int subdivisions, - const float diff_mat[4][4]); + const float diff_mat[4][4], + const float thickness_chg); /** * Get average pressure. */ diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h index 404ce63a5df..c14da538e7c 100644 --- a/source/blender/blenkernel/BKE_idprop.h +++ b/source/blender/blenkernel/BKE_idprop.h @@ -7,6 +7,7 @@ */ #include "BLI_compiler_attrs.h" +#include "BLI_sys_types.h" #ifdef __cplusplus extern "C" { diff --git a/source/blender/blenkernel/BKE_idprop.hh b/source/blender/blenkernel/BKE_idprop.hh index 1e741cc252f..6a42ab1669f 100644 --- a/source/blender/blenkernel/BKE_idprop.hh +++ b/source/blender/blenkernel/BKE_idprop.hh @@ -45,6 +45,9 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, d std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, const StringRefNull value); +/** \brief Allocate a new IDProperty of type IDP_ID, set its name and value. */ +std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, ID *id); + /** * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_INT. * diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 2db8f75770a..eb43ce823ac 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -366,14 +366,7 @@ bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile); void BKE_image_reassign_tile(struct Image *ima, struct ImageTile *tile, int new_tile_number); void BKE_image_sort_tiles(struct Image *ima); -bool BKE_image_fill_tile(struct Image *ima, - struct ImageTile *tile, - int width, - int height, - const float color[4], - int gen_type, - int planes, - bool is_float); +bool BKE_image_fill_tile(struct Image *ima, struct ImageTile *tile); typedef enum { UDIM_TILE_FORMAT_NONE = 0, @@ -425,13 +418,13 @@ int BKE_image_get_tile_from_pos(struct Image *ima, void BKE_image_get_tile_uv(const struct Image *ima, const int tile_number, float r_uv[2]); /** - * Return the tile_number for the closest UDIM tile. + * Return the tile_number for the closest UDIM tile to `co`. */ int BKE_image_find_nearest_tile_with_offset(const struct Image *image, const float co[2], - float r_uv_offset[2]) ATTR_NONNULL(1, 2, 3); + float r_uv_offset[2]) ATTR_NONNULL(2, 3); int BKE_image_find_nearest_tile(const struct Image *image, const float co[2]) - ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT; + ATTR_NONNULL(2) ATTR_WARN_UNUSED_RESULT; void BKE_image_get_size(struct Image *image, struct ImageUser *iuser, int *r_width, int *r_height); void BKE_image_get_size_fl(struct Image *image, struct ImageUser *iuser, float r_size[2]); diff --git a/source/blender/blenkernel/BKE_image_format.h b/source/blender/blenkernel/BKE_image_format.h index 6a03d1d8df5..8f71e1f4648 100644 --- a/source/blender/blenkernel/BKE_image_format.h +++ b/source/blender/blenkernel/BKE_image_format.h @@ -69,7 +69,7 @@ char BKE_imtype_valid_depths(char imtype); * String is from command line `--render-format` argument, * keep in sync with `creator_args.c` help info. */ -char BKE_imtype_from_arg(const char *arg); +char BKE_imtype_from_arg(const char *imtype_arg); /* Conversion between ImBuf settings. */ diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 37b30d63722..9f506ded8e9 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -47,7 +47,7 @@ void key_curve_normal_weights(float t, float data[4], int type); /** * Returns key coordinates (+ tilt) when key applied, NULL otherwise. * - * \param obdata if given, also update that geometry with the result of the shape keys evaluation. + * \param obdata: if given, also update that geometry with the result of the shape keys evaluation. */ float *BKE_key_evaluate_object_ex( struct Object *ob, int *r_totelem, float *arr, size_t arr_size, struct ID *obdata); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 9fa59c9e81b..aa4b1c69d24 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -27,7 +27,6 @@ void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object * struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); -bool object_deform_mball(struct Object *ob, struct ListBase *dispbase); void outside_lattice(struct Lattice *lt); float (*BKE_lattice_vert_coords_alloc(const struct Lattice *lt, int *r_vert_len))[3]; diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 9a6c3cf2b5f..3d064c7dea7 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -10,6 +10,7 @@ #include "DNA_layer_types.h" #include "DNA_listBase.h" +#include "DNA_object_enums.h" #ifdef __cplusplus extern "C" { @@ -353,13 +354,13 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); #define FOREACH_BASE_IN_MODE_BEGIN(_view_layer, _v3d, _object_type, _object_mode, _instance) \ { \ - struct ObjectsInModeIteratorData data_ = { \ - .object_mode = _object_mode, \ - .object_type = _object_type, \ - .view_layer = _view_layer, \ - .v3d = _v3d, \ - .base_active = _view_layer->basact, \ - }; \ + struct ObjectsInModeIteratorData data_; \ + memset(&data_, 0, sizeof(data_)); \ + data_.object_mode = _object_mode; \ + data_.object_type = _object_type; \ + data_.view_layer = _view_layer; \ + data_.v3d = _v3d; \ + data_.base_active = _view_layer->basact; \ ITER_BEGIN (BKE_view_layer_bases_in_mode_iterator_begin, \ BKE_view_layer_bases_in_mode_iterator_next, \ BKE_view_layer_bases_in_mode_iterator_end, \ @@ -520,46 +521,28 @@ struct Object **BKE_view_layer_array_from_objects_in_mode_params( uint *len, const struct ObjectsInModeParams *params); -#define BKE_view_layer_array_from_objects_in_mode(view_layer, v3d, r_len, ...) \ - BKE_view_layer_array_from_objects_in_mode_params( \ - view_layer, v3d, r_len, &(const struct ObjectsInModeParams)__VA_ARGS__) - -#define BKE_view_layer_array_from_bases_in_mode(view_layer, v3d, r_len, ...) \ - BKE_view_layer_array_from_bases_in_mode_params( \ - view_layer, v3d, r_len, &(const struct ObjectsInModeParams)__VA_ARGS__) - bool BKE_view_layer_filter_edit_mesh_has_uvs(const struct Object *ob, void *user_data); bool BKE_view_layer_filter_edit_mesh_has_edges(const struct Object *ob, void *user_data); -/* Utility macros that wrap common args (add more as needed). */ - -#define BKE_view_layer_array_from_objects_in_edit_mode(view_layer, v3d, r_len) \ - BKE_view_layer_array_from_objects_in_mode(view_layer, v3d, r_len, {.object_mode = OB_MODE_EDIT}) - -#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len) \ - BKE_view_layer_array_from_bases_in_mode(view_layer, v3d, r_len, {.object_mode = OB_MODE_EDIT}) - -#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len) \ - BKE_view_layer_array_from_objects_in_mode( \ - view_layer, v3d, r_len, {.object_mode = OB_MODE_EDIT, .no_dup_data = true}) - -#define BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, v3d, r_len) \ - BKE_view_layer_array_from_bases_in_mode( \ - view_layer, v3d, r_len, {.object_mode = OB_MODE_EDIT, .no_dup_data = true}) - -#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( \ - view_layer, v3d, r_len) \ - BKE_view_layer_array_from_objects_in_mode( \ - view_layer, \ - v3d, \ - r_len, \ - {.object_mode = OB_MODE_EDIT, \ - .no_dup_data = true, \ - .filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs}) - -#define BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, v3d, r_len, mode) \ - BKE_view_layer_array_from_objects_in_mode( \ - view_layer, v3d, r_len, {.object_mode = mode, .no_dup_data = true}) +/* Utility functions that wrap common arguments (add more as needed). */ + +struct Object **BKE_view_layer_array_from_objects_in_edit_mode(struct ViewLayer *view_layer, + const struct View3D *v3d, + uint *r_len); +struct Base **BKE_view_layer_array_from_bases_in_edit_mode(struct ViewLayer *view_layer, + const struct View3D *v3d, + uint *r_len); +struct Object **BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + struct ViewLayer *view_layer, const struct View3D *v3d, uint *r_len); + +struct Base **BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + struct ViewLayer *view_layer, const struct View3D *v3d, uint *r_len); +struct Object **BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + struct ViewLayer *view_layer, const struct View3D *v3d, uint *r_len); +struct Object **BKE_view_layer_array_from_objects_in_mode_unique_data(struct ViewLayer *view_layer, + const struct View3D *v3d, + uint *r_len, + eObjectMode mode); struct ViewLayerAOV *BKE_view_layer_add_aov(struct ViewLayer *view_layer); void BKE_view_layer_remove_aov(struct ViewLayer *view_layer, struct ViewLayerAOV *aov); diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 94497d9a487..febdad2ca0d 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -444,9 +444,9 @@ struct ID *BKE_id_copy(struct Main *bmain, const struct ID *id); * Currently, it only handles the given ID, and their shape keys and actions if any, according to * the given `duplicate_flags`. * - * \param duplicate_flags is of type #eDupli_ID_Flags, see #UserDef.dupflag. Currently only + * \param duplicate_flags: is of type #eDupli_ID_Flags, see #UserDef.dupflag. Currently only * `USER_DUP_LINKED_ID` and `USER_DUP_ACT` have an effect here. - * \param copy_flags flags passed to #BKE_id_copy_ex. + * \param copy_flags: flags passed to #BKE_id_copy_ex. */ struct ID *BKE_id_copy_for_duplicate(struct Main *bmain, struct ID *id, @@ -454,6 +454,13 @@ struct ID *BKE_id_copy_for_duplicate(struct Main *bmain, int copy_flags); /** + * Special version of #BKE_id_copy which is safe from using evaluated id as source with a copy + * result appearing in the main database. + * Takes care of the referenced data-blocks consistency. + */ +struct ID *BKE_id_copy_for_use_in_bmain(struct Main *bmain, const struct ID *id); + +/** * Does a mere memory swap over the whole IDs data (including type-specific memory). * \note Most internal ID data itself is not swapped (only IDProperties are). * diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index a23d010b51f..7d265ceb102 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -55,18 +55,9 @@ bool BKE_mball_is_basis(const struct Object *ob); struct Object *BKE_mball_basis_find(struct Scene *scene, struct Object *ob); /** - * Compute bounding box of all meta-elements / meta-ball. - * - * Bounding box is computed from polygonized surface. \a ob is - * basic meta-balls (with name `Meta` for example). All other meta-ball objects - * (with names `Meta.001`, `Meta.002`, etc) are included in this bounding-box. - */ -void BKE_mball_texspace_calc(struct Object *ob); -/** * Return or compute bounding-box for given meta-ball object. */ struct BoundBox *BKE_mball_boundbox_get(struct Object *ob); -float *BKE_mball_make_orco(struct Object *ob, struct ListBase *dispbase); /** * Copy some properties from a meta-ball obdata to all other meta-ball obdata belonging to the same @@ -110,18 +101,7 @@ bool BKE_mball_select_swap_multi_ex(struct Base **bases, int bases_len); /* **** Depsgraph evaluation **** */ -struct Depsgraph; - -/* Draw Cache */ - -enum { - BKE_MBALL_BATCH_DIRTY_ALL = 0, -}; -void BKE_mball_batch_cache_dirty_tag(struct MetaBall *mb, int mode); -void BKE_mball_batch_cache_free(struct MetaBall *mb); - -extern void (*BKE_mball_batch_cache_dirty_tag_cb)(struct MetaBall *mb, int mode); -extern void (*BKE_mball_batch_cache_free_cb)(struct MetaBall *mb); +void BKE_mball_data_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_mball_tessellate.h b/source/blender/blenkernel/BKE_mball_tessellate.h index 2dc16dc64d6..0840c51bb4d 100644 --- a/source/blender/blenkernel/BKE_mball_tessellate.h +++ b/source/blender/blenkernel/BKE_mball_tessellate.h @@ -12,11 +12,11 @@ extern "C" { struct Depsgraph; struct Object; struct Scene; +struct Mesh; -void BKE_mball_polygonize(struct Depsgraph *depsgraph, - struct Scene *scene, - struct Object *ob, - struct ListBase *dispbase); +struct Mesh *BKE_mball_polygonize(struct Depsgraph *depsgraph, + struct Scene *scene, + struct Object *ob); void BKE_mball_cubeTable_free(void); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 17f541b362e..ec6799ee995 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -6,6 +6,9 @@ * \ingroup bke */ +#include "DNA_mesh_types.h" + +#include "BKE_customdata.h" #include "BKE_mesh_types.h" #include "BLI_compiler_attrs.h" #include "BLI_utildefines.h" @@ -193,7 +196,6 @@ void BKE_mesh_orco_ensure(struct Object *ob, struct Mesh *mesh); struct Mesh *BKE_mesh_from_object(struct Object *ob); void BKE_mesh_assign_object(struct Main *bmain, struct Object *ob, struct Mesh *me); -void BKE_mesh_from_metaball(struct ListBase *lb, struct Mesh *me); void BKE_mesh_to_curve_nurblist(const struct Mesh *me, struct ListBase *nurblist, int edge_users_test); @@ -853,7 +855,7 @@ struct Mesh *BKE_mesh_merge_verts(struct Mesh *mesh, int merge_mode); /** - * Account for custom-data such as UV's becoming detached because of of imprecision + * Account for custom-data such as UV's becoming detached because of imprecision * in custom-data interpolation. * Without running this operation subdivision surface can cause UV's to be disconnected, * see: T81065. @@ -865,19 +867,7 @@ void BKE_mesh_merge_customdata_for_apply_modifier(struct Mesh *me); /** * Update the hide flag for edges and faces from the corresponding flag in verts. */ -void BKE_mesh_flush_hidden_from_verts_ex(const struct MVert *mvert, - const struct MLoop *mloop, - struct MEdge *medge, - int totedge, - struct MPoly *mpoly, - int totpoly); void BKE_mesh_flush_hidden_from_verts(struct Mesh *me); -void BKE_mesh_flush_hidden_from_polys_ex(struct MVert *mvert, - const struct MLoop *mloop, - struct MEdge *medge, - int totedge, - const struct MPoly *mpoly, - int totpoly); void BKE_mesh_flush_hidden_from_polys(struct Mesh *me); /** * simple poly -> vert/edge selection. @@ -1032,6 +1022,30 @@ char *BKE_mesh_debug_info(const struct Mesh *me) void BKE_mesh_debug_print(const struct Mesh *me) ATTR_NONNULL(1); #endif +/** + * \return The material index for each polygon. May be null. + * \note In C++ code, prefer using the attribute API (#MutableAttributeAccessor)/ + */ +BLI_INLINE const int *BKE_mesh_material_indices(const Mesh *mesh) +{ + return (const int *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_INT32, "material_index"); +} + +/** + * \return The material index for each polygon. Create the layer if it doesn't exist. + * \note In C++ code, prefer using the attribute API (#MutableAttributeAccessor)/ + */ +BLI_INLINE int *BKE_mesh_material_indices_for_write(Mesh *mesh) +{ + int *indices = (int *)CustomData_duplicate_referenced_layer_named( + &mesh->pdata, CD_PROP_INT32, "material_index", mesh->totpoly); + if (indices) { + return indices; + } + return (int *)CustomData_add_layer_named( + &mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totpoly, "material_index"); +} + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_mesh_legacy_convert.h b/source/blender/blenkernel/BKE_mesh_legacy_convert.h index 909fd0e0dea..11ee86c62a7 100644 --- a/source/blender/blenkernel/BKE_mesh_legacy_convert.h +++ b/source/blender/blenkernel/BKE_mesh_legacy_convert.h @@ -18,6 +18,26 @@ struct Mesh; struct MFace; /** + * Convert the hidden element attributes to the old flag format for writing. + */ +void BKE_mesh_legacy_convert_hide_layers_to_flags(struct Mesh *mesh); +/** + * Convert the old hide flags (#ME_HIDE) to the hidden element attribute for reading. + * Only add the attributes when there are any elements in each domain hidden. + */ +void BKE_mesh_legacy_convert_flags_to_hide_layers(struct Mesh *mesh); + +/** + * Move material indices from a generic attribute to #MPoly. + */ +void BKE_mesh_legacy_convert_material_indices_to_mpoly(struct Mesh *mesh); +/** + * Move material indices from the #MPoly struct to a generic attributes. + * Only add the attribute when the indices are not all zero. + */ +void BKE_mesh_legacy_convert_mpoly_to_material_indices(struct Mesh *mesh); + +/** * Recreate #MFace Tessellation. * * \note This doesn't use multi-threading like #BKE_mesh_recalc_looptri since diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index c58bcbea242..abe590b6806 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -17,11 +17,10 @@ struct MLoopUV; struct MPoly; struct MVert; -/* map from uv vertex to face (for select linked, stitch, uv suburf) */ - /* UvVertMap */ #define STD_UV_CONNECT_LIMIT 0.0001f +/* Map from uv vertex to face. Used by select linked, uv subdivision-surface and obj exporter. */ typedef struct UvVertMap { struct UvMapVert **vert; struct UvMapVert *buf; @@ -52,21 +51,37 @@ typedef struct UvElement { unsigned int island; } UvElement; -/* UvElementMap is a container for UvElements of a mesh. It stores some UvElements belonging to the - * same uv island in sequence and the number of uvs per island so it is possible to access all uvs - * belonging to an island directly by iterating through the buffer. +/** UvElementMap is a container for UvElements of a BMesh. + * + * It simplifies access to UV information and ensures the + * different UV selection modes are respected. + * + * If islands are calculated, it also stores UvElements + * belonging to the same uv island in sequence and + * the number of uvs per island. */ typedef struct UvElementMap { - /* address UvElements by their vertex */ - struct UvElement **vert; - /* UvElement Store */ - struct UvElement *buf; - /* Total number of UVs in the layer. Useful to know */ - int totalUVs; - /* Number of Islands in the mesh */ - int totalIslands; - /* Stores the starting index in buf where each island begins */ - int *islandIndices; + /** UvElement Storage. */ + struct UvElement *storage; + /** Total number of UVs. */ + int total_uvs; + /** Total number of unique UVs. */ + int total_unique_uvs; + + /** If Non-NULL, address UvElements by `BM_elem_index_get(BMVert*)`. */ + struct UvElement **vertex; + + /** If Non-NULL, pointer to local head of each unique UV. */ + struct UvElement **head_table; + + /** Number of islands, or zero if not calculated. */ + int total_islands; + /** Array of starting index in #storage where each island begins. */ + int *island_indices; + /** Array of number of UVs in each island. */ + int *island_total_uvs; + /** Array of number of unique UVs in each island. */ + int *island_total_unique_uvs; } UvElementMap; /* Connectivity data */ @@ -77,6 +92,7 @@ typedef struct MeshElemMap { /* mapping */ UvVertMap *BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly, + const bool *hide_poly, const struct MLoop *mloop, const struct MLoopUV *mloopuv, unsigned int totpoly, diff --git a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h index dff17bd6575..d9f5a75ca61 100644 --- a/source/blender/blenkernel/BKE_mesh_remesh_voxel.h +++ b/source/blender/blenkernel/BKE_mesh_remesh_voxel.h @@ -28,9 +28,9 @@ struct Mesh *BKE_mesh_remesh_quadriflow(const struct Mesh *mesh, void *update_cb_data); /* Data reprojection functions */ -void BKE_mesh_remesh_reproject_paint_mask(struct Mesh *target, struct Mesh *source); +void BKE_mesh_remesh_reproject_paint_mask(struct Mesh *target, const struct Mesh *source); void BKE_remesh_reproject_vertex_paint(struct Mesh *target, const struct Mesh *source); -void BKE_remesh_reproject_sculpt_face_sets(struct Mesh *target, struct Mesh *source); +void BKE_remesh_reproject_sculpt_face_sets(struct Mesh *target, const struct Mesh *source); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_mesh_sample.hh b/source/blender/blenkernel/BKE_mesh_sample.hh index 0b7d1a1835f..fb01083f334 100644 --- a/source/blender/blenkernel/BKE_mesh_sample.hh +++ b/source/blender/blenkernel/BKE_mesh_sample.hh @@ -13,7 +13,6 @@ #include "DNA_meshdata_types.h" #include "BKE_attribute.h" -#include "BKE_attribute.hh" struct Mesh; struct BVHTreeFromMesh; @@ -27,22 +26,22 @@ namespace blender::bke::mesh_surface_sample { void sample_point_attribute(const Mesh &mesh, Span<int> looptri_indices, Span<float3> bary_coords, - const GVArray &data_in, - const IndexMask mask, - GMutableSpan data_out); + const GVArray &src, + IndexMask mask, + GMutableSpan dst); void sample_corner_attribute(const Mesh &mesh, Span<int> looptri_indices, Span<float3> bary_coords, - const GVArray &data_in, - const IndexMask mask, - GMutableSpan data_out); + const GVArray &src, + IndexMask mask, + GMutableSpan dst); void sample_face_attribute(const Mesh &mesh, Span<int> looptri_indices, - const GVArray &data_in, - const IndexMask mask, - GMutableSpan data_out); + const GVArray &src, + IndexMask mask, + GMutableSpan dst); enum class eAttributeMapMode { INTERPOLATED, @@ -57,7 +56,6 @@ enum class eAttributeMapMode { * these are computed lazily when needed and re-used. */ class MeshAttributeInterpolator { - private: const Mesh *mesh_; const IndexMask mask_; const Span<float3> positions_; @@ -68,18 +66,14 @@ class MeshAttributeInterpolator { public: MeshAttributeInterpolator(const Mesh *mesh, - const IndexMask mask, - const Span<float3> positions, - const Span<int> looptri_indices); + IndexMask mask, + Span<float3> positions, + Span<int> looptri_indices); void sample_data(const GVArray &src, eAttrDomain domain, eAttributeMapMode mode, - const GMutableSpan dst); - - void sample_attribute(const GAttributeReader &src_attribute, - GSpanAttributeWriter &dst_attribute, - eAttributeMapMode mode); + GMutableSpan dst); protected: Span<float3> ensure_barycentric_coords(); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 90dbec7ec52..1118552b643 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -101,6 +101,7 @@ typedef struct bNodeSocketTemplate { namespace blender { class CPPType; namespace nodes { +class DNode; class NodeMultiFunctionBuilder; class GeoNodeExecParams; class NodeDeclarationBuilder; @@ -109,6 +110,11 @@ class GatherLinkSearchOpParams; namespace fn { class MFDataType; } // namespace fn +namespace realtime_compositor { +class Context; +class NodeOperation; +class ShaderNode; +} // namespace realtime_compositor } // namespace blender using CPPTypeHandle = blender::CPPType; @@ -123,7 +129,14 @@ using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket using NodeGatherSocketLinkOperationsFunction = void (*)(blender::nodes::GatherLinkSearchOpParams ¶ms); +using NodeGetCompositorOperationFunction = blender::realtime_compositor::NodeOperation + *(*)(blender::realtime_compositor::Context &context, blender::nodes::DNode node); +using NodeGetCompositorShaderNodeFunction = + blender::realtime_compositor::ShaderNode *(*)(blender::nodes::DNode node); + #else +typedef void *NodeGetCompositorOperationFunction; +typedef void *NodeGetCompositorShaderNodeFunction; typedef void *NodeMultiFunctionBuildFunction; typedef void *NodeGeometryExecFunction; typedef void *NodeDeclareFunction; @@ -309,6 +322,14 @@ typedef struct bNodeType { /* gpu */ NodeGPUExecFunction gpu_fn; + /* Get an instance of this node's compositor operation. Freeing the instance is the + * responsibility of the caller. */ + NodeGetCompositorOperationFunction get_compositor_operation; + + /* Get an instance of this node's compositor shader node. Freeing the instance is the + * responsibility of the caller. */ + NodeGetCompositorShaderNodeFunction get_compositor_shader_node; + /* Build a multi-function for this node. */ NodeMultiFunctionBuildFunction build_multi_function; @@ -374,6 +395,9 @@ typedef struct bNodeTreeType { int type; /* type identifier */ char idname[64]; /* identifier name */ + /* The ID name of group nodes for this type. */ + char group_idname[64]; + char ui_name[64]; char ui_description[256]; int ui_icon; @@ -1078,7 +1102,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i //#define SH_NODE_MATERIAL 100 #define SH_NODE_RGB 101 #define SH_NODE_VALUE 102 -#define SH_NODE_MIX_RGB 103 +#define SH_NODE_MIX_RGB_LEGACY 103 #define SH_NODE_VALTORGB 104 #define SH_NODE_RGBTOBW 105 #define SH_NODE_SHADERTORGB 106 @@ -1181,6 +1205,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define SH_NODE_POINT_INFO 710 #define SH_NODE_COMBINE_COLOR 711 #define SH_NODE_SEPARATE_COLOR 712 +#define SH_NODE_MIX 713 /** \} */ @@ -1302,16 +1327,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, i #define CMP_CHAN_RGB 1 #define CMP_CHAN_A 2 -/* filter types */ -#define CMP_FILT_SOFT 0 -#define CMP_FILT_SHARP_BOX 1 -#define CMP_FILT_LAPLACE 2 -#define CMP_FILT_SOBEL 3 -#define CMP_FILT_PREWITT 4 -#define CMP_FILT_KIRSCH 5 -#define CMP_FILT_SHADOW 6 -#define CMP_FILT_SHARP_DIAMOND 7 - /* scale node type, in custom1 */ #define CMP_SCALE_RELATIVE 0 #define CMP_SCALE_ABSOLUTE 1 diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh index f5fb53f962b..4c13f73848c 100644 --- a/source/blender/blenkernel/BKE_node_runtime.hh +++ b/source/blender/blenkernel/BKE_node_runtime.hh @@ -3,9 +3,20 @@ #pragma once #include <memory> +#include <mutex> -#include "BLI_sys_types.h" +#include "BLI_multi_value_map.hh" #include "BLI_utility_mixins.hh" +#include "BLI_vector.hh" + +#include "DNA_node_types.h" + +#include "BKE_node.h" + +struct bNode; +struct bNodeSocket; +struct bNodeTree; +struct bNodeType; namespace blender::nodes { struct FieldInferencingInterface; @@ -36,6 +47,32 @@ class bNodeTreeRuntime : NonCopyable, NonMovable { /** Information about how inputs and outputs of the node group interact with fields. */ std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface; + + /** + * Protects access to all topology cache variables below. This is necessary so that the cache can + * be updated on a const #bNodeTree. + */ + std::mutex topology_cache_mutex; + bool topology_cache_is_dirty = true; + bool topology_cache_exists = false; + /** + * Under some circumstances, it can be useful to use the cached data while editing the + * #bNodeTree. By default, this is protected against using an assert. + */ + mutable std::atomic<int> allow_use_dirty_topology_cache = 0; + + /** Only valid when #topology_cache_is_dirty is false. */ + Vector<bNode *> nodes; + Vector<bNodeLink *> links; + Vector<bNodeSocket *> sockets; + Vector<bNodeSocket *> input_sockets; + Vector<bNodeSocket *> output_sockets; + MultiValueMap<const bNodeType *, bNode *> nodes_by_type; + Vector<bNode *> toposort_left_to_right; + Vector<bNode *> toposort_right_to_left; + bool has_link_cycle = false; + bool has_undefined_nodes_or_sockets = false; + bNode *group_output_node = nullptr; }; /** @@ -47,12 +84,24 @@ class bNodeSocketRuntime : NonCopyable, NonMovable { public: /** * References a socket declaration that is owned by `node->declaration`. This is only runtime - * data. It has to be updated when the node declaration changes. + * data. It has to be updated when the node declaration changes. Access can be allowed by using + * #AllowUsingOutdatedInfo. */ const SocketDeclarationHandle *declaration = nullptr; /** #eNodeTreeChangedFlag. */ uint32_t changed_flag = 0; + + /** Only valid when #topology_cache_is_dirty is false. */ + Vector<bNodeLink *> directly_linked_links; + Vector<bNodeSocket *> directly_linked_sockets; + Vector<bNodeSocket *> logically_linked_sockets; + Vector<bNodeSocket *> logically_linked_skipped_sockets; + bNode *owner_node = nullptr; + bNodeSocket *internal_link_input = nullptr; + int index_in_node = -1; + int index_in_all_sockets = -1; + int index_in_inout_sockets = -1; }; /** @@ -84,6 +133,395 @@ class bNodeRuntime : NonCopyable, NonMovable { /** #eNodeTreeChangedFlag. */ uint32_t changed_flag = 0; + + /** Only valid if #topology_cache_is_dirty is false. */ + Vector<bNodeSocket *> inputs; + Vector<bNodeSocket *> outputs; + Vector<bNodeLink *> internal_links; + Map<StringRefNull, bNodeSocket *> inputs_by_identifier; + Map<StringRefNull, bNodeSocket *> outputs_by_identifier; + int index_in_tree = -1; + bool has_linked_inputs = false; + bool has_linked_outputs = false; + bNodeTree *owner_tree = nullptr; }; +namespace node_tree_runtime { + +class AllowUsingOutdatedInfo : NonCopyable, NonMovable { + private: + const bNodeTree &tree_; + + public: + AllowUsingOutdatedInfo(const bNodeTree &tree) : tree_(tree) + { + tree_.runtime->allow_use_dirty_topology_cache.fetch_add(1); + } + + ~AllowUsingOutdatedInfo() + { + tree_.runtime->allow_use_dirty_topology_cache.fetch_sub(1); + } +}; + +inline bool topology_cache_is_available(const bNodeTree &tree) +{ + if (!tree.runtime->topology_cache_exists) { + return false; + } + if (tree.runtime->allow_use_dirty_topology_cache.load() > 0) { + return true; + } + if (tree.runtime->topology_cache_is_dirty) { + return false; + } + return true; +} + +inline bool topology_cache_is_available(const bNode &node) +{ + const bNodeTree *ntree = node.runtime->owner_tree; + if (ntree == nullptr) { + return false; + } + return topology_cache_is_available(*ntree); +} + +inline bool topology_cache_is_available(const bNodeSocket &socket) +{ + const bNode *node = socket.runtime->owner_node; + if (node == nullptr) { + return false; + } + return topology_cache_is_available(*node); +} + +} // namespace node_tree_runtime + } // namespace blender::bke + +/* -------------------------------------------------------------------- */ +/** \name #bNodeTree Inline Methods + * \{ */ + +inline blender::Span<bNode *> bNodeTree::nodes_by_type(const blender::StringRefNull type_idname) +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str())); +} + +inline blender::Span<const bNode *> bNodeTree::nodes_by_type( + const blender::StringRefNull type_idname) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes_by_type.lookup(nodeTypeFind(type_idname.c_str())); +} + +inline blender::Span<const bNode *> bNodeTree::toposort_left_to_right() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->toposort_left_to_right; +} + +inline blender::Span<const bNode *> bNodeTree::toposort_right_to_left() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->toposort_right_to_left; +} + +inline blender::Span<const bNode *> bNodeTree::all_nodes() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes; +} + +inline blender::Span<bNode *> bNodeTree::all_nodes() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->nodes; +} + +inline bool bNodeTree::has_link_cycle() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->has_link_cycle; +} + +inline bool bNodeTree::has_undefined_nodes_or_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->has_undefined_nodes_or_sockets; +} + +inline const bNode *bNodeTree::group_output_node() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->group_output_node; +} + +inline blender::Span<const bNodeSocket *> bNodeTree::all_input_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->input_sockets; +} + +inline blender::Span<bNodeSocket *> bNodeTree::all_input_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->input_sockets; +} + +inline blender::Span<const bNodeSocket *> bNodeTree::all_output_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->output_sockets; +} + +inline blender::Span<bNodeSocket *> bNodeTree::all_output_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->output_sockets; +} + +inline blender::Span<const bNodeSocket *> bNodeTree::all_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->sockets; +} + +inline blender::Span<bNodeSocket *> bNodeTree::all_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->sockets; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNode Inline Methods + * \{ */ + +inline blender::Span<bNodeSocket *> bNode::input_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->inputs; +} + +inline blender::Span<bNodeSocket *> bNode::output_sockets() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->outputs; +} + +inline blender::Span<const bNodeSocket *> bNode::input_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->inputs; +} + +inline blender::Span<const bNodeSocket *> bNode::output_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->outputs; +} + +inline bNodeSocket &bNode::input_socket(int index) +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->inputs[index]; +} + +inline bNodeSocket &bNode::output_socket(int index) +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->outputs[index]; +} + +inline const bNodeSocket &bNode::input_socket(int index) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->inputs[index]; +} + +inline const bNodeSocket &bNode::output_socket(int index) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->outputs[index]; +} + +inline const bNodeSocket &bNode::input_by_identifier(blender::StringRef identifier) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->inputs_by_identifier.lookup_as(identifier); +} + +inline const bNodeSocket &bNode::output_by_identifier(blender::StringRef identifier) const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->outputs_by_identifier.lookup_as(identifier); +} + +inline blender::StringRefNull bNode::label_or_name() const +{ + if (this->label[0] == '\0') { + return this->name; + } + return this->label; +} + +inline bool bNode::is_muted() const +{ + return this->flag & NODE_MUTED; +} + +inline bool bNode::is_reroute() const +{ + return this->type == NODE_REROUTE; +} + +inline bool bNode::is_frame() const +{ + return this->type == NODE_FRAME; +} + +inline bool bNode::is_group() const +{ + return ELEM(this->type, NODE_GROUP, NODE_CUSTOM_GROUP); +} + +inline bool bNode::is_group_input() const +{ + return this->type == NODE_GROUP_INPUT; +} + +inline bool bNode::is_group_output() const +{ + return this->type == NODE_GROUP_OUTPUT; +} + +inline blender::Span<const bNodeLink *> bNode::internal_links_span() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->internal_links; +} + +inline const blender::nodes::NodeDeclaration *bNode::declaration() const +{ + BLI_assert(this->runtime->declaration != nullptr); + return this->runtime->declaration; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNodeLink Inline Methods + * \{ */ + +inline bool bNodeLink::is_muted() const +{ + return this->flag & NODE_LINK_MUTED; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #bNodeSocket Inline Methods + * \{ */ + +inline int bNodeSocket::index() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->index_in_node; +} + +inline int bNodeSocket::index_in_tree() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->index_in_all_sockets; +} + +inline bool bNodeSocket::is_available() const +{ + return (this->flag & SOCK_UNAVAIL) == 0; +} + +inline bNode &bNodeSocket::owner_node() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node; +} + +inline const bNodeTree &bNodeSocket::owner_tree() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node->runtime->owner_tree; +} + +inline blender::Span<const bNodeSocket *> bNodeSocket::logically_linked_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->logically_linked_sockets; +} + +inline blender::Span<const bNodeLink *> bNodeSocket::directly_linked_links() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_links; +} + +inline blender::Span<bNodeLink *> bNodeSocket::directly_linked_links() +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_links; +} + +inline blender::Span<const bNodeSocket *> bNodeSocket::directly_linked_sockets() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return this->runtime->directly_linked_sockets; +} + +inline bool bNodeSocket::is_directly_linked() const +{ + return !this->directly_linked_links().is_empty(); +} + +inline bool bNodeSocket::is_logically_linked() const +{ + return !this->logically_linked_sockets().is_empty(); +} + +inline const bNodeSocket *bNodeSocket::internal_link_input() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + BLI_assert(this->in_out == SOCK_OUT); + return this->runtime->internal_link_input; +} + +template<typename T> const T *bNodeSocket::default_value_typed() const +{ + return static_cast<const T *>(this->default_value); +} + +inline bool bNodeSocket::is_input() const +{ + return this->in_out == SOCK_IN; +} + +inline bool bNodeSocket::is_output() const +{ + return this->in_out == SOCK_OUT; +} + +inline bool bNodeSocket::is_multi_input() const +{ + return this->flag & SOCK_MULTI_INPUT; +} + +inline const bNode &bNodeSocket::owner_node() const +{ + BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this)); + return *this->runtime->owner_node; +} + +/** \} */ diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index f0eb16a819d..e0fb6c5e834 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -474,8 +474,8 @@ void BKE_object_handle_data_update(struct Depsgraph *depsgraph, */ void BKE_object_handle_update(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob); /** - * The main object update call, for object matrix, constraints, keys and #DispList (modifiers) - * requires flags to be set! + * The main object update call, for object matrix, constraints, keys and modifiers. + * Requires flags to be set! * * Ideally we shouldn't have to pass the rigid body world, * but need bigger restructuring to avoid id. @@ -586,7 +586,6 @@ void BKE_object_runtime_reset_on_copy(struct Object *object, int flag); void BKE_object_runtime_free_data(struct Object *object); void BKE_object_batch_cache_dirty_tag(struct Object *ob); -void BKE_object_data_batch_cache_dirty_tag(struct ID *object_data); /* this function returns a superset of the scenes selection based on relationships */ diff --git a/source/blender/blenkernel/BKE_outliner_treehash.h b/source/blender/blenkernel/BKE_outliner_treehash.h deleted file mode 100644 index 6f4d126fcbf..00000000000 --- a/source/blender/blenkernel/BKE_outliner_treehash.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#pragma once - -/** \file - * \ingroup bke - */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct BLI_mempool; -struct ID; -struct TreeStoreElem; - -/* create and fill hashtable with treestore elements */ -void *BKE_outliner_treehash_create_from_treestore(struct BLI_mempool *treestore); - -/* full rebuild for already allocated hashtable */ -void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, struct BLI_mempool *treestore); - -/* clear element usage flags */ -void BKE_outliner_treehash_clear_used(void *treehash); - -/* Add/remove hashtable elements */ -void BKE_outliner_treehash_add_element(void *treehash, struct TreeStoreElem *elem); -void BKE_outliner_treehash_remove_element(void *treehash, struct TreeStoreElem *elem); - -/* find first unused element with specific type, nr and id */ -struct TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, - short type, - short nr, - struct ID *id); - -/* find user or unused element with specific type, nr and id */ -struct TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, - short type, - short nr, - struct ID *id); - -/* free treehash structure */ -void BKE_outliner_treehash_free(void *treehash); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/blenkernel/BKE_outliner_treehash.hh b/source/blender/blenkernel/BKE_outliner_treehash.hh new file mode 100644 index 00000000000..7f1dad5fd68 --- /dev/null +++ b/source/blender/blenkernel/BKE_outliner_treehash.hh @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#pragma once + +/** \file + * \ingroup bke + * + * Hash table of tree-store elements (#TreeStoreElem) for fast lookups via a (id, type, index) + * tuple as key. + * + * The Outliner may have to perform many lookups for rebuilding complex trees, so this should be + * treated as performance sensitive. + */ + +#include <memory> + +#include "BLI_map.hh" + +struct BLI_mempool; +struct ID; +struct TreeStoreElem; + +namespace blender::bke::outliner::treehash { + +/* -------------------------------------------------------------------- */ + +class TreeStoreElemKey { + public: + ID *id = nullptr; + short type = 0; + short nr = 0; + + explicit TreeStoreElemKey(const TreeStoreElem &elem); + TreeStoreElemKey(ID *id, short type, short nr); + + uint64_t hash() const; + friend bool operator==(const TreeStoreElemKey &a, const TreeStoreElemKey &b); +}; + +/* -------------------------------------------------------------------- */ + +class TreeHash { + Map<TreeStoreElemKey, std::unique_ptr<class TseGroup>> elem_groups_; + + public: + ~TreeHash(); + + /** Create and fill hash-table with treestore elements */ + static std::unique_ptr<TreeHash> create_from_treestore(BLI_mempool &treestore); + + /** Full rebuild for already allocated hash-table. */ + void rebuild_from_treestore(BLI_mempool &treestore); + + /** Clear element usage flags. */ + void clear_used(); + + /** Add hash-table element. */ + void add_element(TreeStoreElem &elem); + /** Remove hash-table element. */ + void remove_element(TreeStoreElem &elem); + + /** Find first unused element with specific type, nr and id. */ + TreeStoreElem *lookup_unused(short type, short nr, ID *id) const; + + /** Find user or unused element with specific type, nr and id. */ + TreeStoreElem *lookup_any(short type, short nr, ID *id) const; + + private: + TreeHash() = default; + + TseGroup *lookup_group(const TreeStoreElemKey &key) const; + TseGroup *lookup_group(const TreeStoreElem &elem) const; + TseGroup *lookup_group(short type, short nr, ID *id) const; + void fill_treehash(BLI_mempool &treestore); +}; + +} // namespace blender::bke::outliner::treehash diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 162459d2005..92b1aacc300 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -13,6 +13,7 @@ #include "DNA_object_enums.h" #include "BKE_attribute.h" +#include "BKE_pbvh.h" #ifdef __cplusplus extern "C" { @@ -59,10 +60,10 @@ struct bContext; struct bToolRef; struct tPaletteColorHSV; -extern const char PAINT_CURSOR_SCULPT[3]; -extern const char PAINT_CURSOR_VERTEX_PAINT[3]; -extern const char PAINT_CURSOR_WEIGHT_PAINT[3]; -extern const char PAINT_CURSOR_TEXTURE_PAINT[3]; +extern const uchar PAINT_CURSOR_SCULPT[3]; +extern const uchar PAINT_CURSOR_VERTEX_PAINT[3]; +extern const uchar PAINT_CURSOR_WEIGHT_PAINT[3]; +extern const uchar PAINT_CURSOR_TEXTURE_PAINT[3]; typedef enum ePaintMode { PAINT_MODE_SCULPT = 0, @@ -97,6 +98,7 @@ typedef enum ePaintOverlayControlFlags { PAINT_OVERLAY_OVERRIDE_PRIMARY = (1 << 5), PAINT_OVERLAY_OVERRIDE_SECONDARY = (1 << 6), } ePaintOverlayControlFlags; +ENUM_OPERATORS(ePaintOverlayControlFlags, PAINT_OVERLAY_OVERRIDE_SECONDARY); #define PAINT_OVERRIDE_MASK \ (PAINT_OVERLAY_OVERRIDE_SECONDARY | PAINT_OVERLAY_OVERRIDE_PRIMARY | \ @@ -156,7 +158,7 @@ struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name); * Call when entering each respective paint mode. */ bool BKE_paint_ensure(struct ToolSettings *ts, struct Paint **r_paint); -void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const char col[3]); +void BKE_paint_init(struct Main *bmain, struct Scene *sce, ePaintMode mode, const uchar col[3]); void BKE_paint_free(struct Paint *p); /** * Called when copying scene settings, so even if 'src' and 'tar' are the same still do a @@ -212,7 +214,7 @@ bool BKE_paint_always_hide_test(struct Object *ob); * Returns non-zero if any of the face's vertices are hidden, zero otherwise. */ bool paint_is_face_hidden(const struct MLoopTri *lt, - const struct MVert *mvert, + const bool *hide_vert, const struct MLoop *mloop); /** * Returns non-zero if any of the corners of the grid @@ -397,7 +399,7 @@ typedef struct SculptVertexInfo { typedef struct SculptBoundaryEditInfo { /* Vertex index from where the topology propagation reached this vertex. */ - int original_vertex; + int original_vertex_i; /* How many steps were needed to reach this vertex from the boundary. */ int num_propagation_steps; @@ -408,13 +410,14 @@ typedef struct SculptBoundaryEditInfo { /* Edge for drawing the boundary preview in the cursor. */ typedef struct SculptBoundaryPreviewEdge { - int v1; - int v2; + PBVHVertRef v1; + PBVHVertRef v2; } SculptBoundaryPreviewEdge; typedef struct SculptBoundary { /* Vertex indices of the active boundary. */ - int *vertices; + PBVHVertRef *vertices; + int *vertices_i; int vertices_capacity; int num_vertices; @@ -432,12 +435,13 @@ typedef struct SculptBoundary { bool forms_loop; /* Initial vertex in the boundary which is closest to the current sculpt active vertex. */ - int initial_vertex; + PBVHVertRef initial_vertex; + int initial_vertex_i; /* Vertex that at max_propagation_steps from the boundary and closest to the original active * vertex that was used to initialize the boundary. This is used as a reference to check how much * the deformation will go into the mesh and to calculate the strength of the brushes. */ - int pivot_vertex; + PBVHVertRef pivot_vertex; /* Stores the initial positions of the pivot and boundary initial vertex as they may be deformed * during the brush action. This allows to use them as a reference positions and vectors for some @@ -565,7 +569,7 @@ typedef struct SculptSession { struct ExpandCache *expand_cache; /* Cursor data and active vertex for tools */ - int active_vertex_index; + PBVHVertRef active_vertex; int active_face_index; int active_grid_index; @@ -591,8 +595,8 @@ typedef struct SculptSession { struct Scene *scene; /* Dynamic mesh preview */ - int *preview_vert_index_list; - int preview_vert_index_count; + PBVHVertRef *preview_vert_list; + int preview_vert_count; /* Pose Brush Preview */ float pose_origin[3]; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 5641ff0ba34..8c9488b0b46 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -8,8 +8,11 @@ */ #include "BLI_bitmap.h" +#include "BLI_compiler_compat.h" #include "BLI_ghash.h" +#include "bmesh.h" + /* For embedding CCGKey in iterator. */ #include "BKE_attribute.h" #include "BKE_ccg.h" @@ -43,6 +46,41 @@ struct MeshElemMap; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; +typedef enum { + PBVH_FACES, + PBVH_GRIDS, + PBVH_BMESH, +} PBVHType; + +/* Public members of PBVH, used for inlined functions. */ +struct PBVHPublic { + PBVHType type; + BMesh *bm; +}; + +/* + * These structs represent logical verts/edges/faces. + * for PBVH_GRIDS and PBVH_FACES they store integer + * offsets, PBVH_BMESH stores pointers. + * + * The idea is to enforce stronger type checking by encapsulating + * intptr_t's in structs. + */ + +typedef struct PBVHVertRef { + intptr_t i; +} PBVHVertRef; + +typedef struct PBVHEdgeRef { + intptr_t i; +} PBVHEdgeRef; + +typedef struct PBVHFaceRef { + intptr_t i; +} PBVHFaceRef; + +#define PBVH_REF_NONE -1LL + typedef struct { float (*co)[3]; } PBVHProxyNode; @@ -87,9 +125,97 @@ typedef struct PBVHFrustumPlanes { int num_planes; } PBVHFrustumPlanes; +BLI_INLINE PBVHType BKE_pbvh_type(const PBVH *pbvh) +{ + return ((const struct PBVHPublic *)pbvh)->type; +} + +BLI_INLINE BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh) +{ + return ((struct PBVHPublic *)pbvh)->bm; +} + void BKE_pbvh_set_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes); void BKE_pbvh_get_frustum_planes(PBVH *pbvh, PBVHFrustumPlanes *planes); +BLI_INLINE PBVHVertRef BKE_pbvh_make_vref(intptr_t i) +{ + PBVHVertRef ret = {i}; + return ret; +} + +BLI_INLINE PBVHEdgeRef BKE_pbvh_make_eref(intptr_t i) +{ + PBVHEdgeRef ret = {i}; + return ret; +} + +BLI_INLINE PBVHFaceRef BKE_pbvh_make_fref(intptr_t i) +{ + PBVHFaceRef ret = {i}; + return ret; +} + +BLI_INLINE int BKE_pbvh_vertex_to_index(PBVH *pbvh, PBVHVertRef v) +{ + return (BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != PBVH_REF_NONE ? + BM_elem_index_get((BMVert *)(v.i)) : + (v.i)); +} + +BLI_INLINE PBVHVertRef BKE_pbvh_index_to_vertex(PBVH *pbvh, int index) +{ + switch (BKE_pbvh_type(pbvh)) { + case PBVH_FACES: + case PBVH_GRIDS: + return BKE_pbvh_make_vref(index); + case PBVH_BMESH: + return BKE_pbvh_make_vref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->vtable[index]); + } + + return BKE_pbvh_make_vref(PBVH_REF_NONE); +} + +BLI_INLINE int BKE_pbvh_edge_to_index(PBVH *pbvh, PBVHEdgeRef e) +{ + return (BKE_pbvh_type(pbvh) == PBVH_BMESH && e.i != PBVH_REF_NONE ? + BM_elem_index_get((BMEdge *)(e.i)) : + (e.i)); +} + +BLI_INLINE PBVHEdgeRef BKE_pbvh_index_to_edge(PBVH *pbvh, int index) +{ + switch (BKE_pbvh_type(pbvh)) { + case PBVH_FACES: + case PBVH_GRIDS: + return BKE_pbvh_make_eref(index); + case PBVH_BMESH: + return BKE_pbvh_make_eref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->etable[index]); + } + + return BKE_pbvh_make_eref(PBVH_REF_NONE); +} + +BLI_INLINE int BKE_pbvh_face_to_index(PBVH *pbvh, PBVHFaceRef f) +{ + return (BKE_pbvh_type(pbvh) == PBVH_BMESH && f.i != PBVH_REF_NONE ? + BM_elem_index_get((BMFace *)(f.i)) : + (f.i)); +} + +BLI_INLINE PBVHFaceRef BKE_pbvh_index_to_face(PBVH *pbvh, int index) +{ + switch (BKE_pbvh_type(pbvh)) { + case PBVH_FACES: + case PBVH_GRIDS: + return BKE_pbvh_make_fref(index); + case PBVH_BMESH: + return BKE_pbvh_make_fref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->ftable[index]); + } + + return BKE_pbvh_make_fref(PBVH_REF_NONE); +} + /* Callbacks */ /** @@ -181,7 +307,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *active_vertex_index, + PBVHVertRef *active_vertex, int *active_face_grid_index, float *face_normal); @@ -224,19 +350,16 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, void *user_data, bool full_render); -void BKE_pbvh_draw_debug_cb( - PBVH *pbvh, - void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag), - void *user_data); +void BKE_pbvh_draw_debug_cb(PBVH *pbvh, + void (*draw_fn)(PBVHNode *node, + void *user_data, + const float bmin[3], + const float bmax[3], + PBVHNodeFlags flag), + void *user_data); /* PBVH Access */ -typedef enum { - PBVH_FACES, - PBVH_GRIDS, - PBVH_BMESH, -} PBVHType; -PBVHType BKE_pbvh_type(const PBVH *pbvh); bool BKE_pbvh_has_faces(const PBVH *pbvh); /** @@ -272,7 +395,6 @@ int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh); /** * Only valid for type == #PBVH_BMESH. */ -struct BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh); void BKE_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size); typedef enum { @@ -308,7 +430,7 @@ void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked); bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node); void BKE_pbvh_mark_rebuild_pixels(PBVH *pbvh); -void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, int index); +void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, PBVHVertRef vertex); void BKE_pbvh_node_get_grids(PBVH *pbvh, PBVHNode *node, @@ -399,6 +521,7 @@ typedef struct PBVHVertexIter { int gy; int i; int index; + PBVHVertRef vertex; bool respect_hide; /* grid */ @@ -413,6 +536,7 @@ typedef struct PBVHVertexIter { /* mesh */ struct MVert *mverts; float (*vert_normals)[3]; + const bool *hide_vert; int totvert; const int *vert_indices; float *vmask; @@ -443,7 +567,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m if (vi.grids) { \ vi.width = vi.gridsize; \ vi.height = vi.gridsize; \ - vi.index = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \ + vi.index = vi.vertex.i = vi.grid_indices[vi.g] * vi.key.grid_area - 1; \ vi.grid = vi.grids[vi.grid_indices[vi.g]]; \ if (mode == PBVH_ITER_UNIQUE) { \ vi.gh = vi.grid_hidden[vi.grid_indices[vi.g]]; \ @@ -462,6 +586,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi.mask = vi.key.has_mask ? CCG_elem_mask(&vi.key, vi.grid) : NULL; \ vi.grid = CCG_elem_next(&vi.key, vi.grid); \ vi.index++; \ + vi.vertex.i++; \ vi.visible = true; \ if (vi.gh) { \ if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) { \ @@ -472,7 +597,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m else if (vi.mverts) { \ vi.mvert = &vi.mverts[vi.vert_indices[vi.gx]]; \ if (vi.respect_hide) { \ - vi.visible = !(vi.mvert->flag & ME_HIDE); \ + vi.visible = !(vi.hide_vert && vi.hide_vert[vi.vert_indices[vi.gx]]); \ if (mode == PBVH_ITER_UNIQUE && !vi.visible) { \ continue; \ } \ @@ -482,7 +607,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } \ vi.co = vi.mvert->co; \ vi.no = vi.vert_normals[vi.vert_indices[vi.gx]]; \ - vi.index = vi.vert_indices[vi.i]; \ + vi.index = vi.vertex.i = vi.vert_indices[vi.i]; \ if (vi.vmask) { \ vi.mask = &vi.vmask[vi.index]; \ } \ @@ -502,6 +627,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } \ vi.co = vi.bm_vert->co; \ vi.fno = vi.bm_vert->no; \ + vi.vertex = BKE_pbvh_make_vref((intptr_t)vi.bm_vert); \ vi.index = BM_elem_index_get(vi.bm_vert); \ vi.mask = (float *)BM_ELEM_CD_GET_VOID_P(vi.bm_vert, vi.cd_vert_mask_offset); \ } @@ -545,6 +671,8 @@ void BKE_pbvh_parallel_range_settings(struct TaskParallelSettings *settings, struct MVert *BKE_pbvh_get_verts(const PBVH *pbvh); const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3]; +const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh); +bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh); PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node); void BKE_pbvh_node_color_buffer_free(PBVH *pbvh); @@ -581,11 +709,12 @@ void BKE_pbvh_node_num_loops(PBVH *pbvh, PBVHNode *node, int *r_totloop); void BKE_pbvh_update_active_vcol(PBVH *pbvh, const struct Mesh *mesh); void BKE_pbvh_pmap_set(PBVH *pbvh, const struct MeshElemMap *pmap); -void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4]); -void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]); +void BKE_pbvh_vertex_color_set(PBVH *pbvh, PBVHVertRef vertex, const float color[4]); +void BKE_pbvh_vertex_color_get(const PBVH *pbvh, PBVHVertRef vertex, float r_color[4]); void BKE_pbvh_ensure_node_loops(PBVH *pbvh); bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh); +int BKE_pbvh_debug_draw_gen_get(PBVHNode *node); #ifdef __cplusplus } diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh index e73950e6299..ad8eca2b36f 100644 --- a/source/blender/blenkernel/BKE_pbvh_pixels.hh +++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh @@ -186,8 +186,14 @@ struct NodeData { { UDIMTilePixels *tile = find_tile_data(image_tile); if (tile && tile->flags.dirty) { - BKE_image_partial_update_mark_region( - &image, image_tile.image_tile, &image_buffer, &tile->dirty_region); + if (image_buffer.planes == 8) { + image_buffer.planes = 32; + BKE_image_partial_update_mark_full_update(&image); + } + else { + BKE_image_partial_update_mark_region( + &image, image_tile.image_tile, &image_buffer, &tile->dirty_region); + } tile->clear_dirty(); } } diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h index ee90fea6506..62a1824d844 100644 --- a/source/blender/blenkernel/BKE_pointcloud.h +++ b/source/blender/blenkernel/BKE_pointcloud.h @@ -33,8 +33,6 @@ bool BKE_pointcloud_customdata_required(const struct PointCloud *pointcloud, con /* Dependency Graph */ -struct PointCloud *BKE_pointcloud_new_for_eval(const struct PointCloud *pointcloud_src, - int totpoint); struct PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference); void BKE_pointcloud_data_update(struct Depsgraph *depsgraph, diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 3922bfb6c0d..3691ab677b7 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -55,7 +55,7 @@ struct wmWindowManager; typedef struct wmSpaceTypeListenerParams { struct wmWindow *window; struct ScrArea *area; - struct wmNotifier *notifier; + const struct wmNotifier *notifier; const struct Scene *scene; } wmSpaceTypeListenerParams; @@ -124,7 +124,7 @@ typedef struct wmRegionListenerParams { struct wmWindow *window; struct ScrArea *area; /* Can be NULL when the region is not part of an area. */ struct ARegion *region; - struct wmNotifier *notifier; + const struct wmNotifier *notifier; const struct Scene *scene; } wmRegionListenerParams; @@ -291,7 +291,7 @@ enum { /* Draw an item in the uiList */ typedef void (*uiListDrawItemFunc)(struct uiList *ui_list, - struct bContext *C, + const struct bContext *C, struct uiLayout *layout, struct PointerRNA *dataptr, struct PointerRNA *itemptr, @@ -303,12 +303,12 @@ typedef void (*uiListDrawItemFunc)(struct uiList *ui_list, /* Draw the filtering part of an uiList */ typedef void (*uiListDrawFilterFunc)(struct uiList *ui_list, - struct bContext *C, + const struct bContext *C, struct uiLayout *layout); /* Filter items of an uiList */ typedef void (*uiListFilterItemsFunc)(struct uiList *ui_list, - struct bContext *C, + const struct bContext *C, struct PointerRNA *, const char *propname); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 9965b6f1351..11c37a74a54 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -134,7 +134,7 @@ void *BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Sequence *s void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle); -void BKE_sound_mute_scene_sound(void *handle, char mute); +void BKE_sound_mute_scene_sound(void *handle, bool mute); void BKE_sound_move_scene_sound(const struct Scene *scene, void *handle, diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index 767018ae0bb..27542aa3586 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -360,7 +360,7 @@ class BezierSpline final : public Spline { * Returns non-owning access to an array of values containing the information necessary to * interpolate values from the original control points to evaluated points. The control point * index is the integer part of each value, and the factor used for interpolating to the next - * control point is the remaining factional part. + * control point is the remaining fractional part. */ blender::Span<float> evaluated_mappings() const; blender::Span<blender::float3> evaluated_positions() const final; diff --git a/source/blender/blenkernel/BKE_volume.h b/source/blender/blenkernel/BKE_volume.h index 4215cad5858..8549cd14b3c 100644 --- a/source/blender/blenkernel/BKE_volume.h +++ b/source/blender/blenkernel/BKE_volume.h @@ -135,7 +135,7 @@ struct VolumeGrid *BKE_volume_grid_add(struct Volume *volume, void BKE_volume_grid_remove(struct Volume *volume, struct VolumeGrid *grid); /** - * Openvdb crashes when the determinant of the transform matrix becomes too small. + * OpenVDB crashes when the determinant of the transform matrix becomes too small. */ bool BKE_volume_grid_determinant_valid(double determinant); diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index f76f7f5a968..61549a66e1f 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -25,7 +25,6 @@ set(INC ../simulation ../../../intern/eigen ../../../intern/ghost - ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/iksolver/extern ../../../intern/atomic @@ -144,6 +143,7 @@ set(SRC intern/geometry_component_mesh.cc intern/geometry_component_pointcloud.cc intern/geometry_component_volume.cc + intern/geometry_fields.cc intern/geometry_set.cc intern/geometry_set_instances.cc intern/gpencil.c @@ -191,7 +191,7 @@ set(SRC intern/mask_evaluate.c intern/mask_rasterize.c intern/material.c - intern/mball.c + intern/mball.cc intern/mball_tessellate.c intern/mesh.cc intern/mesh_boolean_convert.cc @@ -230,6 +230,7 @@ set(SRC intern/multires_versioning.c intern/nla.c intern/node.cc + intern/node_runtime.cc intern/node_tree_update.cc intern/object.cc intern/object_deform.c @@ -238,9 +239,9 @@ set(SRC intern/object_update.c intern/ocean.c intern/ocean_spectrum.c - intern/outliner_treehash.c + intern/outliner_treehash.cc intern/packedFile.c - intern/paint.c + intern/paint.cc intern/paint_canvas.cc intern/paint_toolslots.c intern/particle.c @@ -280,7 +281,7 @@ set(SRC intern/subdiv_displacement_multires.c intern/subdiv_eval.c intern/subdiv_foreach.c - intern/subdiv_mesh.c + intern/subdiv_mesh.cc intern/subdiv_modifier.c intern/subdiv_stats.c intern/subdiv_topology.c @@ -399,6 +400,7 @@ set(SRC BKE_image_format.h BKE_image_partial_update.hh BKE_image_save.h + BKE_image_wrappers.hh BKE_ipo.h BKE_kelvinlet.h BKE_key.h @@ -445,11 +447,12 @@ set(SRC BKE_object_deform.h BKE_object_facemap.h BKE_ocean.h - BKE_outliner_treehash.h + BKE_outliner_treehash.hh BKE_packedFile.h BKE_paint.h BKE_particle.h BKE_pbvh.h + BKE_pbvh_pixels.hh BKE_pointcache.h BKE_pointcloud.h BKE_preferences.h diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 7ef676b3b71..e83720e99f1 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -95,7 +95,7 @@ static MVert *dm_getVertArray(DerivedMesh *dm) if (!mvert) { mvert = (MVert *)CustomData_add_layer( - &dm->vertData, CD_MVERT, CD_CALLOC, nullptr, dm->getNumVerts(dm)); + &dm->vertData, CD_MVERT, CD_SET_DEFAULT, nullptr, dm->getNumVerts(dm)); CustomData_set_layer_flag(&dm->vertData, CD_MVERT, CD_FLAG_TEMPORARY); dm->copyVertArray(dm, mvert); } @@ -109,7 +109,7 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm) if (!medge) { medge = (MEdge *)CustomData_add_layer( - &dm->edgeData, CD_MEDGE, CD_CALLOC, nullptr, dm->getNumEdges(dm)); + &dm->edgeData, CD_MEDGE, CD_SET_DEFAULT, nullptr, dm->getNumEdges(dm)); CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY); dm->copyEdgeArray(dm, medge); } @@ -123,7 +123,7 @@ static MLoop *dm_getLoopArray(DerivedMesh *dm) if (!mloop) { mloop = (MLoop *)CustomData_add_layer( - &dm->loopData, CD_MLOOP, CD_CALLOC, nullptr, dm->getNumLoops(dm)); + &dm->loopData, CD_MLOOP, CD_SET_DEFAULT, nullptr, dm->getNumLoops(dm)); CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY); dm->copyLoopArray(dm, mloop); } @@ -137,7 +137,7 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm) if (!mpoly) { mpoly = (MPoly *)CustomData_add_layer( - &dm->polyData, CD_MPOLY, CD_CALLOC, nullptr, dm->getNumPolys(dm)); + &dm->polyData, CD_MPOLY, CD_SET_DEFAULT, nullptr, dm->getNumPolys(dm)); CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY); dm->copyPolyArray(dm, mpoly); } @@ -284,11 +284,11 @@ void DM_from_template(DerivedMesh *dm, int numPolys) { const CustomData_MeshMasks *mask = &CD_MASK_DERIVEDMESH; - CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_CALLOC, numVerts); - CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_CALLOC, numEdges); - CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_CALLOC, numTessFaces); - CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_CALLOC, numLoops); - CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_CALLOC, numPolys); + CustomData_copy(&source->vertData, &dm->vertData, mask->vmask, CD_SET_DEFAULT, numVerts); + CustomData_copy(&source->edgeData, &dm->edgeData, mask->emask, CD_SET_DEFAULT, numEdges); + CustomData_copy(&source->faceData, &dm->faceData, mask->fmask, CD_SET_DEFAULT, numTessFaces); + CustomData_copy(&source->loopData, &dm->loopData, mask->lmask, CD_SET_DEFAULT, numLoops); + CustomData_copy(&source->polyData, &dm->polyData, mask->pmask, CD_SET_DEFAULT, numPolys); dm->cd_flag = source->cd_flag; @@ -584,7 +584,7 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc } if (!(layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer))) { - CustomData_add_layer(&mesh->vdata, layer, CD_CALLOC, nullptr, mesh->totvert); + CustomData_add_layer(&mesh->vdata, layer, CD_SET_DEFAULT, nullptr, mesh->totvert); BKE_mesh_update_customdata_pointers(mesh, false); layerorco = (float(*)[3])CustomData_get_layer(&mesh->vdata, layer); @@ -1003,11 +1003,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, ((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) { /* calc */ CustomData_add_layer( - &mesh_final->vdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totvert); + &mesh_final->vdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totvert); CustomData_add_layer( - &mesh_final->edata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totedge); + &mesh_final->edata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totedge); CustomData_add_layer( - &mesh_final->pdata, CD_ORIGINDEX, CD_CALLOC, nullptr, mesh_final->totpoly); + &mesh_final->pdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totpoly); /* Not worth parallelizing this, * gives less than 0.1% overall speedup in best of best cases... */ @@ -1043,8 +1043,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* add an origspace layer if needed */ if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer( - &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); + CustomData_add_layer(&mesh_final->ldata, + CD_ORIGSPACE_MLOOP, + CD_SET_DEFAULT, + nullptr, + mesh_final->totloop); mesh_init_origspace(mesh_final); } } @@ -1506,8 +1509,11 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer( - &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_CALLOC, nullptr, mesh_final->totloop); + CustomData_add_layer(&mesh_final->ldata, + CD_ORIGSPACE_MLOOP, + CD_SET_DEFAULT, + nullptr, + mesh_final->totloop); mesh_init_origspace(mesh_final); } } @@ -1591,7 +1597,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, /* Add orco coordinates to final and deformed mesh if requested. */ if (final_datamask.vmask & CD_MASK_ORCO) { - /* FIXME(Campbell): avoid the need to convert to mesh data just to add an orco layer. */ + /* FIXME(@campbellbarton): avoid the need to convert to mesh data just to add an orco layer. */ BKE_mesh_wrapper_ensure_mdata(mesh_final); add_orco_mesh(ob, em_input, mesh_final, mesh_orco, CD_ORCO); diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 2db4c086e04..6d7aed239e7 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -288,7 +288,7 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data, int max_seg_idx = BKE_anim_path_get_array_size(cache) - 1; /* Make an initial guess of where our intersection point will be. - * If the curve was a straight line, then the faction passed in r_new_curve_pos + * If the curve was a straight line, then the fraction passed in r_new_curve_pos * would be the correct location. * So make it our first initial guess. */ diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index fccff602d2e..f7b14cc3479 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -516,7 +516,7 @@ CatalogFilePath AssetCatalogService::find_suitable_cdf_path_for_writing( sizeof(asset_lib_cdf_path), suitable_root_path, DEFAULT_CATALOG_FILENAME.c_str(), - NULL); + nullptr); return asset_lib_cdf_path; } diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc index 495a2c82332..0f7fabcff9b 100644 --- a/source/blender/blenkernel/intern/attribute.cc +++ b/source/blender/blenkernel/intern/attribute.cc @@ -187,9 +187,9 @@ static bool unique_name_cb(void *arg, const char *name) continue; } - CustomData *cdata = info[domain].customdata; + const CustomData *cdata = info[domain].customdata; for (int i = 0; i < cdata->totlayer; i++) { - CustomDataLayer *layer = cdata->layers + i; + const CustomDataLayer *layer = cdata->layers + i; if (STREQ(layer->name, name)) { return true; @@ -247,7 +247,7 @@ CustomDataLayer *BKE_id_attribute_new( return nullptr; } - attributes->add(uniquename, domain, eCustomDataType(type), AttributeInitDefault()); + attributes->add(uniquename, domain, eCustomDataType(type), AttributeInitDefaultValue()); const int index = CustomData_get_named_layer_index(customdata, type, uniquename); return (index == -1) ? nullptr : &(customdata->layers[index]); @@ -421,6 +421,7 @@ int BKE_id_attribute_data_length(ID *id, CustomDataLayer *layer) if (mesh->edit_mesh != nullptr) { return 0; } + break; } default: break; @@ -493,10 +494,10 @@ void BKE_id_attributes_active_set(ID *id, CustomDataLayer *active_layer) int index = 0; for (const int domain : IndexRange(ATTR_DOMAIN_NUM)) { - CustomData *customdata = info[domain].customdata; + const CustomData *customdata = info[domain].customdata; if (customdata) { for (int i = 0; i < customdata->totlayer; i++) { - CustomDataLayer *layer = &customdata->layers[i]; + const CustomDataLayer *layer = &customdata->layers[i]; if (layer == active_layer) { *BKE_id_attributes_active_index_p(id) = index; return; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 1af3cde1821..0187dbd6f78 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -5,7 +5,6 @@ #include "BKE_attribute_math.hh" #include "BKE_customdata.h" #include "BKE_deform.h" -#include "BKE_geometry_fields.hh" #include "BKE_geometry_set.hh" #include "BKE_mesh.h" #include "BKE_pointcloud.h" @@ -56,7 +55,7 @@ const char *no_procedural_access_message = bool allow_procedural_attribute_access(StringRef attribute_name) { - return !attribute_name.startswith(".selection"); + return !attribute_name.startswith(".selection") && !attribute_name.startswith(".hide"); } static int attribute_data_type_complexity(const eCustomDataType data_type) @@ -161,12 +160,19 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data const AttributeInit &initializer) { switch (initializer.type) { - case AttributeInit::Type::Default: { - void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num); + case AttributeInit::Type::Construct: { + void *data = CustomData_add_layer( + &custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num); + return data != nullptr; + } + case AttributeInit::Type::DefaultValue: { + void *data = CustomData_add_layer( + &custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num); return data != nullptr; } case AttributeInit::Type::VArray: { - void *data = CustomData_add_layer(&custom_data, data_type, CD_DEFAULT, nullptr, domain_num); + void *data = CustomData_add_layer( + &custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num); if (data == nullptr) { return false; } @@ -175,7 +181,7 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data return true; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast<const AttributeInitMove &>(initializer).data; + void *source_data = static_cast<const AttributeInitMoveArray &>(initializer).data; void *data = CustomData_add_layer( &custom_data, data_type, CD_ASSIGN, source_data, domain_num); if (data == nullptr) { @@ -216,14 +222,19 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr { const int old_layer_num = custom_data.totlayer; switch (initializer.type) { - case AttributeInit::Type::Default: { + case AttributeInit::Type::Construct: { add_generic_custom_data_layer( - custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id); + custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id); + break; + } + case AttributeInit::Type::DefaultValue: { + add_generic_custom_data_layer( + custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num, attribute_id); break; } case AttributeInit::Type::VArray: { void *data = add_generic_custom_data_layer( - custom_data, data_type, CD_DEFAULT, nullptr, domain_num, attribute_id); + custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id); if (data != nullptr) { const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; varray.materialize_to_uninitialized(varray.index_range(), data); @@ -231,7 +242,7 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr break; } case AttributeInit::Type::MoveArray: { - void *source_data = static_cast<const AttributeInitMove &>(initializer).data; + void *source_data = static_cast<const AttributeInitMoveArray &>(initializer).data; void *data = add_generic_custom_data_layer( custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id); if (source_data != nullptr && data == nullptr) { @@ -723,7 +734,7 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id, const eCustomDataType data_type) { void *result = add_generic_custom_data_layer( - data, data_type, CD_DEFAULT, nullptr, size_, attribute_id); + data, data_type, CD_SET_DEFAULT, nullptr, size_, attribute_id); return result != nullptr; } @@ -794,7 +805,7 @@ void CustomDataAttributes::reorder(Span<AttributeIDRef> new_order) } /* -------------------------------------------------------------------- */ -/** \name Geometry Component +/** \name Attribute API * \{ */ static blender::GVArray try_adapt_data_type(blender::GVArray varray, @@ -805,123 +816,6 @@ static blender::GVArray try_adapt_data_type(blender::GVArray varray, return conversions.try_convert(std::move(varray), to_type); } -GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &UNUSED(scope)) const -{ - if (const GeometryComponentFieldContext *geometry_context = - dynamic_cast<const GeometryComponentFieldContext *>(&context)) { - const GeometryComponent &component = geometry_context->geometry_component(); - const eAttrDomain domain = geometry_context->domain(); - return this->get_varray_for_context(component, domain, mask); - } - return {}; -} - -GVArray AttributeFieldInput::get_varray_for_context(const GeometryComponent &component, - const eAttrDomain domain, - IndexMask UNUSED(mask)) const -{ - const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_); - if (auto attributes = component.attributes()) { - return attributes->lookup(name_, domain, data_type); - } - return {}; -} - -std::string AttributeFieldInput::socket_inspection_name() const -{ - std::stringstream ss; - ss << '"' << name_ << '"' << TIP_(" attribute from geometry"); - return ss.str(); -} - -uint64_t AttributeFieldInput::hash() const -{ - return get_default_hash_2(name_, type_); -} - -bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const -{ - if (const AttributeFieldInput *other_typed = dynamic_cast<const AttributeFieldInput *>(&other)) { - return name_ == other_typed->name_ && type_ == other_typed->type_; - } - return false; -} - -static StringRef get_random_id_attribute_name(const eAttrDomain domain) -{ - switch (domain) { - case ATTR_DOMAIN_POINT: - case ATTR_DOMAIN_INSTANCE: - return "id"; - default: - return ""; - } -} - -GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryComponent &component, - const eAttrDomain domain, - IndexMask mask) const -{ - - const StringRef name = get_random_id_attribute_name(domain); - if (auto attributes = component.attributes()) { - if (GVArray attribute = attributes->lookup(name, domain, CD_PROP_INT32)) { - return attribute; - } - } - - /* Use the index as the fallback if no random ID attribute exists. */ - return fn::IndexFieldInput::get_index_varray(mask); -} - -std::string IDAttributeFieldInput::socket_inspection_name() const -{ - return TIP_("ID / Index"); -} - -uint64_t IDAttributeFieldInput::hash() const -{ - /* All random ID attribute inputs are the same within the same evaluation context. */ - return 92386459827; -} - -bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const -{ - /* All random ID attribute inputs are the same within the same evaluation context. */ - return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr; -} - -GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryComponent &component, - const eAttrDomain domain, - IndexMask UNUSED(mask)) const -{ - const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_); - return component.attributes()->lookup(anonymous_id_.get(), domain, data_type); -} - -std::string AnonymousAttributeFieldInput::socket_inspection_name() const -{ - std::stringstream ss; - ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_; - return ss.str(); -} - -uint64_t AnonymousAttributeFieldInput::hash() const -{ - return get_default_hash_2(anonymous_id_.get(), type_); -} - -bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const -{ - if (const AnonymousAttributeFieldInput *other_typed = - dynamic_cast<const AnonymousAttributeFieldInput *>(&other)) { - return anonymous_id_.get() == other_typed->anonymous_id_.get() && type_ == other_typed->type_; - } - return false; -} - GVArray AttributeAccessor::lookup(const AttributeIDRef &attribute_id, const std::optional<eAttrDomain> domain, const std::optional<eCustomDataType> data_type) const @@ -1072,7 +966,8 @@ GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_span( GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span( const AttributeIDRef &attribute_id, const eAttrDomain domain, const eCustomDataType data_type) { - GAttributeWriter attribute = this->lookup_or_add_for_write(attribute_id, domain, data_type); + GAttributeWriter attribute = this->lookup_or_add_for_write( + attribute_id, domain, data_type, AttributeInitConstruct()); if (attribute) { return GSpanAttributeWriter{std::move(attribute), false}; } diff --git a/source/blender/blenkernel/intern/attribute_math.cc b/source/blender/blenkernel/intern/attribute_math.cc index c38df2a2969..d8102b4eeb8 100644 --- a/source/blender/blenkernel/intern/attribute_math.cc +++ b/source/blender/blenkernel/intern/attribute_math.cc @@ -4,13 +4,31 @@ namespace blender::attribute_math { -ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> output_buffer, +ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, ColorGeometry4f default_color) - : buffer_(output_buffer), - default_color_(default_color), - total_weights_(output_buffer.size(), 0.0f) + : ColorGeometry4fMixer(buffer, buffer.index_range(), default_color) +{ +} + +ColorGeometry4fMixer::ColorGeometry4fMixer(MutableSpan<ColorGeometry4f> buffer, + const IndexMask mask, + const ColorGeometry4f default_color) + : buffer_(buffer), default_color_(default_color), total_weights_(buffer.size(), 0.0f) { - buffer_.fill(ColorGeometry4f(0.0f, 0.0f, 0.0f, 0.0f)); + const ColorGeometry4f zero{0.0f, 0.0f, 0.0f, 0.0f}; + mask.foreach_index([&](const int64_t i) { buffer_[i] = zero; }); +} + +void ColorGeometry4fMixer::set(const int64_t index, + const ColorGeometry4f &color, + const float weight) +{ + BLI_assert(weight >= 0.0f); + buffer_[index].r = color.r * weight; + buffer_[index].g = color.g * weight; + buffer_[index].b = color.b * weight; + buffer_[index].a = color.a * weight; + total_weights_[index] = weight; } void ColorGeometry4fMixer::mix_in(const int64_t index, @@ -28,7 +46,12 @@ void ColorGeometry4fMixer::mix_in(const int64_t index, void ColorGeometry4fMixer::finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(buffer_.index_range()); +} + +void ColorGeometry4fMixer::finalize(const IndexMask mask) +{ + mask.foreach_index([&](const int64_t i) { const float weight = total_weights_[i]; ColorGeometry4f &output_color = buffer_[i]; if (weight > 0.0f) { @@ -41,16 +64,37 @@ void ColorGeometry4fMixer::finalize() else { output_color = default_color_; } - } + }); } ColorGeometry4bMixer::ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, - ColorGeometry4b default_color) + const ColorGeometry4b default_color) + : ColorGeometry4bMixer(buffer, buffer.index_range(), default_color) +{ +} + +ColorGeometry4bMixer::ColorGeometry4bMixer(MutableSpan<ColorGeometry4b> buffer, + const IndexMask mask, + const ColorGeometry4b default_color) : buffer_(buffer), default_color_(default_color), total_weights_(buffer.size(), 0.0f), accumulation_buffer_(buffer.size(), float4(0, 0, 0, 0)) { + const ColorGeometry4b zero{0, 0, 0, 0}; + mask.foreach_index([&](const int64_t i) { buffer_[i] = zero; }); +} + +void ColorGeometry4bMixer::ColorGeometry4bMixer::set(int64_t index, + const ColorGeometry4b &color, + const float weight) +{ + BLI_assert(weight >= 0.0f); + accumulation_buffer_[index][0] = color.r * weight; + accumulation_buffer_[index][1] = color.g * weight; + accumulation_buffer_[index][2] = color.b * weight; + accumulation_buffer_[index][3] = color.a * weight; + total_weights_[index] = weight; } void ColorGeometry4bMixer::mix_in(int64_t index, const ColorGeometry4b &color, float weight) @@ -66,7 +110,12 @@ void ColorGeometry4bMixer::mix_in(int64_t index, const ColorGeometry4b &color, f void ColorGeometry4bMixer::finalize() { - for (const int64_t i : buffer_.index_range()) { + this->finalize(buffer_.index_range()); +} + +void ColorGeometry4bMixer::finalize(const IndexMask mask) +{ + mask.foreach_index([&](const int64_t i) { const float weight = total_weights_[i]; const float4 &accum_value = accumulation_buffer_[i]; ColorGeometry4b &output_color = buffer_[i]; @@ -80,7 +129,7 @@ void ColorGeometry4bMixer::finalize() else { output_color = default_color_; } - } + }); } } // namespace blender::attribute_math diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index a86d6e25ee9..2e07b52c7bf 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -1567,7 +1567,7 @@ void boid_body(BoidBrainData *bbd, ParticleData *pa) cross_v3_v3v3(mat[1], mat[2], mat[0]); /* apply rotation */ - mat3_to_quat_is_ok(q, mat); + mat3_to_quat_legacy(q, mat); copy_qt_qt(pa->state.rot, q); } diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 5838ef1cbbe..34b87dda338 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -186,6 +186,7 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->paint_curve, IDWALK_CB_USER); if (brush->gpencil_settings) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->gpencil_settings->material, IDWALK_CB_USER); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->gpencil_settings->material_alt, IDWALK_CB_USER); } BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_texture_mtex_foreach_id(data, &brush->mtex)); BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, @@ -346,6 +347,7 @@ static void brush_blend_read_lib(BlendLibReader *reader, ID *id) else { brush->gpencil_settings->material = nullptr; } + BLO_read_id_address(reader, brush->id.lib, &brush->gpencil_settings->material_alt); } } @@ -358,6 +360,7 @@ static void brush_blend_read_expand(BlendExpander *expander, ID *id) BLO_expand(expander, brush->paint_curve); if (brush->gpencil_settings != nullptr) { BLO_expand(expander, brush->gpencil_settings->material); + BLO_expand(expander, brush->gpencil_settings->material_alt); } } @@ -597,7 +600,7 @@ using eGPCurveMappingPreset = enum eGPCurveMappingPreset { GPCURVE_PRESET_CHISEL_STRENGTH = 5, }; -static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, int preset) +static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, eGPCurveMappingPreset preset) { if (cuma->curve) { MEM_freeN(cuma->curve); @@ -704,6 +707,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) /* Set vertex mix factor. */ brush->gpencil_settings->vertex_mode = GPPAINT_MODE_BOTH; brush->gpencil_settings->vertex_factor = 1.0f; + brush->gpencil_settings->material_alt = nullptr; switch (type) { case GP_BRUSH_PRESET_AIRBRUSH: { diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc index 03dd5c89b70..d0b57b45d35 100644 --- a/source/blender/blenkernel/intern/bvhutils.cc +++ b/source/blender/blenkernel/intern/bvhutils.cc @@ -27,6 +27,8 @@ #include "MEM_guardedalloc.h" +using blender::VArray; + /* -------------------------------------------------------------------- */ /** \name BVHCache * \{ */ @@ -1181,9 +1183,13 @@ static BLI_bitmap *loose_edges_map_get(const MEdge *medge, } static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly, + const VArray<bool> &hide_poly, const int looptri_len, int *r_looptri_active_len) { + if (hide_poly.is_single() && !hide_poly.get_internal_single()) { + return nullptr; + } BLI_bitmap *looptri_mask = BLI_BITMAP_NEW(looptri_len, __func__); int looptri_no_hidden_len = 0; @@ -1191,8 +1197,7 @@ static BLI_bitmap *looptri_no_hidden_map_get(const MPoly *mpoly, int i_poly = 0; while (looptri_iter != looptri_len) { int mp_totlooptri = mpoly[i_poly].totloop - 2; - const MPoly &mp = mpoly[i_poly]; - if (mp.flag & ME_HIDE) { + if (hide_poly[i_poly]) { looptri_iter += mp_totlooptri; } else { @@ -1276,9 +1281,15 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data, 0.0f, tree_type, 6, mesh->mvert, mesh->mface, mesh->totface, nullptr, -1); break; - case BVHTREE_FROM_LOOPTRI_NO_HIDDEN: - mask = looptri_no_hidden_map_get(mesh->mpoly, looptri_len, &mask_bits_act_len); + case BVHTREE_FROM_LOOPTRI_NO_HIDDEN: { + blender::bke::AttributeAccessor attributes = blender::bke::mesh_attributes(*mesh); + mask = looptri_no_hidden_map_get( + mesh->mpoly, + attributes.lookup_or_default(".hide_poly", ATTR_DOMAIN_FACE, false), + looptri_len, + &mask_bits_act_len); ATTR_FALLTHROUGH; + } case BVHTREE_FROM_LOOPTRI: data->tree = bvhtree_from_mesh_looptri_create_tree(0.0f, tree_type, diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 6b6b7223a0b..fd83ac50cad 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -429,10 +429,10 @@ bool BKE_cache_file_uses_render_procedural(const CacheFile *cache_file, Scene *s return cache_file->use_render_procedural; } -CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filename[1024]) +CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filepath[1024]) { for (CacheFileLayer *layer = cache_file->layers.first; layer; layer = layer->next) { - if (STREQ(layer->filepath, filename)) { + if (STREQ(layer->filepath, filepath)) { return NULL; } } @@ -440,7 +440,7 @@ CacheFileLayer *BKE_cachefile_add_layer(CacheFile *cache_file, const char filena const int num_layers = BLI_listbase_count(&cache_file->layers); CacheFileLayer *layer = MEM_callocN(sizeof(CacheFileLayer), "CacheFileLayer"); - BLI_strncpy(layer->filepath, filename, sizeof(layer->filepath)); + BLI_strncpy(layer->filepath, filepath, sizeof(layer->filepath)); BLI_addtail(&cache_file->layers, layer); diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c index b2f817b7821..5145f1cbbc0 100644 --- a/source/blender/blenkernel/intern/colorband.c +++ b/source/blender/blenkernel/intern/colorband.c @@ -144,7 +144,7 @@ static float color_sample_remove_cost(const struct ColorResampleElem *c) return area; } -/* TODO(campbell): create BLI_math_filter? */ +/* TODO(@campbellbarton): create `BLI_math_filter` ? */ static float filter_gauss(float x) { const float gaussfac = 1.6f; diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 9f1d2d7bbb2..071fa5fe6bf 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -1559,7 +1559,7 @@ static void followpath_evaluate(bConstraint *con, bConstraintOb *cob, ListBase * /* un-apply scaling caused by path */ if ((data->followflag & FOLLOWPATH_RADIUS) == 0) { - /* XXX(campbell): Assume that scale correction means that radius + /* XXX(@campbellbarton): Assume that scale correction means that radius * will have some scale error in it. */ float obsize[3]; diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc index 8d4b64da817..fdd269bd9c8 100644 --- a/source/blender/blenkernel/intern/crazyspace.cc +++ b/source/blender/blenkernel/intern/crazyspace.cc @@ -73,7 +73,7 @@ static void set_crazy_vertex_quat(float r_quat[4], static bool modifiers_disable_subsurf_temporary(struct Scene *scene, Object *ob) { bool disabled = false; - int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true); ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first); for (int i = 0; md && i <= cageIndex; i++, md = md->next) { @@ -241,7 +241,7 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgra Mesh *me_input = static_cast<Mesh *>(ob->data); Mesh *me = nullptr; int i, a, modifiers_left_num = 0, verts_num = 0; - int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, 1); + int cageIndex = BKE_modifiers_get_cage_index(scene, ob, nullptr, true); float(*defmats)[3][3] = nullptr, (*deformedVerts)[3] = nullptr; VirtualModifierData virtualModifierData; ModifierEvalContext mectx = {depsgraph, ob, ModifierApplyFlag(0)}; @@ -362,7 +362,7 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph, VirtualModifierData virtualModifierData; Object object_eval; crazyspace_init_object_for_eval(depsgraph, object, &object_eval); - MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0); + MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, false); const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0; const bool has_multires = mmd != nullptr && mmd->sculptlvl > 0; const ModifierEvalContext mectx = {depsgraph, &object_eval, ModifierApplyFlag(0)}; diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index 5125e010b81..40b64aa8dc8 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -2470,7 +2470,7 @@ static void make_bevel_list_segment_2D(BevList *bl) static void make_bevel_list_2D(BevList *bl) { - /* NOTE(campbell): `bevp->dir` and `bevp->quat` are not needed for beveling but are + /* NOTE(@campbellbarton): `bevp->dir` and `bevp->quat` are not needed for beveling but are * used when making a path from a 2D curve, therefore they need to be set. */ BevPoint *bevp0, *bevp1, *bevp2; diff --git a/source/blender/blenkernel/intern/curve_nurbs.cc b/source/blender/blenkernel/intern/curve_nurbs.cc index 3ab6fb01ea5..62d5682da0f 100644 --- a/source/blender/blenkernel/intern/curve_nurbs.cc +++ b/source/blender/blenkernel/intern/curve_nurbs.cc @@ -4,8 +4,9 @@ * \ingroup bke */ -#include "BKE_attribute_math.hh" +#include "BLI_task.hh" +#include "BKE_attribute_math.hh" #include "BKE_curves.hh" namespace blender::bke::curves::nurbs { @@ -192,16 +193,16 @@ static void interpolate_to_evaluated(const BasisCache &basis_cache, { attribute_math::DefaultMixer<T> mixer{dst}; - for (const int i : dst.index_range()) { - Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order); - - for (const int j : point_weights.index_range()) { - const int point_index = (basis_cache.start_indices[i] + j) % src.size(); - mixer.mix_in(i, src[point_index], point_weights[j]); + threading::parallel_for(dst.index_range(), 128, [&](const IndexRange range) { + for (const int i : range) { + Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order); + for (const int j : point_weights.index_range()) { + const int point_index = (basis_cache.start_indices[i] + j) % src.size(); + mixer.mix_in(i, src[point_index], point_weights[j]); + } } - } - - mixer.finalize(); + mixer.finalize(range); + }); } template<typename T> @@ -213,17 +214,18 @@ static void interpolate_to_evaluated_rational(const BasisCache &basis_cache, { attribute_math::DefaultMixer<T> mixer{dst}; - for (const int i : dst.index_range()) { - Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order); + threading::parallel_for(dst.index_range(), 128, [&](const IndexRange range) { + for (const int i : range) { + Span<float> point_weights = basis_cache.weights.as_span().slice(i * order, order); - for (const int j : point_weights.index_range()) { - const int point_index = (basis_cache.start_indices[i] + j) % src.size(); - const float weight = point_weights[j] * control_weights[point_index]; - mixer.mix_in(i, src[point_index], weight); + for (const int j : point_weights.index_range()) { + const int point_index = (basis_cache.start_indices[i] + j) % src.size(); + const float weight = point_weights[j] * control_weights[point_index]; + mixer.mix_in(i, src[point_index], weight); + } } - } - - mixer.finalize(); + mixer.finalize(range); + }); } void interpolate_to_evaluated(const BasisCache &basis_cache, diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index f90cf48090c..6211f6b7be6 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -366,6 +366,8 @@ namespace blender::bke { Curves *curves_new_nomain(const int points_num, const int curves_num) { + BLI_assert(points_num >= 0); + BLI_assert(curves_num >= 0); Curves *curves_id = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr)); CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); curves.resize(points_num, curves_num); diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index ef4a4ee1d6b..3f549b39a00 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -13,6 +13,7 @@ #include "BLI_index_mask_ops.hh" #include "BLI_length_parameterize.hh" #include "BLI_math_rotation.hh" +#include "BLI_task.hh" #include "DNA_curves_types.h" @@ -57,7 +58,7 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num) CustomData_add_layer_named(&this->point_data, CD_PROP_FLOAT3, - CD_DEFAULT, + CD_CONSTRUCT, nullptr, this->point_num, ATTR_POSITION.c_str()); @@ -221,7 +222,7 @@ static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves, return {data, num}; } data = (T *)CustomData_add_layer_named( - &custom_data, type, CD_CALLOC, nullptr, num, name.c_str()); + &custom_data, type, CD_SET_DEFAULT, nullptr, num, name.c_str()); MutableSpan<T> span = {data, num}; if (num > 0 && span.first() != default_value) { span.fill(default_value); @@ -254,6 +255,12 @@ void CurvesGeometry::fill_curve_types(const IndexMask selection, const CurveType this->fill_curve_types(type); return; } + if (std::optional<int8_t> single_type = this->curve_types().get_if_single()) { + if (single_type == type) { + /* No need for an array if the types are already a single with the correct type. */ + return; + } + } /* A potential performance optimization is only counting the changed indices. */ this->curve_types_for_write().fill_indices(selection, type); this->update_curve_types(); @@ -1169,6 +1176,10 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, } CurvesGeometry new_curves{new_point_count, new_curve_count}; + Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer( + curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT); + Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer( + curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE); threading::parallel_invoke( 256 < new_point_count * new_curve_count, @@ -1176,8 +1187,7 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, [&]() { new_curves.offsets_for_write().copy_from(new_curve_offsets); }, [&]() { /* Copy over point attributes. */ - for (auto &attribute : bke::retrieve_attributes_for_transfer( - curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT)) { + for (bke::AttributeTransferData &attribute : point_attributes) { threading::parallel_for(copy_point_ranges.index_range(), 128, [&](IndexRange range) { for (const int range_i : range) { const IndexRange src_range = copy_point_ranges[range_i]; @@ -1188,24 +1198,29 @@ static CurvesGeometry copy_with_removed_points(const CurvesGeometry &curves, {copy_point_range_dst_offsets[range_i], src_range.size()}); } }); - attribute.dst.finish(); } - + }, + [&]() { /* Copy over curve attributes. - * In some cases points are just dissolved, so the the number of + * In some cases points are just dissolved, so the number of * curves will be the same. That could be optimized in the future. */ - for (auto &attribute : bke::retrieve_attributes_for_transfer( - curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE)) { + for (bke::AttributeTransferData &attribute : curve_attributes) { if (new_curves.curves_num() == curves.curves_num()) { attribute.dst.span.copy_from(attribute.src); } else { copy_with_map(attribute.src, new_curve_orig_indices, attribute.dst.span); } - attribute.dst.finish(); } }); + for (bke::AttributeTransferData &attribute : point_attributes) { + attribute.dst.finish(); + } + for (bke::AttributeTransferData &attribute : curve_attributes) { + attribute.dst.finish(); + } + return new_curves; } @@ -1242,6 +1257,10 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, } CurvesGeometry new_curves{new_tot_points, new_tot_curves}; + Vector<bke::AttributeTransferData> point_attributes = bke::retrieve_attributes_for_transfer( + curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT); + Vector<bke::AttributeTransferData> curve_attributes = bke::retrieve_attributes_for_transfer( + curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE); threading::parallel_invoke( 256 < new_tot_points * new_tot_curves, @@ -1273,8 +1292,7 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, }, [&]() { /* Copy over point attributes. */ - for (auto &attribute : bke::retrieve_attributes_for_transfer( - curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_POINT)) { + for (bke::AttributeTransferData &attribute : point_attributes) { threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) { for (const int range_i : range) { copy_between_buffers(attribute.src.type(), @@ -1284,11 +1302,11 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, new_point_ranges[range_i]); } }); - attribute.dst.finish(); } + }, + [&]() { /* Copy over curve attributes. */ - for (auto &attribute : bke::retrieve_attributes_for_transfer( - curves.attributes(), new_curves.attributes_for_write(), ATTR_DOMAIN_MASK_CURVE)) { + for (bke::AttributeTransferData &attribute : curve_attributes) { threading::parallel_for(old_curve_ranges.index_range(), 128, [&](IndexRange range) { for (const int range_i : range) { copy_between_buffers(attribute.src.type(), @@ -1298,10 +1316,16 @@ static CurvesGeometry copy_with_removed_curves(const CurvesGeometry &curves, new_curve_ranges[range_i]); } }); - attribute.dst.finish(); } }); + for (bke::AttributeTransferData &attribute : point_attributes) { + attribute.dst.finish(); + } + for (bke::AttributeTransferData &attribute : curve_attributes) { + attribute.dst.finish(); + } + return new_curves; } @@ -1456,12 +1480,15 @@ static void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves, MutableSpan<T> r_values) { attribute_math::DefaultMixer<T> mixer(r_values); - for (const int i_curve : IndexRange(curves.curves_num())) { - for (const int i_point : curves.points_for_curve(i_curve)) { - mixer.mix_in(i_curve, old_values[i_point]); + + threading::parallel_for(curves.curves_range(), 128, [&](const IndexRange range) { + for (const int i_curve : range) { + for (const int i_point : curves.points_for_curve(i_curve)) { + mixer.mix_in(i_curve, old_values[i_point]); + } } - } - mixer.finalize(); + mixer.finalize(range); + }); } /** diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 1c7b78fd902..9a9128387b1 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -26,6 +26,7 @@ #include "BLI_math_vector.hh" #include "BLI_mempool.h" #include "BLI_path_util.h" +#include "BLI_set.hh" #include "BLI_span.hh" #include "BLI_string.h" #include "BLI_string_ref.hh" @@ -58,6 +59,7 @@ #include "data_transfer_intern.h" using blender::IndexRange; +using blender::Set; using blender::Span; using blender::StringRef; using blender::Vector; @@ -152,9 +154,15 @@ struct LayerTypeInfo { void (*swap)(void *data, const int *corner_indices); /** - * a function to set a layer's data to default values. if null, the - * default is assumed to be all zeros */ - void (*set_default)(void *data, int count); + * Set values to the type's default. If undefined, the default is assumed to be zeroes. + * Memory pointed to by #data is expected to be uninitialized. + */ + void (*set_default_value)(void *data, int count); + /** + * Construct and fill a valid value for the type. Necessary for non-trivial types. + * Memory pointed to by #data is expected to be uninitialized. + */ + void (*construct)(void *data, int count); /** A function used by mesh validating code, must ensures passed item has valid data. */ cd_validate validate; @@ -165,7 +173,7 @@ struct LayerTypeInfo { void (*initminmax)(void *min, void *max); void (*add)(void *data1, const void *data2); void (*dominmax)(const void *data1, void *min, void *max); - void (*copyvalue)(const void *source, void *dest, const int mixmode, const float mixfactor); + void (*copyvalue)(const void *source, void *dest, int mixmode, const float mixfactor); /** a function to read data from a cdf file */ bool (*read)(CDataFile *cdf, void *data, int count); @@ -187,7 +195,7 @@ struct LayerTypeInfo { /** \name Callbacks for (#MDeformVert, #CD_MDEFORMVERT) * \{ */ -static void layerCopy_mdeformvert(const void *source, void *dest, int count) +static void layerCopy_mdeformvert(const void *source, void *dest, const int count) { int i, size = sizeof(MDeformVert); @@ -209,7 +217,7 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count) } } -static void layerFree_mdeformvert(void *data, int count, int size) +static void layerFree_mdeformvert(void *data, const int count, const int size) { for (int i = 0; i < count; i++) { MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(data, i * size)); @@ -222,38 +230,10 @@ static void layerFree_mdeformvert(void *data, int count, int size) } } -/* copy just zeros in this case */ -static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, int count) -{ - const int size = sizeof(void *); - - for (int i = 0; i < count; i++) { - void **ptr = (void **)POINTER_OFFSET(dest, i * size); - *ptr = nullptr; - } -} - -#ifndef WITH_PYTHON -void bpy_bm_generic_invalidate(struct BPy_BMGeneric *UNUSED(self)) -{ - /* dummy */ -} -#endif - -static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size) -{ - for (int i = 0; i < count; i++) { - void **ptr = (void **)POINTER_OFFSET(data, i * size); - if (*ptr) { - bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr)); - } - } -} - static void layerInterp_mdeformvert(const void **sources, const float *weights, const float *UNUSED(sub_weights), - int count, + const int count, void *dest) { /* a single linked list of MDeformWeight's @@ -338,6 +318,11 @@ static void layerInterp_mdeformvert(const void **sources, } } +static void layerConstruct_mdeformvert(void *data, const int count) +{ + memset(data, 0, sizeof(MDeformVert) * count); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -347,7 +332,7 @@ static void layerInterp_mdeformvert(const void **sources, static void layerInterp_normal(const void **sources, const float *weights, const float *UNUSED(sub_weights), - int count, + const int count, void *dest) { /* NOTE: This is linear interpolation, which is not optimal for vectors. @@ -355,8 +340,8 @@ static void layerInterp_normal(const void **sources, * so for now it will do... */ float no[3] = {0.0f}; - while (count--) { - madd_v3_v3fl(no, (const float *)sources[count], weights[count]); + for (const int i : IndexRange(count)) { + madd_v3_v3fl(no, (const float *)sources[i], weights[i]); } /* Weighted sum of normalized vectors will **not** be normalized, even if weights are. */ @@ -406,7 +391,7 @@ static void layerCopyValue_normal(const void *source, /** \name Callbacks for (#MTFace, #CD_MTFACE) * \{ */ -static void layerCopy_tface(const void *source, void *dest, int count) +static void layerCopy_tface(const void *source, void *dest, const int count) { const MTFace *source_tf = (const MTFace *)source; MTFace *dest_tf = (MTFace *)dest; @@ -415,8 +400,11 @@ static void layerCopy_tface(const void *source, void *dest, int count) } } -static void layerInterp_tface( - const void **sources, const float *weights, const float *sub_weights, int count, void *dest) +static void layerInterp_tface(const void **sources, + const float *weights, + const float *sub_weights, + const int count, + void *dest) { MTFace *tf = static_cast<MTFace *>(dest); float uv[4][2] = {{0.0f}}; @@ -456,7 +444,7 @@ static void layerSwap_tface(void *data, const int *corner_indices) memcpy(tf->uv, uv, sizeof(tf->uv)); } -static void layerDefault_tface(void *data, int count) +static void layerDefault_tface(void *data, const int count) { static MTFace default_tf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}}; MTFace *tf = (MTFace *)data; @@ -477,7 +465,7 @@ static int layerMaxNum_tface() /** \name Callbacks for (#MFloatProperty, #CD_PROP_FLOAT) * \{ */ -static void layerCopy_propFloat(const void *source, void *dest, int count) +static void layerCopy_propFloat(const void *source, void *dest, const int count) { memcpy(dest, source, sizeof(MFloatProperty) * count); } @@ -485,7 +473,7 @@ static void layerCopy_propFloat(const void *source, void *dest, int count) static void layerInterp_propFloat(const void **sources, const float *weights, const float *UNUSED(sub_weights), - int count, + const int count, void *dest) { float result = 0.0f; @@ -520,15 +508,10 @@ static bool layerValidate_propFloat(void *data, const uint totitems, const bool /** \name Callbacks for (#MIntProperty, #CD_PROP_INT32) * \{ */ -static void layerCopy_propInt(const void *source, void *dest, int count) -{ - memcpy(dest, source, sizeof(MIntProperty) * count); -} - static void layerInterp_propInt(const void **sources, const float *weights, const float *UNUSED(sub_weights), - int count, + const int count, void *dest) { float result = 0.0f; @@ -547,7 +530,7 @@ static void layerInterp_propInt(const void **sources, /** \name Callbacks for (#MStringProperty, #CD_PROP_STRING) * \{ */ -static void layerCopy_propString(const void *source, void *dest, int count) +static void layerCopy_propString(const void *source, void *dest, const int count) { memcpy(dest, source, sizeof(MStringProperty) * count); } @@ -558,7 +541,7 @@ static void layerCopy_propString(const void *source, void *dest, int count) /** \name Callbacks for (#OrigSpaceFace, #CD_ORIGSPACE) * \{ */ -static void layerCopy_origspace_face(const void *source, void *dest, int count) +static void layerCopy_origspace_face(const void *source, void *dest, const int count) { const OrigSpaceFace *source_tf = (const OrigSpaceFace *)source; OrigSpaceFace *dest_tf = (OrigSpaceFace *)dest; @@ -568,8 +551,11 @@ static void layerCopy_origspace_face(const void *source, void *dest, int count) } } -static void layerInterp_origspace_face( - const void **sources, const float *weights, const float *sub_weights, int count, void *dest) +static void layerInterp_origspace_face(const void **sources, + const float *weights, + const float *sub_weights, + const int count, + void *dest) { OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(dest); float uv[4][2] = {{0.0f}}; @@ -606,7 +592,7 @@ static void layerSwap_origspace_face(void *data, const int *corner_indices) memcpy(osf->uv, uv, sizeof(osf->uv)); } -static void layerDefault_origspace_face(void *data, int count) +static void layerDefault_origspace_face(void *data, const int count) { static OrigSpaceFace default_osf = {{{0, 0}, {1, 0}, {1, 1}, {0, 1}}}; OrigSpaceFace *osf = (OrigSpaceFace *)data; @@ -652,7 +638,7 @@ static void layerSwap_mdisps(void *data, const int *ci) } } -static void layerCopy_mdisps(const void *source, void *dest, int count) +static void layerCopy_mdisps(const void *source, void *dest, const int count) { const MDisps *s = static_cast<const MDisps *>(source); MDisps *d = static_cast<MDisps *>(dest); @@ -673,7 +659,7 @@ static void layerCopy_mdisps(const void *source, void *dest, int count) } } -static void layerFree_mdisps(void *data, int count, int UNUSED(size)) +static void layerFree_mdisps(void *data, const int count, const int UNUSED(size)) { MDisps *d = static_cast<MDisps *>(data); @@ -691,7 +677,12 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size)) } } -static bool layerRead_mdisps(CDataFile *cdf, void *data, int count) +static void layerConstruct_mdisps(void *data, const int count) +{ + memset(data, 0, sizeof(MDisps) * count); +} + +static bool layerRead_mdisps(CDataFile *cdf, void *data, const int count) { MDisps *d = static_cast<MDisps *>(data); @@ -709,7 +700,7 @@ static bool layerRead_mdisps(CDataFile *cdf, void *data, int count) return true; } -static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count) +static bool layerWrite_mdisps(CDataFile *cdf, const void *data, const int count) { const MDisps *d = static_cast<const MDisps *>(data); @@ -723,7 +714,7 @@ static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count) return true; } -static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int count) +static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, const int count) { const MDisps *d = static_cast<const MDisps *>(data); size_t size = 0; @@ -738,6 +729,40 @@ static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int /** \} */ /* -------------------------------------------------------------------- */ +/** \name Callbacks for (#CD_BM_ELEM_PYPTR) + * \{ */ + +/* copy just zeros in this case */ +static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, const int count) +{ + const int size = sizeof(void *); + + for (int i = 0; i < count; i++) { + void **ptr = (void **)POINTER_OFFSET(dest, i * size); + *ptr = nullptr; + } +} + +#ifndef WITH_PYTHON +void bpy_bm_generic_invalidate(struct BPy_BMGeneric *UNUSED(self)) +{ + /* dummy */ +} +#endif + +static void layerFree_bmesh_elem_py_ptr(void *data, const int count, const int size) +{ + for (int i = 0; i < count; i++) { + void **ptr = (void **)POINTER_OFFSET(data, i * size); + if (*ptr) { + bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr)); + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Callbacks for (`float`, #CD_PAINT_MASK) * \{ */ @@ -762,7 +787,7 @@ static void layerInterp_paint_mask(const void **sources, /** \name Callbacks for (#GridPaintMask, #CD_GRID_PAINT_MASK) * \{ */ -static void layerCopy_grid_paint_mask(const void *source, void *dest, int count) +static void layerCopy_grid_paint_mask(const void *source, void *dest, const int count) { const GridPaintMask *s = static_cast<const GridPaintMask *>(source); GridPaintMask *d = static_cast<GridPaintMask *>(dest); @@ -779,7 +804,7 @@ static void layerCopy_grid_paint_mask(const void *source, void *dest, int count) } } -static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size)) +static void layerFree_grid_paint_mask(void *data, const int count, const int UNUSED(size)) { GridPaintMask *gpm = static_cast<GridPaintMask *>(data); @@ -789,6 +814,11 @@ static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size)) } } +static void layerConstruct_grid_paint_mask(void *data, const int count) +{ + memset(data, 0, sizeof(GridPaintMask) * count); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -867,7 +897,7 @@ static bool layerEqual_mloopcol(const void *data1, const void *data2) return r * r + g * g + b * b + a * a < 0.001f; } -static void layerMultiply_mloopcol(void *data, float fac) +static void layerMultiply_mloopcol(void *data, const float fac) { MLoopCol *m = static_cast<MLoopCol *>(data); @@ -936,7 +966,7 @@ static void layerInitMinMax_mloopcol(void *vmin, void *vmax) max->a = 0; } -static void layerDefault_mloopcol(void *data, int count) +static void layerDefault_mloopcol(void *data, const int count) { MLoopCol default_mloopcol = {255, 255, 255, 255}; MLoopCol *mlcol = (MLoopCol *)data; @@ -1011,7 +1041,7 @@ static bool layerEqual_mloopuv(const void *data1, const void *data2) return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f; } -static void layerMultiply_mloopuv(void *data, float fac) +static void layerMultiply_mloopuv(void *data, const float fac) { MLoopUV *luv = static_cast<MLoopUV *>(data); @@ -1105,7 +1135,7 @@ static bool layerEqual_mloop_origspace(const void *data1, const void *data2) return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f; } -static void layerMultiply_mloop_origspace(void *data, float fac) +static void layerMultiply_mloop_origspace(void *data, const float fac) { OrigSpaceLoop *luv = static_cast<OrigSpaceLoop *>(data); @@ -1157,8 +1187,11 @@ static void layerInterp_mloop_origspace(const void **sources, } /* --- end copy */ -static void layerInterp_mcol( - const void **sources, const float *weights, const float *sub_weights, int count, void *dest) +static void layerInterp_mcol(const void **sources, + const float *weights, + const float *sub_weights, + const int count, + void *dest) { MCol *mc = static_cast<MCol *>(dest); struct { @@ -1217,7 +1250,7 @@ static void layerSwap_mcol(void *data, const int *corner_indices) memcpy(mcol, col, sizeof(col)); } -static void layerDefault_mcol(void *data, int count) +static void layerDefault_mcol(void *data, const int count) { static MCol default_mcol = {255, 255, 255, 255}; MCol *mcol = (MCol *)data; @@ -1227,7 +1260,7 @@ static void layerDefault_mcol(void *data, int count) } } -static void layerDefault_origindex(void *data, int count) +static void layerDefault_origindex(void *data, const int count) { copy_vn_i((int *)data, count, ORIGINDEX_NONE); } @@ -1285,7 +1318,7 @@ static void layerInterp_shapekey(const void **sources, /** \name Callbacks for (#MVertSkin, #CD_MVERT_SKIN) * \{ */ -static void layerDefault_mvert_skin(void *data, int count) +static void layerDefault_mvert_skin(void *data, const int count) { MVertSkin *vs = static_cast<MVertSkin *>(data); @@ -1295,7 +1328,7 @@ static void layerDefault_mvert_skin(void *data, int count) } } -static void layerCopy_mvert_skin(const void *source, void *dest, int count) +static void layerCopy_mvert_skin(const void *source, void *dest, const int count) { memcpy(dest, source, sizeof(MVertSkin) * count); } @@ -1347,7 +1380,7 @@ static void layerSwap_flnor(void *data, const int *corner_indices) /** \name Callbacks for (`int`, #CD_FACEMAP) * \{ */ -static void layerDefault_fmap(void *data, int count) +static void layerDefault_fmap(void *data, const int count) { int *fmap_num = (int *)data; for (int i = 0; i < count; i++) { @@ -1423,7 +1456,7 @@ static bool layerEqual_propcol(const void *data1, const void *data2) return tot < 0.001f; } -static void layerMultiply_propcol(void *data, float fac) +static void layerMultiply_propcol(void *data, const float fac) { MPropCol *m = static_cast<MPropCol *>(data); mul_v4_fl(m->color, fac); @@ -1453,7 +1486,7 @@ static void layerInitMinMax_propcol(void *vmin, void *vmax) copy_v4_fl(max->color, FLT_MIN); } -static void layerDefault_propcol(void *data, int count) +static void layerDefault_propcol(void *data, const int count) { /* Default to white, full alpha. */ MPropCol default_propcol = {{1.0f, 1.0f, 1.0f, 1.0f}}; @@ -1500,7 +1533,7 @@ static void layerInterp_propfloat3(const void **sources, copy_v3_v3((float *)dest, &result.x); } -static void layerMultiply_propfloat3(void *data, float fac) +static void layerMultiply_propfloat3(void *data, const float fac) { vec3f *vec = static_cast<vec3f *>(data); vec->x *= fac; @@ -1553,7 +1586,7 @@ static void layerInterp_propfloat2(const void **sources, copy_v2_v2((float *)dest, &result.x); } -static void layerMultiply_propfloat2(void *data, float fac) +static void layerMultiply_propfloat2(void *data, const float fac) { vec2f *vec = static_cast<vec2f *>(data); vec->x *= fac; @@ -1618,30 +1651,23 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerFree_mdeformvert, layerInterp_mdeformvert, nullptr, + layerConstruct_mdeformvert, nullptr}, /* 3: CD_MEDGE */ {sizeof(MEdge), "MEdge", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 4: CD_MFACE */ {sizeof(MFace), "MFace", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 5: CD_MTFACE */ - {sizeof(MTFace), "MTFace", 1, - N_("UVMap"), layerCopy_tface, nullptr, - layerInterp_tface, layerSwap_tface, layerDefault_tface, - nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, - nullptr, layerMaxNum_tface}, - /* 6: CD_MCOL */ - /* 4 MCol structs per face */ - {sizeof(MCol[4]), - "MCol", - 4, - N_("Col"), + {sizeof(MTFace), + "MTFace", + 1, + N_("UVMap"), + layerCopy_tface, nullptr, + layerInterp_tface, + layerSwap_tface, nullptr, - layerInterp_mcol, - layerSwap_mcol, - layerDefault_mcol, + layerDefault_tface, nullptr, nullptr, nullptr, @@ -1652,7 +1678,16 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, nullptr, nullptr, - nullptr}, + layerMaxNum_tface}, + /* 6: CD_MCOL */ + /* 4 MCol structs per face */ + {sizeof(MCol[4]), "MCol", 4, + N_("Col"), nullptr, nullptr, + layerInterp_mcol, layerSwap_mcol, layerDefault_mcol, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr}, /* 7: CD_ORIGINDEX */ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_origindex}, /* 8: CD_NORMAL */ @@ -1672,6 +1707,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, nullptr, nullptr, + nullptr, layerCopyValue_normal}, /* 9: CD_FACEMAP */ {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_fmap, nullptr}, @@ -1685,13 +1721,14 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_propFloat, nullptr, nullptr, + nullptr, layerValidate_propFloat}, /* 11: CD_PROP_INT32 */ {sizeof(MIntProperty), "MIntProperty", 1, N_("Int"), - layerCopy_propInt, + nullptr, nullptr, layerInterp_propInt, nullptr}, @@ -1730,6 +1767,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_mloopuv, nullptr, nullptr, + nullptr, layerValidate_mloopuv, layerEqual_mloopuv, layerMultiply_mloopuv, @@ -1752,6 +1790,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerDefault_mloopcol, nullptr, + nullptr, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, @@ -1774,6 +1813,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerSwap_mdisps, nullptr, + layerConstruct_mdisps, nullptr, nullptr, nullptr, @@ -1843,6 +1883,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, nullptr, nullptr, + nullptr, layerEqual_mloop_origspace, layerMultiply_mloop_origspace, layerInitMinMax_mloop_origspace, @@ -1860,6 +1901,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerDefault_mloopcol, nullptr, + nullptr, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, @@ -1887,7 +1929,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerFree_grid_paint_mask, nullptr, nullptr, - nullptr}, + nullptr, + layerConstruct_grid_paint_mask}, /* 36: CD_MVERT_SKIN */ {sizeof(MVertSkin), "MVertSkin", @@ -1945,6 +1988,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { nullptr, layerDefault_propcol, nullptr, + nullptr, layerEqual_propcol, layerMultiply_propcol, layerInitMinMax_propcol, @@ -1965,6 +2009,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_propfloat3, nullptr, nullptr, + nullptr, layerValidate_propfloat3, nullptr, layerMultiply_propfloat3, @@ -1980,6 +2025,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerInterp_propfloat2, nullptr, nullptr, + nullptr, layerValidate_propfloat2, nullptr, layerMultiply_propfloat2, @@ -2317,7 +2363,44 @@ bool CustomData_merge(const CustomData *source, return changed; } -void CustomData_realloc(CustomData *data, int totelem) +static bool attribute_stored_in_bmesh_flag(const StringRef name) +{ + return ELEM(name, ".hide_vert", ".hide_edge", ".hide_poly", "material_index"); +} + +static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src) +{ + Vector<CustomDataLayer> dst_layers; + for (const CustomDataLayer &layer : Span<CustomDataLayer>{src.layers, src.totlayer}) { + if (!attribute_stored_in_bmesh_flag(layer.name)) { + dst_layers.append(layer); + } + } + + CustomData dst = src; + dst.layers = static_cast<CustomDataLayer *>( + MEM_calloc_arrayN(dst_layers.size(), sizeof(CustomDataLayer), __func__)); + dst.totlayer = dst_layers.size(); + memcpy(dst.layers, dst_layers.data(), dst_layers.as_span().size_in_bytes()); + + CustomData_update_typemap(&dst); + + return dst; +} + +bool CustomData_merge_mesh_to_bmesh(const CustomData *source, + CustomData *dest, + const eCustomDataMask mask, + const eCDAllocType alloctype, + const int totelem) +{ + CustomData source_copy = shallow_copy_remove_non_bmesh_attributes(*source); + const bool result = CustomData_merge(&source_copy, dest, mask, alloctype, totelem); + MEM_SAFE_FREE(source_copy.layers); + return result; +} + +void CustomData_realloc(CustomData *data, const int totelem) { BLI_assert(totelem >= 0); for (int i = 0; i < data->totlayer; i++) { @@ -2348,7 +2431,18 @@ void CustomData_copy(const CustomData *source, CustomData_merge(source, dest, mask, alloctype, totelem); } -static void customData_free_layer__internal(CustomDataLayer *layer, int totelem) +void CustomData_copy_mesh_to_bmesh(const CustomData *source, + CustomData *dest, + const eCustomDataMask mask, + const eCDAllocType alloctype, + const int totelem) +{ + CustomData source_copy = shallow_copy_remove_non_bmesh_attributes(*source); + CustomData_copy(&source_copy, dest, mask, alloctype, totelem); + MEM_SAFE_FREE(source_copy.layers); +} + +static void customData_free_layer__internal(CustomDataLayer *layer, const int totelem) { const LayerTypeInfo *typeInfo; @@ -2383,7 +2477,7 @@ void CustomData_reset(CustomData *data) copy_vn_i(data->typemap, CD_NUMTYPES, -1); } -void CustomData_free(CustomData *data, int totelem) +void CustomData_free(CustomData *data, const int totelem) { for (int i = 0; i < data->totlayer; i++) { customData_free_layer__internal(&data->layers[i], totelem); @@ -2397,7 +2491,7 @@ void CustomData_free(CustomData *data, int totelem) CustomData_reset(data); } -void CustomData_free_typemask(CustomData *data, int totelem, eCustomDataMask mask) +void CustomData_free_typemask(CustomData *data, const int totelem, eCustomDataMask mask) { for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; @@ -2432,7 +2526,7 @@ static void customData_update_offsets(CustomData *data) } /* to use when we're in the middle of modifying layers */ -static int CustomData_get_layer_index__notypemap(const CustomData *data, int type) +static int CustomData_get_layer_index__notypemap(const CustomData *data, const int type) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2446,13 +2540,13 @@ static int CustomData_get_layer_index__notypemap(const CustomData *data, int typ /* -------------------------------------------------------------------- */ /* index values to access the layers (offset from the layer start) */ -int CustomData_get_layer_index(const CustomData *data, int type) +int CustomData_get_layer_index(const CustomData *data, const int type) { BLI_assert(customdata_typemap_is_valid(data)); return data->typemap[type]; } -int CustomData_get_layer_index_n(const CustomData *data, int type, int n) +int CustomData_get_layer_index_n(const CustomData *data, const int type, const int n) { BLI_assert(n >= 0); int i = CustomData_get_layer_index(data, type); @@ -2465,7 +2559,7 @@ int CustomData_get_layer_index_n(const CustomData *data, int type, int n) return i; } -int CustomData_get_named_layer_index(const CustomData *data, int type, const char *name) +int CustomData_get_named_layer_index(const CustomData *data, const int type, const char *name) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2478,28 +2572,28 @@ int CustomData_get_named_layer_index(const CustomData *data, int type, const cha return -1; } -int CustomData_get_active_layer_index(const CustomData *data, int type) +int CustomData_get_active_layer_index(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? layer_index + data->layers[layer_index].active : -1; } -int CustomData_get_render_layer_index(const CustomData *data, int type) +int CustomData_get_render_layer_index(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? layer_index + data->layers[layer_index].active_rnd : -1; } -int CustomData_get_clone_layer_index(const CustomData *data, int type) +int CustomData_get_clone_layer_index(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? layer_index + data->layers[layer_index].active_clone : -1; } -int CustomData_get_stencil_layer_index(const CustomData *data, int type) +int CustomData_get_stencil_layer_index(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2509,7 +2603,7 @@ int CustomData_get_stencil_layer_index(const CustomData *data, int type) /* -------------------------------------------------------------------- */ /* index values per layer type */ -int CustomData_get_named_layer(const CustomData *data, int type, const char *name) +int CustomData_get_named_layer(const CustomData *data, const int type, const char *name) { const int named_index = CustomData_get_named_layer_index(data, type, name); const int layer_index = data->typemap[type]; @@ -2517,28 +2611,28 @@ int CustomData_get_named_layer(const CustomData *data, int type, const char *nam return (named_index != -1) ? named_index - layer_index : -1; } -int CustomData_get_active_layer(const CustomData *data, int type) +int CustomData_get_active_layer(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? data->layers[layer_index].active : -1; } -int CustomData_get_render_layer(const CustomData *data, int type) +int CustomData_get_render_layer(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? data->layers[layer_index].active_rnd : -1; } -int CustomData_get_clone_layer(const CustomData *data, int type) +int CustomData_get_clone_layer(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); return (layer_index != -1) ? data->layers[layer_index].active_clone : -1; } -int CustomData_get_stencil_layer(const CustomData *data, int type) +int CustomData_get_stencil_layer(const CustomData *data, const int type) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2552,7 +2646,13 @@ const char *CustomData_get_active_layer_name(const CustomData *data, const int t return layer_index < 0 ? nullptr : data->layers[layer_index].name; } -void CustomData_set_layer_active(CustomData *data, int type, int n) +const char *CustomData_get_render_layer_name(const CustomData *data, const int type) +{ + const int layer_index = CustomData_get_render_layer_index(data, type); + return layer_index < 0 ? nullptr : data->layers[layer_index].name; +} + +void CustomData_set_layer_active(CustomData *data, const int type, const int n) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2561,7 +2661,7 @@ void CustomData_set_layer_active(CustomData *data, int type, int n) } } -void CustomData_set_layer_render(CustomData *data, int type, int n) +void CustomData_set_layer_render(CustomData *data, const int type, const int n) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2570,7 +2670,7 @@ void CustomData_set_layer_render(CustomData *data, int type, int n) } } -void CustomData_set_layer_clone(CustomData *data, int type, int n) +void CustomData_set_layer_clone(CustomData *data, const int type, const int n) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2579,7 +2679,7 @@ void CustomData_set_layer_clone(CustomData *data, int type, int n) } } -void CustomData_set_layer_stencil(CustomData *data, int type, int n) +void CustomData_set_layer_stencil(CustomData *data, const int type, const int n) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2588,7 +2688,7 @@ void CustomData_set_layer_stencil(CustomData *data, int type, int n) } } -void CustomData_set_layer_active_index(CustomData *data, int type, int n) +void CustomData_set_layer_active_index(CustomData *data, const int type, const int n) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2600,7 +2700,7 @@ void CustomData_set_layer_active_index(CustomData *data, int type, int n) } } -void CustomData_set_layer_render_index(CustomData *data, int type, int n) +void CustomData_set_layer_render_index(CustomData *data, const int type, const int n) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2612,7 +2712,7 @@ void CustomData_set_layer_render_index(CustomData *data, int type, int n) } } -void CustomData_set_layer_clone_index(CustomData *data, int type, int n) +void CustomData_set_layer_clone_index(CustomData *data, const int type, const int n) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2624,7 +2724,7 @@ void CustomData_set_layer_clone_index(CustomData *data, int type, int n) } } -void CustomData_set_layer_stencil_index(CustomData *data, int type, int n) +void CustomData_set_layer_stencil_index(CustomData *data, const int type, const int n) { const int layer_index = data->typemap[type]; BLI_assert(customdata_typemap_is_valid(data)); @@ -2636,7 +2736,7 @@ void CustomData_set_layer_stencil_index(CustomData *data, int type, int n) } } -void CustomData_set_layer_flag(CustomData *data, int type, int flag) +void CustomData_set_layer_flag(CustomData *data, const int type, const int flag) { for (int i = 0; i < data->totlayer; i++) { if (data->layers[i].type == type) { @@ -2645,7 +2745,7 @@ void CustomData_set_layer_flag(CustomData *data, int type, int flag) } } -void CustomData_clear_layer_flag(CustomData *data, int type, int flag) +void CustomData_clear_layer_flag(CustomData *data, const int type, const int flag) { const int nflag = ~flag; @@ -2656,7 +2756,7 @@ void CustomData_clear_layer_flag(CustomData *data, int type, int flag) } } -static bool customData_resize(CustomData *data, int amount) +static bool customData_resize(CustomData *data, const int amount) { CustomDataLayer *tmp = static_cast<CustomDataLayer *>( MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp), __func__)); @@ -2675,59 +2775,72 @@ static bool customData_resize(CustomData *data, int amount) } static CustomDataLayer *customData_add_layer__internal(CustomData *data, - int type, - eCDAllocType alloctype, + const int type, + const eCDAllocType alloctype, void *layerdata, - int totelem, + const int totelem, const char *name) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); - int flag = 0, index = data->totlayer; - void *newlayerdata = nullptr; - - /* Passing a layer-data to copy from with an alloctype that won't copy is - * most likely a bug */ - BLI_assert(!layerdata || ELEM(alloctype, CD_ASSIGN, CD_DUPLICATE, CD_REFERENCE)); + int flag = 0; if (!typeInfo->defaultname && CustomData_has_layer(data, type)) { return &data->layers[CustomData_get_layer_index(data, type)]; } - if (ELEM(alloctype, CD_ASSIGN, CD_REFERENCE)) { - newlayerdata = layerdata; - } - else if (totelem > 0 && typeInfo->size > 0) { - if (alloctype == CD_DUPLICATE && layerdata) { - newlayerdata = MEM_malloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type)); - } - else { - newlayerdata = MEM_calloc_arrayN((size_t)totelem, typeInfo->size, layerType_getName(type)); - } - - if (!newlayerdata) { - return nullptr; - } - } - - if (alloctype == CD_DUPLICATE && layerdata) { - if (totelem > 0) { - if (typeInfo->copy) { - typeInfo->copy(layerdata, newlayerdata, totelem); + void *newlayerdata = nullptr; + switch (alloctype) { + case CD_SET_DEFAULT: + if (totelem > 0) { + if (typeInfo->set_default_value) { + newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + typeInfo->set_default_value(newlayerdata, totelem); + } + else { + newlayerdata = MEM_calloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + } + } + break; + case CD_CONSTRUCT: + if (totelem > 0) { + newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + if (typeInfo->construct) { + typeInfo->construct(newlayerdata, totelem); + } + } + break; + case CD_ASSIGN: + if (totelem > 0) { + BLI_assert(layerdata != nullptr); + newlayerdata = layerdata; } else { - memcpy(newlayerdata, layerdata, (size_t)totelem * typeInfo->size); + MEM_SAFE_FREE(layerdata); } - } - } - else if (alloctype == CD_DEFAULT) { - if (typeInfo->set_default) { - typeInfo->set_default(newlayerdata, totelem); - } - } - else if (alloctype == CD_REFERENCE) { - flag |= CD_FLAG_NOFREE; + break; + case CD_REFERENCE: + if (totelem > 0) { + BLI_assert(layerdata != nullptr); + newlayerdata = layerdata; + flag |= CD_FLAG_NOFREE; + } + break; + case CD_DUPLICATE: + if (totelem > 0) { + newlayerdata = MEM_malloc_arrayN(totelem, typeInfo->size, layerType_getName(type)); + if (typeInfo->copy) { + typeInfo->copy(layerdata, newlayerdata, totelem); + } + else { + BLI_assert(layerdata != nullptr); + BLI_assert(newlayerdata != nullptr); + memcpy(newlayerdata, layerdata, totelem * typeInfo->size); + } + } + break; } + int index = data->totlayer; if (index >= data->maxlayer) { if (!customData_resize(data, CUSTOMDATA_GROW)) { if (newlayerdata != layerdata) { @@ -2744,14 +2857,16 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, data->layers[index] = data->layers[index - 1]; } + CustomDataLayer &new_layer = data->layers[index]; + /* Clear remaining data on the layer. The original data on the layer has been moved to another * index. Without this, it can happen that information from the previous layer at that index * leaks into the new layer. */ - memset(data->layers + index, 0, sizeof(CustomDataLayer)); + memset(&new_layer, 0, sizeof(CustomDataLayer)); - data->layers[index].type = type; - data->layers[index].flag = flag; - data->layers[index].data = newlayerdata; + new_layer.type = type; + new_layer.flag = flag; + new_layer.data = newlayerdata; /* Set default name if none exists. Note we only call DATA_() once * we know there is a default name, to avoid overhead of locale lookups @@ -2761,24 +2876,24 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, } if (name) { - BLI_strncpy(data->layers[index].name, name, sizeof(data->layers[index].name)); + BLI_strncpy(new_layer.name, name, sizeof(new_layer.name)); CustomData_set_layer_unique_name(data, index); } else { - data->layers[index].name[0] = '\0'; + new_layer.name[0] = '\0'; } if (index > 0 && data->layers[index - 1].type == type) { - data->layers[index].active = data->layers[index - 1].active; - data->layers[index].active_rnd = data->layers[index - 1].active_rnd; - data->layers[index].active_clone = data->layers[index - 1].active_clone; - data->layers[index].active_mask = data->layers[index - 1].active_mask; + new_layer.active = data->layers[index - 1].active; + new_layer.active_rnd = data->layers[index - 1].active_rnd; + new_layer.active_clone = data->layers[index - 1].active_clone; + new_layer.active_mask = data->layers[index - 1].active_mask; } else { - data->layers[index].active = 0; - data->layers[index].active_rnd = 0; - data->layers[index].active_clone = 0; - data->layers[index].active_mask = 0; + new_layer.active = 0; + new_layer.active_rnd = 0; + new_layer.active_clone = 0; + new_layer.active_mask = 0; } customData_update_offsets(data); @@ -2787,7 +2902,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, } void *CustomData_add_layer( - CustomData *data, int type, eCDAllocType alloctype, void *layerdata, int totelem) + CustomData *data, const int type, eCDAllocType alloctype, void *layerdata, const int totelem) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -2803,10 +2918,10 @@ void *CustomData_add_layer( } void *CustomData_add_layer_named(CustomData *data, - int type, - eCDAllocType alloctype, + const int type, + const eCDAllocType alloctype, void *layerdata, - int totelem, + const int totelem, const char *name) { CustomDataLayer *layer = customData_add_layer__internal( @@ -2821,10 +2936,10 @@ void *CustomData_add_layer_named(CustomData *data, } void *CustomData_add_layer_anonymous(CustomData *data, - int type, - eCDAllocType alloctype, + const int type, + const eCDAllocType alloctype, void *layerdata, - int totelem, + const int totelem, const AnonymousAttributeID *anonymous_id) { const char *name = BKE_anonymous_attribute_id_internal_name(anonymous_id); @@ -2841,7 +2956,7 @@ void *CustomData_add_layer_anonymous(CustomData *data, return layer->data; } -bool CustomData_free_layer(CustomData *data, int type, int totelem, int index) +bool CustomData_free_layer(CustomData *data, const int type, const int totelem, const int index) { const int index_first = CustomData_get_layer_index(data, type); const int n = index - index_first; @@ -2905,7 +3020,7 @@ bool CustomData_free_layer_named(CustomData *data, const char *name, const int t return false; } -bool CustomData_free_layer_active(CustomData *data, int type, int totelem) +bool CustomData_free_layer_active(CustomData *data, const int type, const int totelem) { const int index = CustomData_get_active_layer_index(data, type); if (index == -1) { @@ -2914,7 +3029,7 @@ bool CustomData_free_layer_active(CustomData *data, int type, int totelem) return CustomData_free_layer(data, type, totelem, index); } -void CustomData_free_layers(CustomData *data, int type, int totelem) +void CustomData_free_layers(CustomData *data, const int type, const int totelem) { const int index = CustomData_get_layer_index(data, type); while (CustomData_free_layer(data, type, totelem, index)) { @@ -2922,12 +3037,12 @@ void CustomData_free_layers(CustomData *data, int type, int totelem) } } -bool CustomData_has_layer(const CustomData *data, int type) +bool CustomData_has_layer(const CustomData *data, const int type) { return (CustomData_get_layer_index(data, type) != -1); } -int CustomData_number_of_layers(const CustomData *data, int type) +int CustomData_number_of_layers(const CustomData *data, const int type) { int number = 0; @@ -2940,7 +3055,7 @@ int CustomData_number_of_layers(const CustomData *data, int type) return number; } -int CustomData_number_of_layers_typemask(const CustomData *data, eCustomDataMask mask) +int CustomData_number_of_layers_typemask(const CustomData *data, const eCustomDataMask mask) { int number = 0; @@ -3030,7 +3145,7 @@ void *CustomData_duplicate_referenced_layer_anonymous(CustomData *data, return nullptr; } -void CustomData_duplicate_referenced_layers(CustomData *data, int totelem) +void CustomData_duplicate_referenced_layers(CustomData *data, const int totelem) { for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; @@ -3038,7 +3153,7 @@ void CustomData_duplicate_referenced_layers(CustomData *data, int totelem) } } -bool CustomData_is_referenced_layer(CustomData *data, int type) +bool CustomData_is_referenced_layer(CustomData *data, const int type) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3051,7 +3166,7 @@ bool CustomData_is_referenced_layer(CustomData *data, int type) return (layer->flag & CD_FLAG_NOFREE) != 0; } -void CustomData_free_temporary(CustomData *data, int totelem) +void CustomData_free_temporary(CustomData *data, const int totelem) { int i, j; bool changed = false; @@ -3083,7 +3198,7 @@ void CustomData_free_temporary(CustomData *data, int totelem) } } -void CustomData_set_only_copy(const CustomData *data, eCustomDataMask mask) +void CustomData_set_only_copy(const CustomData *data, const eCustomDataMask mask) { for (int i = 0; i < data->totlayer; i++) { if (!(mask & CD_TYPE_AS_MASK(data->layers[i].type))) { @@ -3092,7 +3207,10 @@ void CustomData_set_only_copy(const CustomData *data, eCustomDataMask mask) } } -void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, int count) +void CustomData_copy_elements(const int type, + void *src_data_ofs, + void *dst_data_ofs, + const int count) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -3106,11 +3224,11 @@ void CustomData_copy_elements(int type, void *src_data_ofs, void *dst_data_ofs, void CustomData_copy_data_layer(const CustomData *source, CustomData *dest, - int src_layer_index, - int dst_layer_index, - int src_index, - int dst_index, - int count) + const int src_layer_index, + const int dst_layer_index, + const int src_index, + const int dst_index, + const int count) { const LayerTypeInfo *typeInfo; @@ -3144,8 +3262,11 @@ void CustomData_copy_data_layer(const CustomData *source, } } -void CustomData_copy_data_named( - const CustomData *source, CustomData *dest, int source_index, int dest_index, int count) +void CustomData_copy_data_named(const CustomData *source, + CustomData *dest, + const int source_index, + const int dest_index, + const int count) { /* copies a layer at a time */ for (int src_i = 0; src_i < source->totlayer; src_i++) { @@ -3160,8 +3281,11 @@ void CustomData_copy_data_named( } } -void CustomData_copy_data( - const CustomData *source, CustomData *dest, int source_index, int dest_index, int count) +void CustomData_copy_data(const CustomData *source, + CustomData *dest, + const int source_index, + const int dest_index, + const int count) { /* copies a layer at a time */ int dest_i = 0; @@ -3216,7 +3340,7 @@ void CustomData_copy_layer_type_data(const CustomData *source, count); } -void CustomData_free_elem(CustomData *data, int index, int count) +void CustomData_free_elem(CustomData *data, const int index, const int count) { for (int i = 0; i < data->totlayer; i++) { if (!(data->layers[i].flag & CD_FLAG_NOFREE)) { @@ -3316,7 +3440,7 @@ void CustomData_interp(const CustomData *source, } } -void CustomData_swap_corners(CustomData *data, int index, const int *corner_indices) +void CustomData_swap_corners(CustomData *data, const int index, const int *corner_indices) { for (int i = 0; i < data->totlayer; i++) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[i].type); @@ -3356,7 +3480,7 @@ void CustomData_swap(CustomData *data, const int index_a, const int index_b) } } -void *CustomData_get(const CustomData *data, int index, int type) +void *CustomData_get(const CustomData *data, const int index, const int type) { BLI_assert(index >= 0); @@ -3372,7 +3496,7 @@ void *CustomData_get(const CustomData *data, int index, int type) return POINTER_OFFSET(data->layers[layer_index].data, offset); } -void *CustomData_get_n(const CustomData *data, int type, int index, int n) +void *CustomData_get_n(const CustomData *data, const int type, const int index, const int n) { BLI_assert(index >= 0 && n >= 0); @@ -3386,7 +3510,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n) return POINTER_OFFSET(data->layers[layer_index + n].data, offset); } -void *CustomData_get_layer(const CustomData *data, int type) +void *CustomData_get_layer(const CustomData *data, const int type) { /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3397,7 +3521,7 @@ void *CustomData_get_layer(const CustomData *data, int type) return data->layers[layer_index].data; } -void *CustomData_get_layer_n(const CustomData *data, int type, int n) +void *CustomData_get_layer_n(const CustomData *data, const int type, const int n) { /* get the layer index of the active layer of type */ int layer_index = CustomData_get_layer_index_n(data, type, n); @@ -3408,7 +3532,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n) return data->layers[layer_index].data; } -void *CustomData_get_layer_named(const CustomData *data, int type, const char *name) +void *CustomData_get_layer_named(const CustomData *data, const int type, const char *name) { int layer_index = CustomData_get_named_layer_index(data, type, name); if (layer_index == -1) { @@ -3418,7 +3542,7 @@ void *CustomData_get_layer_named(const CustomData *data, int type, const char *n return data->layers[layer_index].data; } -int CustomData_get_offset(const CustomData *data, int type) +int CustomData_get_offset(const CustomData *data, const int type) { /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3429,10 +3553,10 @@ int CustomData_get_offset(const CustomData *data, int type) return data->layers[layer_index].offset; } -int CustomData_get_offset_named(const CustomData *data, int type, const char *name) +int CustomData_get_n_offset(const CustomData *data, const int type, const int n) { /* get the layer index of the active layer of type */ - int layer_index = CustomData_get_named_layer_index(data, type, name); + int layer_index = CustomData_get_layer_index_n(data, type, n); if (layer_index == -1) { return -1; } @@ -3440,10 +3564,9 @@ int CustomData_get_offset_named(const CustomData *data, int type, const char *na return data->layers[layer_index].offset; } -int CustomData_get_n_offset(const CustomData *data, int type, int n) +int CustomData_get_offset_named(const CustomData *data, int type, const char *name) { - /* get the layer index of the active layer of type */ - int layer_index = CustomData_get_layer_index_n(data, type, n); + int layer_index = CustomData_get_named_layer_index(data, type, name); if (layer_index == -1) { return -1; } @@ -3451,7 +3574,7 @@ int CustomData_get_n_offset(const CustomData *data, int type, int n) return data->layers[layer_index].offset; } -bool CustomData_set_layer_name(const CustomData *data, int type, int n, const char *name) +bool CustomData_set_layer_name(CustomData *data, const int type, const int n, const char *name) { /* get the layer index of the first layer of type */ const int layer_index = CustomData_get_layer_index_n(data, type, n); @@ -3465,14 +3588,14 @@ bool CustomData_set_layer_name(const CustomData *data, int type, int n, const ch return true; } -const char *CustomData_get_layer_name(const CustomData *data, int type, int n) +const char *CustomData_get_layer_name(const CustomData *data, const int type, const int n) { const int layer_index = CustomData_get_layer_index_n(data, type, n); return (layer_index == -1) ? nullptr : data->layers[layer_index].name; } -void *CustomData_set_layer(const CustomData *data, int type, void *ptr) +void *CustomData_set_layer(const CustomData *data, const int type, void *ptr) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3486,7 +3609,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr) return ptr; } -void *CustomData_set_layer_n(const CustomData *data, int type, int n, void *ptr) +void *CustomData_set_layer_n(const CustomData *data, const int type, const int n, void *ptr) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_layer_index_n(data, type, n); @@ -3499,7 +3622,7 @@ void *CustomData_set_layer_n(const CustomData *data, int type, int n, void *ptr) return ptr; } -void CustomData_set(const CustomData *data, int index, int type, const void *source) +void CustomData_set(const CustomData *data, const int index, const int type, const void *source) { void *dest = CustomData_get(data, index, type); const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -3551,7 +3674,7 @@ void CustomData_bmesh_update_active_layers(CustomData *fdata, CustomData *ldata) } } -void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype) +void CustomData_bmesh_init_pool(CustomData *data, const int totelem, const char htype) { int chunksize; @@ -3753,13 +3876,13 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data, } } -static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n) +static void CustomData_bmesh_set_default_n(CustomData *data, void **block, const int n) { int offset = data->layers[n].offset; const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); - if (typeInfo->set_default) { - typeInfo->set_default(POINTER_OFFSET(*block, offset), 1); + if (typeInfo->set_default_value) { + typeInfo->set_default_value(POINTER_OFFSET(*block, offset), 1); } else { memset(POINTER_OFFSET(*block, offset), 0, typeInfo->size); @@ -3848,7 +3971,7 @@ void CustomData_bmesh_copy_data(const CustomData *source, CustomData_bmesh_copy_data_exclude_by_type(source, dest, src_block, dest_block, 0); } -void *CustomData_bmesh_get(const CustomData *data, void *block, int type) +void *CustomData_bmesh_get(const CustomData *data, void *block, const int type) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); @@ -3859,7 +3982,7 @@ void *CustomData_bmesh_get(const CustomData *data, void *block, int type) return POINTER_OFFSET(block, data->layers[layer_index].offset); } -void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int n) +void *CustomData_bmesh_get_n(const CustomData *data, void *block, const int type, const int n) { /* get the layer index of the first layer of type */ int layer_index = CustomData_get_layer_index(data, type); @@ -3870,7 +3993,7 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int return POINTER_OFFSET(block, data->layers[layer_index + n].offset); } -void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n) +void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, const int n) { if (n < 0 || n >= data->totlayer) { return nullptr; @@ -3879,7 +4002,7 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n) return POINTER_OFFSET(block, data->layers[n].offset); } -bool CustomData_layer_has_math(const CustomData *data, int layer_n) +bool CustomData_layer_has_math(const CustomData *data, const int layer_n) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type); @@ -3891,7 +4014,7 @@ bool CustomData_layer_has_math(const CustomData *data, int layer_n) return false; } -bool CustomData_layer_has_interp(const CustomData *data, int layer_n) +bool CustomData_layer_has_interp(const CustomData *data, const int layer_n) { const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type); @@ -4012,7 +4135,7 @@ void CustomData_data_dominmax(int type, const void *data, void *min, void *max) } } -void CustomData_data_multiply(int type, void *data, float fac) +void CustomData_data_multiply(int type, void *data, const float fac) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -4030,7 +4153,7 @@ void CustomData_data_add(int type, void *data1, const void *data2) } } -void CustomData_bmesh_set(const CustomData *data, void *block, int type, const void *source) +void CustomData_bmesh_set(const CustomData *data, void *block, const int type, const void *source) { void *dest = CustomData_bmesh_get(data, block, type); const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -4047,7 +4170,8 @@ void CustomData_bmesh_set(const CustomData *data, void *block, int type, const v } } -void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, const void *source) +void CustomData_bmesh_set_n( + CustomData *data, void *block, const int type, const int n, const void *source) { void *dest = CustomData_bmesh_get_n(data, block, type, n); const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -4064,7 +4188,7 @@ void CustomData_bmesh_set_n(CustomData *data, void *block, int type, int n, cons } } -void CustomData_bmesh_set_layer_n(CustomData *data, void *block, int n, const void *source) +void CustomData_bmesh_set_layer_n(CustomData *data, void *block, const int n, const void *source) { void *dest = CustomData_bmesh_get_layer_n(data, block, n); const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); @@ -4263,7 +4387,9 @@ void CustomData_file_write_info(int type, const char **r_struct_name, int *r_str *r_struct_num = typeInfo->structnum; } -void CustomData_blend_write_prepare(CustomData &data, Vector<CustomDataLayer, 16> &layers_to_write) +void CustomData_blend_write_prepare(CustomData &data, + Vector<CustomDataLayer, 16> &layers_to_write, + const Set<std::string> &skip_names) { for (const CustomDataLayer &layer : Span(data.layers, data.totlayer)) { if (layer.flag & CD_FLAG_NOCOPY) { @@ -4272,6 +4398,9 @@ void CustomData_blend_write_prepare(CustomData &data, Vector<CustomDataLayer, 16 if (layer.anonymous_id != nullptr) { continue; } + if (skip_names.contains(layer.name)) { + continue; + } layers_to_write.append(layer); } data.totlayer = layers_to_write.size(); @@ -4318,7 +4447,7 @@ int CustomData_layertype_layers_max(const int type) return typeInfo->layers_max(); } -static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int index) +static bool cd_layer_find_dupe(CustomData *data, const char *name, const int type, const int index) { /* see if there is a duplicate */ for (int i = 0; i < data->totlayer; i++) { @@ -4353,7 +4482,7 @@ static bool customdata_unique_check(void *arg, const char *name) return cd_layer_find_dupe(data_arg->data, name, data_arg->type, data_arg->index); } -void CustomData_set_layer_unique_name(CustomData *data, int index) +void CustomData_set_layer_unique_name(CustomData *data, const int index) { CustomDataLayer *nlayer = &data->layers[index]; const LayerTypeInfo *typeInfo = layerType_getInfo(nlayer->type); @@ -4398,7 +4527,7 @@ void CustomData_validate_layer_name(const CustomData *data, } } -bool CustomData_verify_versions(CustomData *data, int index) +bool CustomData_verify_versions(CustomData *data, const int index) { const LayerTypeInfo *typeInfo; CustomDataLayer *layer = &data->layers[index]; @@ -4460,8 +4589,8 @@ static bool CustomData_layer_ensure_data_exists(CustomDataLayer *layer, size_t c case CD_MLOOPUV: /* See T90620. */ layer->data = MEM_calloc_arrayN(count, typeInfo->size, layerType_getName(layer->type)); BLI_assert(layer->data); - if (typeInfo->set_default) { - typeInfo->set_default(layer->data, count); + if (typeInfo->set_default_value) { + typeInfo->set_default_value(layer->data, count); } return true; break; @@ -4557,7 +4686,7 @@ void CustomData_external_reload(CustomData *data, } } -void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, int totelem) +void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, const int totelem) { CustomDataExternal *external = data->external; CustomDataLayer *layer; @@ -4631,7 +4760,7 @@ void CustomData_external_read(CustomData *data, ID *id, eCustomDataMask mask, in } void CustomData_external_write( - CustomData *data, ID *id, eCustomDataMask mask, int totelem, int free) + CustomData *data, ID *id, eCustomDataMask mask, const int totelem, const int free) { CustomDataExternal *external = data->external; int update = 0; @@ -4733,8 +4862,11 @@ void CustomData_external_write( cdf_free(cdf); } -void CustomData_external_add( - CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filepath) +void CustomData_external_add(CustomData *data, + ID *UNUSED(id), + const int type, + const int UNUSED(totelem), + const char *filepath) { CustomDataExternal *external = data->external; @@ -4758,7 +4890,7 @@ void CustomData_external_add( layer->flag |= CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY; } -void CustomData_external_remove(CustomData *data, ID *id, int type, int totelem) +void CustomData_external_remove(CustomData *data, ID *id, const int type, const int totelem) { CustomDataExternal *external = data->external; @@ -4782,7 +4914,7 @@ void CustomData_external_remove(CustomData *data, ID *id, int type, int totelem) } } -bool CustomData_external_test(CustomData *data, int type) +bool CustomData_external_test(CustomData *data, const int type) { int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { @@ -5083,7 +5215,10 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, /** \name Custom Data IO * \{ */ -static void write_mdisps(BlendWriter *writer, int count, const MDisps *mdlist, int external) +static void write_mdisps(BlendWriter *writer, + const int count, + const MDisps *mdlist, + const int external) { if (mdlist) { BLO_write_struct_array(writer, MDisps, count, mdlist); @@ -5183,7 +5318,10 @@ void CustomData_blend_write(BlendWriter *writer, } } -static void blend_read_mdisps(BlendDataReader *reader, int count, MDisps *mdisps, int external) +static void blend_read_mdisps(BlendDataReader *reader, + const int count, + MDisps *mdisps, + const int external) { if (mdisps) { for (int i = 0; i < count; i++) { @@ -5225,7 +5363,7 @@ static void blend_read_paint_mask(BlendDataReader *reader, } } -void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count) +void CustomData_blend_read(BlendDataReader *reader, CustomData *data, const int count) { BLO_read_data_address(reader, &data->layers); diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 17a74b5564a..02b5175f65f 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -70,8 +70,6 @@ void BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types, r_data_masks->lmask |= CD_MASK_MLOOPUV; } else if (cddata_type == CD_FAKE_LNOR) { - r_data_masks->vmask |= CD_MASK_NORMAL; - r_data_masks->pmask |= CD_MASK_NORMAL; r_data_masks->lmask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL; } } @@ -282,7 +280,8 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src, loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL); const bool do_loop_nors_dst = (loop_nors_dst == NULL); if (do_loop_nors_dst) { - loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst); + loop_nors_dst = CustomData_add_layer( + ldata_dst, CD_NORMAL, CD_SET_DEFAULT, NULL, num_loops_dst); CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } if (dirty_nors_dst || do_loop_nors_dst) { @@ -335,7 +334,7 @@ static void data_transfer_dtdata_type_postprocess(Object *UNUSED(ob_src), if (!custom_nors_dst) { custom_nors_dst = CustomData_add_layer( - ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst); + ldata_dst, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, NULL, num_loops_dst); } /* Note loop_nors_dst contains our custom normals as transferred from source... */ @@ -563,7 +562,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map if (use_create) { /* Create as much data layers as necessary! */ for (; idx_dst < idx_src; idx_dst++) { - CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } } else { @@ -624,7 +623,8 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) { if (use_create) { - CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); + CustomData_add_layer_named( + cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } else { @@ -712,7 +712,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } else if (use_dupref_dst && r_map) { /* If dest is a evaluated mesh (from modifier), @@ -765,7 +765,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } else { /* If dest is a evaluated mesh (from modifier), @@ -788,7 +788,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, } /* Create as much data layers as necessary! */ for (; num <= idx_dst; num++) { - CustomData_add_layer(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst); + CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst); } } /* If dest is a evaluated mesh (from modifier), @@ -807,7 +807,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - CustomData_add_layer_named(cd_dst, cddata_type, CD_CALLOC, NULL, num_elem_dst, name); + CustomData_add_layer_named(cd_dst, cddata_type, CD_SET_DEFAULT, NULL, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } /* If dest is a evaluated mesh (from modifier), diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index ebe06fa85eb..d904744995d 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -1243,7 +1243,8 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * Again, use_create is not relevant in this case */ if (!data_dst) { - data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, num_elem_dst); } while (idx_src--) { @@ -1303,7 +1304,8 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { - data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, num_elem_dst); } data_transfer_layersmapping_add_item(r_map, @@ -1442,7 +1444,8 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { - data_dst = CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_CALLOC, NULL, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, num_elem_dst); } data_transfer_layersmapping_add_item(r_map, diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc index 823fce52b50..b87d675496c 100644 --- a/source/blender/blenkernel/intern/displist.cc +++ b/source/blender/blenkernel/intern/displist.cc @@ -34,10 +34,8 @@ #include "BKE_displist.h" #include "BKE_geometry_set.hh" #include "BKE_key.h" -#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_mball.h" -#include "BKE_mball_tessellate.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -86,133 +84,6 @@ DispList *BKE_displist_find(ListBase *lb, int type) return nullptr; } -void BKE_displist_copy(ListBase *lbn, const ListBase *lb) -{ - BKE_displist_free(lbn); - - LISTBASE_FOREACH (const DispList *, dl, lb) { - DispList *dln = (DispList *)MEM_dupallocN(dl); - BLI_addtail(lbn, dln); - dln->verts = (float *)MEM_dupallocN(dl->verts); - dln->nors = (float *)MEM_dupallocN(dl->nors); - dln->index = (int *)MEM_dupallocN(dl->index); - } -} - -void BKE_displist_normals_add(ListBase *lb) -{ - float *vdata, *ndata, nor[3]; - float *v1, *v2, *v3, *v4; - float *n1, *n2, *n3, *n4; - int a, b, p1, p2, p3, p4; - - LISTBASE_FOREACH (DispList *, dl, lb) { - if (dl->type == DL_INDEX3) { - if (dl->nors == nullptr) { - dl->nors = (float *)MEM_callocN(sizeof(float[3]), __func__); - - if (dl->flag & DL_BACK_CURVE) { - dl->nors[2] = -1.0f; - } - else { - dl->nors[2] = 1.0f; - } - } - } - else if (dl->type == DL_SURF) { - if (dl->nors == nullptr) { - dl->nors = (float *)MEM_callocN(sizeof(float[3]) * dl->nr * dl->parts, __func__); - - vdata = dl->verts; - ndata = dl->nors; - - for (a = 0; a < dl->parts; a++) { - - if (BKE_displist_surfindex_get(dl, a, &b, &p1, &p2, &p3, &p4) == 0) { - break; - } - - v1 = vdata + 3 * p1; - n1 = ndata + 3 * p1; - v2 = vdata + 3 * p2; - n2 = ndata + 3 * p2; - v3 = vdata + 3 * p3; - n3 = ndata + 3 * p3; - v4 = vdata + 3 * p4; - n4 = ndata + 3 * p4; - - for (; b < dl->nr; b++) { - normal_quad_v3(nor, v1, v3, v4, v2); - - add_v3_v3(n1, nor); - add_v3_v3(n2, nor); - add_v3_v3(n3, nor); - add_v3_v3(n4, nor); - - v2 = v1; - v1 += 3; - v4 = v3; - v3 += 3; - n2 = n1; - n1 += 3; - n4 = n3; - n3 += 3; - } - } - a = dl->parts * dl->nr; - v1 = ndata; - while (a--) { - normalize_v3(v1); - v1 += 3; - } - } - } - } -} - -void BKE_displist_count(const ListBase *lb, int *totvert, int *totface, int *tottri) -{ - LISTBASE_FOREACH (const DispList *, dl, lb) { - int vert_tot = 0; - int face_tot = 0; - int tri_tot = 0; - bool cyclic_u = dl->flag & DL_CYCL_U; - bool cyclic_v = dl->flag & DL_CYCL_V; - - switch (dl->type) { - case DL_SURF: { - int segments_u = dl->nr - (cyclic_u == false); - int segments_v = dl->parts - (cyclic_v == false); - vert_tot = dl->nr * dl->parts; - face_tot = segments_u * segments_v; - tri_tot = face_tot * 2; - break; - } - case DL_INDEX3: { - vert_tot = dl->nr; - face_tot = dl->parts; - tri_tot = face_tot; - break; - } - case DL_INDEX4: { - vert_tot = dl->nr; - face_tot = dl->parts; - tri_tot = face_tot * 2; - break; - } - case DL_POLY: - case DL_SEGM: { - vert_tot = dl->nr * dl->parts; - break; - } - } - - *totvert += vert_tot; - *totface += face_tot; - *tottri += tri_tot; - } -} - bool BKE_displist_surfindex_get( const DispList *dl, int a, int *b, int *p1, int *p2, int *p3, int *p4) { @@ -243,7 +114,6 @@ bool BKE_displist_surfindex_get( return true; } -/* ****************** Make #DispList ********************* */ #ifdef __INTEL_COMPILER /* ICC with the optimization -02 causes crashes. */ # pragma intel optimization_level 1 @@ -638,27 +508,6 @@ float BKE_displist_calc_taper( return displist_calc_taper(depsgraph, scene, taperobj, fac); } -void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob) -{ - if (!ob || ob->type != OB_MBALL) { - return; - } - - if (ob == BKE_mball_basis_find(scene, ob)) { - if (ob->runtime.curve_cache) { - BKE_displist_free(&(ob->runtime.curve_cache->disp)); - } - else { - ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__); - } - - BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp); - BKE_mball_texspace_calc(ob); - - object_deform_mball(ob, &ob->runtime.curve_cache->disp); - } -} - static ModifierData *curve_get_tessellate_point(const Scene *scene, const Object *ob, const bool for_render, @@ -1493,7 +1342,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph, * - The dependency graph has handling of edit mode pointers (see #update_edit_mode_pointers) * but it doesn't seem to work in this case. * - * Since the the plan is to replace this legacy curve object with the curves data-block + * Since the plan is to replace this legacy curve object with the curves data-block * (see T95355), this somewhat hacky inefficient solution is relatively temporary. */ Curve &cow_curve = *reinterpret_cast<Curve *>( @@ -1514,20 +1363,19 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph, void BKE_displist_minmax(const ListBase *dispbase, float min[3], float max[3]) { - bool doit = false; + bool empty = true; LISTBASE_FOREACH (const DispList *, dl, dispbase) { - const int tot = (ELEM(dl->type, DL_INDEX3, DL_INDEX4)) ? dl->nr : dl->nr * dl->parts; + const int tot = dl->type == DL_INDEX3 ? dl->nr : dl->nr * dl->parts; for (const int i : IndexRange(tot)) { minmax_v3v3_v3(min, max, &dl->verts[i * 3]); } if (tot != 0) { - doit = true; + empty = false; } } - if (!doit) { - /* there's no geometry in displist, use zero-sized boundbox */ + if (empty) { zero_v3(min); zero_v3(max); } diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 423e76fce8c..8a41b2294f5 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1944,7 +1944,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) { mloopcol = CustomData_add_layer_named(&result->ldata, CD_PROP_BYTE_COLOR, - CD_CALLOC, + CD_SET_DEFAULT, NULL, totloop, surface->output_name); @@ -1957,7 +1957,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) { mloopcol_wet = CustomData_add_layer_named(&result->ldata, CD_PROP_BYTE_COLOR, - CD_CALLOC, + CD_SET_DEFAULT, NULL, totloop, surface->output_name2); @@ -1988,7 +1988,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * /* apply weights into a vertex group, if doesn't exists add a new layer */ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) { dvert = CustomData_add_layer( - &result->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, sData->total_points); + &result->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, sData->total_points); /* Make the dvert layer easily accessible from the mesh data. */ result->dvert = dvert; } diff --git a/source/blender/blenkernel/intern/editmesh_tangent.c b/source/blender/blenkernel/intern/editmesh_tangent.c index 0a3107eee24..ec608f79e66 100644 --- a/source/blender/blenkernel/intern/editmesh_tangent.c +++ b/source/blender/blenkernel/intern/editmesh_tangent.c @@ -304,7 +304,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1) { CustomData_add_layer_named( - loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, ""); + loopdata_out, CD_TANGENT, CD_SET_DEFAULT, NULL, (int)loopdata_out_len, ""); } if (calc_act && act_uv_name[0]) { BKE_mesh_add_loop_tangent_named_layer_for_uv( diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 0fc09803088..57b84575c84 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -3247,7 +3247,8 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, mp_example = *mpoly; } - const short mp_mat_nr = mp_example.mat_nr; + const int *orig_material_indices = BKE_mesh_material_indices(orgmesh); + const short mp_mat_nr = orig_material_indices ? orig_material_indices[0] : 0; const char mp_flag = mp_example.flag; int i; @@ -3358,10 +3359,12 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, } } + int *material_indices = BKE_mesh_material_indices_for_write(me); + /* Loop for triangles. */ for (i = 0; i < num_faces; i++, mpolys++, mloops += 3) { /* Initialize from existing face. */ - mpolys->mat_nr = mp_mat_nr; + material_indices[i] = mp_mat_nr; mpolys->flag = mp_flag; mpolys->loopstart = i * 3; diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index 22f105af0f1..56a7e38b2fc 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -547,7 +547,8 @@ static GVArray varray_from_initializer(const AttributeInit &initializer, const Span<SplinePtr> splines) { switch (initializer.type) { - case AttributeInit::Type::Default: + case AttributeInit::Type::Construct: + case AttributeInit::Type::DefaultValue: /* This function shouldn't be called in this case, since there * is no need to copy anything to the new custom data array. */ BLI_assert_unreachable(); @@ -560,7 +561,7 @@ static GVArray varray_from_initializer(const AttributeInit &initializer, total_num += spline->size(); } return GVArray::ForSpan(GSpan(*bke::custom_data_type_to_cpp_type(data_type), - static_cast<const AttributeInitMove &>(initializer).data, + static_cast<const AttributeInitMoveArray &>(initializer).data, total_num)); } BLI_assert_unreachable(); @@ -580,7 +581,7 @@ static bool create_point_attribute(CurveEval *curve, /* First check the one case that allows us to avoid copying the input data. */ if (splines.size() == 1 && initializer.type == AttributeInit::Type::MoveArray) { - void *source_data = static_cast<const AttributeInitMove &>(initializer).data; + void *source_data = static_cast<const AttributeInitMoveArray &>(initializer).data; if (!splines.first()->attributes.create_by_move(attribute_id, data_type, source_data)) { MEM_freeN(source_data); return false; @@ -600,7 +601,7 @@ static bool create_point_attribute(CurveEval *curve, } /* With a default initializer type, we can keep the values at their initial values. */ - if (initializer.type == AttributeInit::Type::Default) { + if (ELEM(initializer.type, AttributeInit::Type::DefaultValue, AttributeInit::Type::Construct)) { return true; } @@ -616,7 +617,7 @@ static bool create_point_attribute(CurveEval *curve, write_attribute.finish(); if (initializer.type == AttributeInit::Type::MoveArray) { - MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data); + MEM_freeN(static_cast<const AttributeInitMoveArray &>(initializer).data); } return true; diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc index 2714c78e381..596c8e0bfc7 100644 --- a/source/blender/blenkernel/intern/geometry_component_curves.cc +++ b/source/blender/blenkernel/intern/geometry_component_curves.cc @@ -206,18 +206,11 @@ static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves return results; } -VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttrDomain domain) +VArray<float3> curve_normals_varray(const CurvesGeometry &curves, const eAttrDomain domain) { - if (!component.has_curves()) { - return {}; - } - - const Curves &curves_id = *component.get_for_read(); - const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); - const VArray<int8_t> types = curves.curve_types(); if (curves.is_single_type(CURVE_TYPE_POLY)) { - return component.attributes()->adapt_domain<float3>( + return curves.adapt_domain<float3>( VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain); } @@ -228,7 +221,7 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttr } if (domain == ATTR_DOMAIN_CURVE) { - return component.attributes()->adapt_domain<float3>( + return curves.adapt_domain<float3>( VArray<float3>::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); } @@ -241,15 +234,9 @@ VArray<float3> curve_normals_varray(const CurveComponent &component, const eAttr /** \name Curve Length Field Input * \{ */ -static VArray<float> construct_curve_length_gvarray(const CurveComponent &component, +static VArray<float> construct_curve_length_gvarray(const CurvesGeometry &curves, const eAttrDomain domain) { - if (!component.has_curves()) { - return {}; - } - const Curves &curves_id = *component.get_for_read(); - const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry); - curves.ensure_evaluated_lengths(); VArray<bool> cyclic = curves.cyclic(); @@ -263,28 +250,23 @@ static VArray<float> construct_curve_length_gvarray(const CurveComponent &compon } if (domain == ATTR_DOMAIN_POINT) { - return component.attributes()->adapt_domain<float>( - std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); + return curves.adapt_domain<float>(std::move(lengths), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); } return {}; } CurveLengthFieldInput::CurveLengthFieldInput() - : GeometryFieldInput(CPPType::get<float>(), "Spline Length node") + : CurvesFieldInput(CPPType::get<float>(), "Spline Length node") { category_ = Category::Generated; } -GVArray CurveLengthFieldInput::get_varray_for_context(const GeometryComponent &component, +GVArray CurveLengthFieldInput::get_varray_for_context(const CurvesGeometry &curves, const eAttrDomain domain, IndexMask UNUSED(mask)) const { - if (component.type() == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - return construct_curve_length_gvarray(curve_component, domain); - } - return {}; + return construct_curve_length_gvarray(curves, domain); } uint64_t CurveLengthFieldInput::hash() const diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 436868ba375..ff55409d5fc 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -115,8 +115,7 @@ void MeshComponent::ensure_owns_direct_data() namespace blender::bke { -VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, - const Mesh &mesh, +VArray<float3> mesh_normals_varray(const Mesh &mesh, const IndexMask mask, const eAttrDomain domain) { @@ -150,7 +149,7 @@ VArray<float3> mesh_normals_varray(const MeshComponent &mesh_component, * array and copy the face normal for each of its corners. In this case using the mesh * component's generic domain interpolation is fine, the data will still be normalized, * since the face normal is just copied to every corner. */ - return mesh_component.attributes()->adapt_domain( + return mesh_attributes(mesh).adapt_domain( VArray<float3>::ForSpan({(float3 *)BKE_mesh_poly_normals_ensure(&mesh), mesh.totpoly}), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER); @@ -843,16 +842,6 @@ static void tag_component_positions_changed(void *owner) } } -static int get_material_index(const MPoly &mpoly) -{ - return static_cast<int>(mpoly.mat_nr); -} - -static void set_material_index(MPoly &mpoly, int index) -{ - mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); -} - static bool get_shade_smooth(const MPoly &mpoly) { return mpoly.flag & ME_SMOOTH; @@ -1202,18 +1191,17 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() make_array_write_attribute<int>, nullptr); - static BuiltinCustomDataLayerProvider material_index( - "material_index", - ATTR_DOMAIN_FACE, - CD_PROP_INT32, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - face_access, - make_derived_read_attribute<MPoly, int, get_material_index>, - make_derived_write_attribute<MPoly, int, get_material_index, set_material_index>, - nullptr); + static BuiltinCustomDataLayerProvider material_index("material_index", + ATTR_DOMAIN_FACE, + CD_PROP_INT32, + CD_PROP_INT32, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + face_access, + make_array_read_attribute<int>, + make_array_write_attribute<int>, + nullptr); static BuiltinCustomDataLayerProvider shade_smooth( "shade_smooth", diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc new file mode 100644 index 00000000000..a52ffb6496b --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_fields.cc @@ -0,0 +1,365 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_attribute.hh" +#include "BKE_curves.hh" +#include "BKE_geometry_fields.hh" +#include "BKE_geometry_set.hh" +#include "BKE_mesh.h" +#include "BKE_pointcloud.h" +#include "BKE_type_conversions.hh" + +#include "DNA_mesh_types.h" +#include "DNA_pointcloud_types.h" + +#include "BLT_translation.h" + +namespace blender::bke { + +MeshFieldContext::MeshFieldContext(const Mesh &mesh, const eAttrDomain domain) + : mesh_(mesh), domain_(domain) +{ + BLI_assert(mesh_attributes(mesh).domain_supported(domain_)); +} + +CurvesFieldContext::CurvesFieldContext(const CurvesGeometry &curves, const eAttrDomain domain) + : curves_(curves), domain_(domain) +{ + BLI_assert(curves.attributes().domain_supported(domain)); +} + +GeometryFieldContext::GeometryFieldContext(const void *geometry, + const GeometryComponentType type, + const eAttrDomain domain) + : geometry_(geometry), type_(type), domain_(domain) +{ + BLI_assert(ELEM(type, + GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_INSTANCES)); +} + +GeometryFieldContext::GeometryFieldContext(const GeometryComponent &component, + const eAttrDomain domain) + : type_(component.type()), domain_(domain) +{ + switch (component.type()) { + case GEO_COMPONENT_TYPE_MESH: { + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + geometry_ = mesh_component.get_for_read(); + break; + } + case GEO_COMPONENT_TYPE_CURVE: { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const Curves *curves = curve_component.get_for_read(); + geometry_ = curves ? &CurvesGeometry::wrap(curves->geometry) : nullptr; + break; + } + case GEO_COMPONENT_TYPE_POINT_CLOUD: { + const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>( + component); + geometry_ = pointcloud_component.get_for_read(); + break; + } + case GEO_COMPONENT_TYPE_INSTANCES: { + const InstancesComponent &instances_component = static_cast<const InstancesComponent &>( + component); + geometry_ = &instances_component; + break; + } + case GEO_COMPONENT_TYPE_VOLUME: + case GEO_COMPONENT_TYPE_EDIT: + BLI_assert_unreachable(); + break; + } +} + +GeometryFieldContext::GeometryFieldContext(const Mesh &mesh, eAttrDomain domain) + : geometry_(&mesh), type_(GEO_COMPONENT_TYPE_MESH), domain_(domain) +{ +} +GeometryFieldContext::GeometryFieldContext(const CurvesGeometry &curves, eAttrDomain domain) + : geometry_(&curves), type_(GEO_COMPONENT_TYPE_CURVE), domain_(domain) +{ +} +GeometryFieldContext::GeometryFieldContext(const PointCloud &points) + : geometry_(&points), type_(GEO_COMPONENT_TYPE_POINT_CLOUD), domain_(ATTR_DOMAIN_POINT) +{ +} +GeometryFieldContext::GeometryFieldContext(const InstancesComponent &instances) + : geometry_(&instances), type_(GEO_COMPONENT_TYPE_INSTANCES), domain_(ATTR_DOMAIN_INSTANCE) +{ +} + +std::optional<AttributeAccessor> GeometryFieldContext::attributes() const +{ + if (const Mesh *mesh = this->mesh()) { + return mesh_attributes(*mesh); + } + if (const CurvesGeometry *curves = this->curves()) { + return curves->attributes(); + } + if (const PointCloud *pointcloud = this->pointcloud()) { + return pointcloud_attributes(*pointcloud); + } + if (const InstancesComponent *instances = this->instances()) { + return instances->attributes(); + } + return {}; +} + +const Mesh *GeometryFieldContext::mesh() const +{ + return this->type() == GEO_COMPONENT_TYPE_MESH ? static_cast<const Mesh *>(geometry_) : nullptr; +} +const CurvesGeometry *GeometryFieldContext::curves() const +{ + return this->type() == GEO_COMPONENT_TYPE_CURVE ? + static_cast<const CurvesGeometry *>(geometry_) : + nullptr; +} +const PointCloud *GeometryFieldContext::pointcloud() const +{ + return this->type() == GEO_COMPONENT_TYPE_POINT_CLOUD ? + static_cast<const PointCloud *>(geometry_) : + nullptr; +} +const InstancesComponent *GeometryFieldContext::instances() const +{ + return this->type() == GEO_COMPONENT_TYPE_INSTANCES ? + static_cast<const InstancesComponent *>(geometry_) : + nullptr; +} + +GVArray GeometryFieldInput::get_varray_for_context(const fn::FieldContext &context, + const IndexMask mask, + ResourceScope & /*scope*/) const +{ + if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>( + &context)) { + return this->get_varray_for_context(*geometry_context, mask); + } + if (const MeshFieldContext *mesh_context = dynamic_cast<const MeshFieldContext *>(&context)) { + return this->get_varray_for_context({mesh_context->mesh(), mesh_context->domain()}, mask); + } + if (const CurvesFieldContext *curve_context = dynamic_cast<const CurvesFieldContext *>( + &context)) { + return this->get_varray_for_context({curve_context->curves(), curve_context->domain()}, mask); + } + if (const PointCloudFieldContext *point_context = dynamic_cast<const PointCloudFieldContext *>( + &context)) { + return this->get_varray_for_context({point_context->pointcloud()}, mask); + } + if (const InstancesFieldContext *instances_context = dynamic_cast<const InstancesFieldContext *>( + &context)) { + return this->get_varray_for_context({instances_context->instances()}, mask); + } + return {}; +} + +GVArray MeshFieldInput::get_varray_for_context(const fn::FieldContext &context, + const IndexMask mask, + ResourceScope & /*scope*/) const +{ + if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>( + &context)) { + if (const Mesh *mesh = geometry_context->mesh()) { + return this->get_varray_for_context(*mesh, geometry_context->domain(), mask); + } + } + if (const MeshFieldContext *mesh_context = dynamic_cast<const MeshFieldContext *>(&context)) { + return this->get_varray_for_context(mesh_context->mesh(), mesh_context->domain(), mask); + } + return {}; +} + +GVArray CurvesFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope & /*scope*/) const +{ + if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>( + &context)) { + if (const CurvesGeometry *curves = geometry_context->curves()) { + return this->get_varray_for_context(*curves, geometry_context->domain(), mask); + } + } + if (const CurvesFieldContext *curves_context = dynamic_cast<const CurvesFieldContext *>( + &context)) { + return this->get_varray_for_context(curves_context->curves(), curves_context->domain(), mask); + } + return {}; +} + +GVArray PointCloudFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope & /*scope*/) const +{ + if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>( + &context)) { + if (const PointCloud *pointcloud = geometry_context->pointcloud()) { + return this->get_varray_for_context(*pointcloud, mask); + } + } + if (const PointCloudFieldContext *point_context = dynamic_cast<const PointCloudFieldContext *>( + &context)) { + return this->get_varray_for_context(point_context->pointcloud(), mask); + } + return {}; +} + +GVArray InstancesFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope & /*scope*/) const +{ + if (const GeometryFieldContext *geometry_context = dynamic_cast<const GeometryFieldContext *>( + &context)) { + if (const InstancesComponent *instances = geometry_context->instances()) { + return this->get_varray_for_context(*instances, mask); + } + } + if (const InstancesFieldContext *instances_context = dynamic_cast<const InstancesFieldContext *>( + &context)) { + return this->get_varray_for_context(instances_context->instances(), mask); + } + return {}; +} + +GVArray AttributeFieldInput::get_varray_for_context(const GeometryFieldContext &context, + IndexMask UNUSED(mask)) const +{ + const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_); + if (auto attributes = context.attributes()) { + return attributes->lookup(name_, context.domain(), data_type); + } + return {}; +} + +std::string AttributeFieldInput::socket_inspection_name() const +{ + std::stringstream ss; + ss << '"' << name_ << '"' << TIP_(" attribute from geometry"); + return ss.str(); +} + +uint64_t AttributeFieldInput::hash() const +{ + return get_default_hash_2(name_, type_); +} + +bool AttributeFieldInput::is_equal_to(const fn::FieldNode &other) const +{ + if (const AttributeFieldInput *other_typed = dynamic_cast<const AttributeFieldInput *>(&other)) { + return name_ == other_typed->name_ && type_ == other_typed->type_; + } + return false; +} + +static StringRef get_random_id_attribute_name(const eAttrDomain domain) +{ + switch (domain) { + case ATTR_DOMAIN_POINT: + case ATTR_DOMAIN_INSTANCE: + return "id"; + default: + return ""; + } +} + +GVArray IDAttributeFieldInput::get_varray_for_context(const GeometryFieldContext &context, + const IndexMask mask) const +{ + + const StringRef name = get_random_id_attribute_name(context.domain()); + if (auto attributes = context.attributes()) { + if (GVArray attribute = attributes->lookup(name, context.domain(), CD_PROP_INT32)) { + return attribute; + } + } + + /* Use the index as the fallback if no random ID attribute exists. */ + return fn::IndexFieldInput::get_index_varray(mask); +} + +std::string IDAttributeFieldInput::socket_inspection_name() const +{ + return TIP_("ID / Index"); +} + +uint64_t IDAttributeFieldInput::hash() const +{ + /* All random ID attribute inputs are the same within the same evaluation context. */ + return 92386459827; +} + +bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const +{ + /* All random ID attribute inputs are the same within the same evaluation context. */ + return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr; +} + +GVArray AnonymousAttributeFieldInput::get_varray_for_context(const GeometryFieldContext &context, + const IndexMask /*mask*/) const +{ + const eCustomDataType data_type = cpp_type_to_custom_data_type(*type_); + return context.attributes()->lookup(anonymous_id_.get(), context.domain(), data_type); +} + +std::string AnonymousAttributeFieldInput::socket_inspection_name() const +{ + std::stringstream ss; + ss << '"' << debug_name_ << '"' << TIP_(" from ") << producer_name_; + return ss.str(); +} + +uint64_t AnonymousAttributeFieldInput::hash() const +{ + return get_default_hash_2(anonymous_id_.get(), type_); +} + +bool AnonymousAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const +{ + if (const AnonymousAttributeFieldInput *other_typed = + dynamic_cast<const AnonymousAttributeFieldInput *>(&other)) { + return anonymous_id_.get() == other_typed->anonymous_id_.get() && type_ == other_typed->type_; + } + return false; +} + +} // namespace blender::bke + +/* -------------------------------------------------------------------- */ +/** \name Mesh and Curve Normals Field Input + * \{ */ + +namespace blender::bke { + +GVArray NormalFieldInput::get_varray_for_context(const GeometryFieldContext &context, + const IndexMask mask) const +{ + if (const Mesh *mesh = context.mesh()) { + return mesh_normals_varray(*mesh, mask, context.domain()); + } + if (const CurvesGeometry *curves = context.curves()) { + return curve_normals_varray(*curves, context.domain()); + } + return {}; +} + +std::string NormalFieldInput::socket_inspection_name() const +{ + return TIP_("Normal"); +} + +uint64_t NormalFieldInput::hash() const +{ + return 213980475983; +} + +bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const +{ + return dynamic_cast<const NormalFieldInput *>(&other) != nullptr; +} + +} // namespace blender::bke + +/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 1a0ce4f0893..633d9ad8c49 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -8,7 +8,6 @@ #include "BKE_attribute.h" #include "BKE_curves.hh" -#include "BKE_geometry_fields.hh" #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" #include "BKE_mesh.h" @@ -634,48 +633,6 @@ void GeometrySet::modify_geometry_sets(ForeachSubGeometryCallback callback) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Mesh and Curve Normals Field Input - * \{ */ - -namespace blender::bke { - -GVArray NormalFieldInput::get_varray_for_context(const GeometryComponent &component, - const eAttrDomain domain, - IndexMask mask) const -{ - if (component.type() == GEO_COMPONENT_TYPE_MESH) { - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - if (const Mesh *mesh = mesh_component.get_for_read()) { - return mesh_normals_varray(mesh_component, *mesh, mask, domain); - } - } - else if (component.type() == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); - return curve_normals_varray(curve_component, domain); - } - return {}; -} - -std::string NormalFieldInput::socket_inspection_name() const -{ - return TIP_("Normal"); -} - -uint64_t NormalFieldInput::hash() const -{ - return 213980475983; -} - -bool NormalFieldInput::is_equal_to(const fn::FieldNode &other) const -{ - return dynamic_cast<const NormalFieldInput *>(&other) != nullptr; -} - -} // namespace blender::bke - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name C API * \{ */ diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve.c index d68b322e4c5..bf224a9613e 100644 --- a/source/blender/blenkernel/intern/gpencil_curve.c +++ b/source/blender/blenkernel/intern/gpencil_curve.c @@ -337,7 +337,6 @@ static void gpencil_convert_spline(Main *bmain, /* Add stroke to frame. */ BLI_addtail(&gpf->strokes, gps); - float *coord_array = NULL; float init_co[3]; switch (nu->type) { @@ -376,8 +375,7 @@ static void gpencil_convert_spline(Main *bmain, BezTriple *bezt = &nu->bezt[inext]; bool last = (bool)(s == segments - 1); - coord_array = MEM_callocN((size_t)3 * resolu * sizeof(float), __func__); - + float *coord_array = MEM_callocN(sizeof(float[3]) * resolu, __func__); for (int j = 0; j < 3; j++) { BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], prevbezt->vec[2][j], @@ -397,8 +395,9 @@ static void gpencil_convert_spline(Main *bmain, gpencil_add_new_points( gps, coord_array, radius_start, radius_end, init, resolu, init_co, last); + /* Free memory. */ - MEM_SAFE_FREE(coord_array); + MEM_freeN(coord_array); /* As the last point of segment is the first point of next segment, back one array * element to avoid duplicated points on the same location. @@ -419,7 +418,7 @@ static void gpencil_convert_spline(Main *bmain, nurb_points = (nu->pntsu - 1) * resolu; } /* Get all curve points. */ - coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__); + float *coord_array = MEM_callocN(sizeof(float[3]) * nurb_points, __func__); BKE_nurb_makeCurve(nu, coord_array, NULL, NULL, NULL, resolu, sizeof(float[3])); /* Allocate memory for storage points. */ @@ -429,7 +428,7 @@ static void gpencil_convert_spline(Main *bmain, /* Add points. */ gpencil_add_new_points(gps, coord_array, 1.0f, 1.0f, 0, gps->totpoints, init_co, false); - MEM_SAFE_FREE(coord_array); + MEM_freeN(coord_array); } break; } diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index d0075a7d161..ce2e106c664 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -35,6 +35,7 @@ #include "BLT_translation.h" +#include "BKE_attribute.hh" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_gpencil.h" @@ -2662,6 +2663,8 @@ bool BKE_gpencil_convert_mesh(Main *bmain, const bool use_faces, const bool use_vgroups) { + using namespace blender; + using namespace blender::bke; if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == nullptr)) { return false; } @@ -2708,12 +2711,15 @@ bool BKE_gpencil_convert_mesh(Main *bmain, bGPDframe *gpf_fill = BKE_gpencil_layer_frame_get( gpl_fill, scene->r.cfra + frame_offset, GP_GETFRAME_ADD_NEW); int i; + + const VArray<int> mesh_material_indices = mesh_attributes(*me_eval).lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); for (i = 0; i < mpoly_len; i++) { const MPoly *mp = &mpoly[i]; /* Find material. */ int mat_idx = 0; - Material *ma = BKE_object_material_get(ob_mesh, mp->mat_nr + 1); + Material *ma = BKE_object_material_get(ob_mesh, mesh_material_indices[i] + 1); make_element_name( ob_mesh->id.name + 2, (ma != nullptr) ? ma->id.name + 2 : "Fill", 64, element_name); mat_idx = BKE_gpencil_material_find_index_by_name_prefix(ob_gp, element_name); @@ -3960,6 +3966,7 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd, const bGPDlayer *gpl, const bGPDstroke *gps, int subdivisions, + const float thickness_chg, int *r_num_perimeter_points) { /* sanity check */ @@ -3968,7 +3975,9 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd, } float defaultpixsize = 1000.0f / gpd->pixfactor; + float ovr_radius = thickness_chg / defaultpixsize / 2.0f; float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f; + stroke_radius = max_ff(stroke_radius - ovr_radius, 0.0f); ListBase *perimeter_right_side = MEM_cnew<ListBase>(__func__); ListBase *perimeter_left_side = MEM_cnew<ListBase>(__func__); @@ -4202,7 +4211,8 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, const bGPDlayer *gpl, bGPDstroke *gps, const int subdivisions, - const float diff_mat[4][4]) + const float diff_mat[4][4], + const float thickness_chg) { if (gps->totpoints == 0) { return nullptr; @@ -4234,7 +4244,7 @@ bGPDstroke *BKE_gpencil_stroke_perimeter_from_view(struct RegionView3D *rv3d, BKE_gpencil_stroke_to_view_space(rv3d, gps_temp, diff_mat); int num_perimeter_points = 0; ListBase *perimeter_points = gpencil_stroke_perimeter_ex( - gpd, gpl, gps_temp, subdivisions, &num_perimeter_points); + gpd, gpl, gps_temp, subdivisions, thickness_chg, &num_perimeter_points); if (num_perimeter_points == 0) { return nullptr; diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c index 82899b974bc..8ac268b26b0 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier.c @@ -360,7 +360,8 @@ GpencilModifierData *BKE_gpencil_modifier_new(int type) md->type = type; md->mode = eGpencilModifierMode_Realtime | eGpencilModifierMode_Render; md->flag = eGpencilModifierFlag_OverrideLibrary_Local; - md->ui_expand_flag = 1; /* Only expand the parent panel at first. */ + /* Only expand the parent panel at first. */ + md->ui_expand_flag = UI_PANEL_DATA_EXPAND_ROOT; if (mti->flags & eGpencilModifierTypeFlag_EnableInEditmode) { md->mode |= eGpencilModifierMode_Editmode; diff --git a/source/blender/blenkernel/intern/icons_rasterize.c b/source/blender/blenkernel/intern/icons_rasterize.c index 5603d84022d..00dbdcfa1e5 100644 --- a/source/blender/blenkernel/intern/icons_rasterize.c +++ b/source/blender/blenkernel/intern/icons_rasterize.c @@ -76,7 +76,7 @@ ImBuf *BKE_icon_geom_rasterize(const struct Icon_Geom *geom, const uchar(*pos)[2] = geom->coords; const uint *col = (void *)geom->colors; - /* TODO(campbell): Currently rasterizes to fixed size, then scales. + /* TODO(@campbellbarton): Currently rasterizes to fixed size, then scales. * Should rasterize to double size for eg instead. */ const int rect_size[2] = {max_ii(256, (int)size_x * 2), max_ii(256, (int)size_y * 2)}; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 43e732b428d..98c317c547b 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -784,7 +784,7 @@ IDProperty *IDP_GetProperties(ID *id, const bool create_if_needed) if (create_if_needed) { id->properties = MEM_callocN(sizeof(IDProperty), "IDProperty"); id->properties->type = IDP_GROUP; - /* NOTE(campbell): Don't overwrite the data's name and type + /* NOTE(@campbellbarton): Don't overwrite the data's name and type * some functions might need this if they * don't have a real ID, should be named elsewhere. */ // strcpy(id->name, "top_level_group"); diff --git a/source/blender/blenkernel/intern/idprop_create.cc b/source/blender/blenkernel/intern/idprop_create.cc index 499a43ee0a7..24f59d5e49e 100644 --- a/source/blender/blenkernel/intern/idprop_create.cc +++ b/source/blender/blenkernel/intern/idprop_create.cc @@ -44,6 +44,14 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_n return std::unique_ptr<IDProperty, IDPropertyDeleter>(property); } +std::unique_ptr<IDProperty, IDPropertyDeleter> create(const StringRefNull prop_name, ID *value) +{ + IDPropertyTemplate prop_template{0}; + prop_template.id = value; + IDProperty *property = IDP_New(IDP_ID, &prop_template, prop_name.c_str()); + return std::unique_ptr<IDProperty, IDPropertyDeleter>(property); +} + static std::unique_ptr<IDProperty, IDPropertyDeleter> array_create(const StringRefNull prop_name, eIDPropertyType subtype, size_t array_len) diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc index b196bcd7207..ae24383e5b9 100644 --- a/source/blender/blenkernel/intern/image.cc +++ b/source/blender/blenkernel/intern/image.cc @@ -627,6 +627,16 @@ void BKE_image_free_data(Image *ima) image_free_data(&ima->id); } +static ImageTile *imagetile_alloc(int tile_number) +{ + ImageTile *tile = MEM_cnew<ImageTile>("Image Tile"); + tile->tile_number = tile_number; + tile->gen_x = 1024; + tile->gen_y = 1024; + tile->gen_type = IMA_GENTYPE_GRID; + return tile; +} + /* only image block itself */ static void image_init(Image *ima, short source, short type) { @@ -641,8 +651,7 @@ static void image_init(Image *ima, short source, short type) ima->flag |= IMA_VIEW_AS_RENDER; } - ImageTile *tile = MEM_cnew<ImageTile>("Image Tiles"); - tile->tile_number = 1001; + ImageTile *tile = imagetile_alloc(1001); BLI_addtail(&ima->tiles, tile); if (type == IMA_TYPE_R_RESULT) { @@ -863,37 +872,89 @@ void BKE_image_get_tile_uv(const Image *ima, const int tile_number, float r_uv[2 } } +/** Linear distance between #x and the unit interval. */ +static float distance_to_unit_interval(float x) +{ + /* The unit interval is between 0 and 1. + * Within the interval, return 0. + * Outside the interval, return the distance to the nearest boundary. + * Intuitively, the function looks like: + * \ | | / + * __\|___|/__ + * 0 1 + */ + + if (x <= 0.0f) { + return -x; /* Distance to left border. */ + } + if (x <= 1.0f) { + return 0.0f; /* Inside unit interval. */ + } + return x - 1.0f; /* Distance to right border. */ +} + +/** Distance squared between #co and the unit square with lower-left starting at #udim. */ +static float distance_squared_to_udim(const float co[2], const float udim[2]) +{ + float delta[2]; + sub_v2_v2v2(delta, co, udim); + delta[0] = distance_to_unit_interval(delta[0]); + delta[1] = distance_to_unit_interval(delta[1]); + return len_squared_v2(delta); +} + +static bool nearest_udim_tile_tie_break(const float best_dist_sq, + const float best_uv[2], + const float dist_sq, + const float uv[2]) +{ + if (best_dist_sq == dist_sq) { /* Exact same distance? Tie-break. */ + if (best_uv[0] == uv[0]) { /* Exact same U? Tie-break. */ + return (uv[1] > best_uv[1]); /* Higher than previous candidate? */ + } + return (uv[0] > best_uv[0]); /* Further right than previous candidate? */ + } + return (dist_sq < best_dist_sq); /* Closer than previous candidate? */ +} + int BKE_image_find_nearest_tile_with_offset(const Image *image, const float co[2], float r_uv_offset[2]) { - /* Distance squared to the closest UDIM tile. */ - float dist_best_sq = FLT_MAX; - float uv_offset_best[2] = {0, 0}; + /* NOTE: If the co-ordinates are integers, take special care to break ties. */ + + zero_v2(r_uv_offset); int tile_number_best = -1; - const float co_offset[2] = {co[0] - 0.5f, co[1] - 0.5f}; + if (!image || image->source != IMA_SRC_TILED) { + return tile_number_best; + } + + /* Distance squared to the closest UDIM tile. */ + float dist_best_sq = FLT_MAX; LISTBASE_FOREACH (const ImageTile *, tile, &image->tiles) { float uv_offset[2]; BKE_image_get_tile_uv(image, tile->tile_number, uv_offset); - /* Distance squared between co[2] and center of UDIM tile. */ - const float dist_sq = len_squared_v2v2(uv_offset, co_offset); + /* Distance squared between #co and closest point on UDIM tile. */ + const float dist_sq = distance_squared_to_udim(co, uv_offset); - if (dist_sq < dist_best_sq) { + if (dist_sq == 0) { /* Either inside in the UDIM, or on its boundary. */ + if (floorf(co[0]) == uv_offset[0] && floorf(co[1]) == uv_offset[1]) { + /* Within the half-open interval of the UDIM. */ + copy_v2_v2(r_uv_offset, uv_offset); + return tile_number_best; + } + } + + if (nearest_udim_tile_tie_break(dist_best_sq, r_uv_offset, dist_sq, uv_offset)) { + /* Tile is better than previous best, update. */ dist_best_sq = dist_sq; + copy_v2_v2(r_uv_offset, uv_offset); tile_number_best = tile->tile_number; - copy_v2_v2(uv_offset_best, uv_offset); - - if (dist_best_sq < 0.5f * 0.5f) { - break; /* No other tile can be closer. */ - } } } - if (tile_number_best != -1) { - copy_v2_v2(r_uv_offset, uv_offset_best); - } return tile_number_best; } @@ -910,7 +971,7 @@ static void image_init_color_management(Image *ima) BKE_image_user_file_path(nullptr, ima, name); - /* will set input color space to image format default's */ + /* Will set input color space to image format default's. */ ibuf = IMB_loadiffname(name, IB_test | IB_alphamode_detect, ima->colorspace_settings.name); if (ibuf) { @@ -1048,73 +1109,70 @@ static void image_buf_fill_isolated(void *usersata_v) } } -static ImBuf *add_ibuf_size(unsigned int width, - unsigned int height, - const char *name, - int depth, - int floatbuf, - short gen_type, - const float color[4], - ColorManagedColorspaceSettings *colorspace_settings) +static ImBuf *add_ibuf_for_tile(Image *ima, ImageTile *tile) { ImBuf *ibuf; unsigned char *rect = nullptr; float *rect_float = nullptr; float fill_color[4]; + const bool floatbuf = (tile->gen_flag & IMA_GEN_FLOAT) != 0; if (floatbuf) { - ibuf = IMB_allocImBuf(width, height, depth, IB_rectfloat); + ibuf = IMB_allocImBuf(tile->gen_x, tile->gen_y, tile->gen_depth, IB_rectfloat); - if (colorspace_settings->name[0] == '\0') { + if (ima->colorspace_settings.name[0] == '\0') { const char *colorspace = IMB_colormanagement_role_colorspace_name_get( COLOR_ROLE_DEFAULT_FLOAT); - STRNCPY(colorspace_settings->name, colorspace); + STRNCPY(ima->colorspace_settings.name, colorspace); } if (ibuf != nullptr) { rect_float = ibuf->rect_float; - IMB_colormanagement_check_is_data(ibuf, colorspace_settings->name); + IMB_colormanagement_check_is_data(ibuf, ima->colorspace_settings.name); } - if (IMB_colormanagement_space_name_is_data(colorspace_settings->name)) { - copy_v4_v4(fill_color, color); + if (IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) { + copy_v4_v4(fill_color, tile->gen_color); } else { /* The input color here should ideally be linear already, but for now * we just convert and postpone breaking the API for later. */ - srgb_to_linearrgb_v4(fill_color, color); + srgb_to_linearrgb_v4(fill_color, tile->gen_color); } } else { - ibuf = IMB_allocImBuf(width, height, depth, IB_rect); + ibuf = IMB_allocImBuf(tile->gen_x, tile->gen_y, tile->gen_depth, IB_rect); - if (colorspace_settings->name[0] == '\0') { + if (ima->colorspace_settings.name[0] == '\0') { const char *colorspace = IMB_colormanagement_role_colorspace_name_get( COLOR_ROLE_DEFAULT_BYTE); - STRNCPY(colorspace_settings->name, colorspace); + STRNCPY(ima->colorspace_settings.name, colorspace); } if (ibuf != nullptr) { rect = (unsigned char *)ibuf->rect; - IMB_colormanagement_assign_rect_colorspace(ibuf, colorspace_settings->name); + IMB_colormanagement_assign_rect_colorspace(ibuf, ima->colorspace_settings.name); } - copy_v4_v4(fill_color, color); + copy_v4_v4(fill_color, tile->gen_color); } if (!ibuf) { return nullptr; } - STRNCPY(ibuf->name, name); + STRNCPY(ibuf->name, ima->filepath); + + /* Mark the tile itself as having been generated. */ + tile->gen_flag |= IMA_GEN_TILE; ImageFillData data; - data.gen_type = gen_type; - data.width = width; - data.height = height; + data.gen_type = tile->gen_type; + data.width = tile->gen_x; + data.height = tile->gen_y; data.rect = rect; data.rect_float = rect_float; copy_v4_v4(data.fill_color, fill_color); @@ -1153,12 +1211,16 @@ Image *BKE_image_add_generated(Main *bmain, /* NOTE: leave `ima->filepath` unset, * setting it to a dummy value may write to an invalid file-path. */ - ima->gen_x = width; - ima->gen_y = height; - ima->gen_type = gen_type; - ima->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0); - ima->gen_depth = depth; - copy_v4_v4(ima->gen_color, color); + + /* The generation info is always stored in the tiles. The first tile + * will be used for non-tiled images. */ + ImageTile *tile = static_cast<ImageTile *>(ima->tiles.first); + tile->gen_x = width; + tile->gen_y = height; + tile->gen_type = gen_type; + tile->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0); + tile->gen_depth = depth; + copy_v4_v4(tile->gen_color, color); if (is_data) { STRNCPY(ima->colorspace_settings.name, @@ -1167,8 +1229,7 @@ Image *BKE_image_add_generated(Main *bmain, for (view_id = 0; view_id < 2; view_id++) { ImBuf *ibuf; - ibuf = add_ibuf_size( - width, height, ima->filepath, depth, floatbuf, gen_type, color, &ima->colorspace_settings); + ibuf = add_ibuf_for_tile(ima, tile); int index = tiled ? 0 : IMA_NO_INDEX; int entry = tiled ? 1001 : 0; image_assign_ibuf(ima, ibuf, stereo3d ? view_id : index, entry); @@ -1187,7 +1248,7 @@ Image *BKE_image_add_generated(Main *bmain, static void image_colorspace_from_imbuf(Image *image, const ImBuf *ibuf) { - const char *colorspace_name = NULL; + const char *colorspace_name = nullptr; if (ibuf->rect_float) { if (ibuf->float_colorspace) { @@ -2949,6 +3010,28 @@ static void image_free_tile(Image *ima, ImageTile *tile) } } +static bool image_remove_tile(Image *ima, ImageTile *tile) +{ + if (BLI_listbase_is_single(&ima->tiles)) { + /* Can't remove the last remaining tile. */ + return false; + } + + image_free_tile(ima, tile); + BLI_remlink(&ima->tiles, tile); + MEM_freeN(tile); + + return true; +} + +static void image_remove_all_tiles(Image *ima) +{ + /* Remove all but the final tile. */ + while (image_remove_tile(ima, static_cast<ImageTile *>(ima->tiles.last))) { + ; + } +} + void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) { if (ima == nullptr) { @@ -2975,11 +3058,12 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) } if (ima->source == IMA_SRC_GENERATED) { - if (ima->gen_x == 0 || ima->gen_y == 0) { + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + if (base_tile->gen_x == 0 || base_tile->gen_y == 0) { ImBuf *ibuf = image_get_cached_ibuf_for_index_entry(ima, IMA_NO_INDEX, 0, nullptr); if (ibuf) { - ima->gen_x = ibuf->x; - ima->gen_y = ibuf->y; + base_tile->gen_x = ibuf->x; + base_tile->gen_y = ibuf->y; IMB_freeImBuf(ibuf); } } @@ -2996,16 +3080,40 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) if (ima->source != IMA_SRC_TILED) { /* Free all but the first tile. */ + image_remove_all_tiles(ima); + + /* If the remaining tile is generated, we need to again ensure that we + * wouldn't continue to use the old filepath. + * + * Otherwise, if this used to be a UDIM image, get the concrete filepath associated + * with the remaining tile and use that as the new filepath. */ ImageTile *base_tile = BKE_image_get_tile(ima, 0); - BLI_assert(base_tile == ima->tiles.first); - for (ImageTile *tile = base_tile->next, *tile_next; tile; tile = tile_next) { - tile_next = tile->next; - image_free_tile(ima, tile); - MEM_freeN(tile); + if ((base_tile->gen_flag & IMA_GEN_TILE) != 0) { + ima->filepath[0] = '\0'; + } + else if (BKE_image_is_filename_tokenized(ima->filepath)) { + const bool was_relative = BLI_path_is_rel(ima->filepath); + + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern = BKE_image_get_tile_strformat(ima->filepath, &tile_format); + BKE_image_set_filepath_from_tile_number( + ima->filepath, udim_pattern, tile_format, base_tile->tile_number); + MEM_freeN(udim_pattern); + + if (was_relative) { + const char *relbase = ID_BLEND_PATH(bmain, &ima->id); + BLI_path_rel(ima->filepath, relbase); + } } - base_tile->next = nullptr; + + /* If the remaining tile was not number 1001, we need to reassign it so that + * ibuf lookups from the cache still succeed. */ base_tile->tile_number = 1001; - ima->tiles.last = base_tile; + } + else { + /* When changing to UDIM, attempt to tokenize the filepath. */ + char *filename = (char *)BLI_path_basename(ima->filepath); + BKE_image_ensure_tile_token(filename); } /* image buffers for non-sequence multilayer will share buffers with RenderResult, @@ -3021,6 +3129,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) image_tag_frame_recalc(ima, nullptr, iuser, ima); } BKE_image_walk_all_users(bmain, ima, image_tag_frame_recalc); + BKE_image_partial_update_mark_full_update(ima); break; @@ -3072,9 +3181,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) * to account for how the two sets might or might not overlap. To be complete, we start * the refresh process by clearing all existing tiles, stopping when there's only 1 tile * left. */ - while (BKE_image_remove_tile(ima, static_cast<ImageTile *>(ima->tiles.last))) { - ; - } + image_remove_all_tiles(ima); int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number; bool needs_final_cleanup = true; @@ -3257,8 +3364,7 @@ ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *la } } - ImageTile *tile = MEM_cnew<ImageTile>("image new tile"); - tile->tile_number = tile_number; + ImageTile *tile = imagetile_alloc(tile_number); if (next_tile) { BLI_insertlinkbefore(&ima->tiles, next_tile, tile); @@ -3293,16 +3399,7 @@ bool BKE_image_remove_tile(struct Image *ima, ImageTile *tile) return false; } - if (BLI_listbase_is_single(&ima->tiles)) { - /* Can't remove the last remaining tile. */ - return false; - } - - image_free_tile(ima, tile); - BLI_remlink(&ima->tiles, tile); - MEM_freeN(tile); - - return true; + return image_remove_tile(ima, tile); } void BKE_image_reassign_tile(struct Image *ima, ImageTile *tile, int new_tile_number) @@ -3364,14 +3461,7 @@ void BKE_image_sort_tiles(struct Image *ima) BLI_listbase_sort(&ima->tiles, tile_sort_cb); } -bool BKE_image_fill_tile(struct Image *ima, - ImageTile *tile, - int width, - int height, - const float color[4], - int gen_type, - int planes, - bool is_float) +bool BKE_image_fill_tile(struct Image *ima, ImageTile *tile) { if (ima == nullptr || tile == nullptr || ima->source != IMA_SRC_TILED) { return false; @@ -3379,8 +3469,7 @@ bool BKE_image_fill_tile(struct Image *ima, image_free_tile(ima, tile); - ImBuf *tile_ibuf = add_ibuf_size( - width, height, ima->filepath, planes, is_float, gen_type, color, &ima->colorspace_settings); + ImBuf *tile_ibuf = add_ibuf_for_tile(ima, tile); if (tile_ibuf != nullptr) { image_assign_ibuf(ima, tile_ibuf, 0, tile->tile_number); @@ -4553,14 +4642,22 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) } } else if (ima->source == IMA_SRC_TILED) { - if (ima->type == IMA_TYPE_IMAGE) { - /* Regular files, ibufs in flip-book, allows saving */ - ibuf = image_load_image_file(ima, iuser, entry, 0, false); + /* Nothing was cached. Check to see if the tile should be generated. */ + ImageTile *tile = BKE_image_get_tile(ima, entry); + if ((tile->gen_flag & IMA_GEN_TILE) != 0) { + ibuf = add_ibuf_for_tile(ima, tile); + image_assign_ibuf(ima, ibuf, 0, entry); } - /* no else; on load the ima type can change */ - if (ima->type == IMA_TYPE_MULTILAYER) { - /* Only 1 layer/pass stored in imbufs, no EXR-handle anim storage, no saving. */ - ibuf = image_load_sequence_multilayer(ima, iuser, entry, 0); + else { + if (ima->type == IMA_TYPE_IMAGE) { + /* Regular files, ibufs in flip-book, allows saving */ + ibuf = image_load_image_file(ima, iuser, entry, 0, false); + } + /* no else; on load the ima type can change */ + if (ima->type == IMA_TYPE_MULTILAYER) { + /* Only 1 layer/pass stored in imbufs, no EXR-handle anim storage, no saving. */ + ibuf = image_load_sequence_multilayer(ima, iuser, entry, 0); + } } } else if (ima->source == IMA_SRC_FILE) { @@ -4578,23 +4675,17 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) else if (ima->source == IMA_SRC_GENERATED) { /* Generated is: `ibuf` is allocated dynamically. */ /* UV test-grid or black or solid etc. */ - if (ima->gen_x == 0) { - ima->gen_x = 1024; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + if (base_tile->gen_x == 0) { + base_tile->gen_x = 1024; } - if (ima->gen_y == 0) { - ima->gen_y = 1024; + if (base_tile->gen_y == 0) { + base_tile->gen_y = 1024; } - if (ima->gen_depth == 0) { - ima->gen_depth = 24; + if (base_tile->gen_depth == 0) { + base_tile->gen_depth = 24; } - ibuf = add_ibuf_size(ima->gen_x, - ima->gen_y, - ima->filepath, - ima->gen_depth, - (ima->gen_flag & IMA_GEN_FLOAT) != 0, - ima->gen_type, - ima->gen_color, - &ima->colorspace_settings); + ibuf = add_ibuf_for_tile(ima, base_tile); image_assign_ibuf(ima, ibuf, index, 0); } else if (ima->source == IMA_SRC_VIEWER) { diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc index 6506b40b603..08fdd715512 100644 --- a/source/blender/blenkernel/intern/image_gpu.cc +++ b/source/blender/blenkernel/intern/image_gpu.cc @@ -138,6 +138,8 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) int arraywidth = 0, arrayheight = 0; ListBase boxes = {nullptr}; + int planes = 0; + LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { ImageUser iuser; BKE_imageuser_default(&iuser); @@ -164,6 +166,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) BKE_image_release_ibuf(ima, ibuf, nullptr); BLI_addtail(&boxes, packtile); + planes = max_ii(planes, ibuf->planes); } } @@ -195,9 +198,15 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) } const bool use_high_bitdepth = (ima->flag & IMA_HIGH_BITDEPTH); + const bool use_grayscale = planes <= 8; /* Create Texture without content. */ - GPUTexture *tex = IMB_touch_gpu_texture( - ima->id.name + 2, main_ibuf, arraywidth, arrayheight, arraylayers, use_high_bitdepth); + GPUTexture *tex = IMB_touch_gpu_texture(ima->id.name + 2, + main_ibuf, + arraywidth, + arrayheight, + arraylayers, + use_high_bitdepth, + use_grayscale); /* Upload each tile one by one. */ LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { @@ -223,6 +232,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *main_ibuf) tilelayer, UNPACK2(tilesize), use_high_bitdepth, + use_grayscale, store_premultiplied); } diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc index 7d7d49275ba..5ee1258c512 100644 --- a/source/blender/blenkernel/intern/image_save.cc +++ b/source/blender/blenkernel/intern/image_save.cc @@ -316,6 +316,8 @@ static void image_save_post(ReportList *reports, if (ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) { ima->source = IMA_SRC_FILE; ima->type = IMA_TYPE_IMAGE; + ImageTile *base_tile = BKE_image_get_tile(ima, 0); + base_tile->gen_flag &= ~IMA_GEN_TILE; } /* Update image file color space when saving to another color space. */ @@ -662,8 +664,11 @@ bool BKE_image_save( } } - /* Set the image path only if all tiles were ok. */ + /* Set the image path and clear the per-tile generated flag only if all tiles were ok. */ if (ok) { + LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { + tile->gen_flag &= ~IMA_GEN_TILE; + } image_save_update_filepath(ima, opts->filepath, opts); } MEM_freeN(udim_pattern); diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index b5c025a40b6..6fb67711ae9 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -398,21 +398,6 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name) return lt; } -bool object_deform_mball(Object *ob, ListBase *dispbase) -{ - if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) { - DispList *dl; - - for (dl = dispbase->first; dl; dl = dl->next) { - BKE_lattice_deform_coords(ob->parent, ob, (float(*)[3])dl->verts, dl->nr, 0, NULL, 1.0f); - } - - return true; - } - - return false; -} - static BPoint *latt_bp(Lattice *lt, int u, int v, int w) { return <->def[BKE_lattice_index_from_uvw(lt, u, v, w)]; diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 4257bccad93..53a9b6d469d 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -572,7 +572,7 @@ void BKE_view_layer_rename(Main *bmain, Scene *scene, ViewLayer *view_layer, con } /* Dependency graph uses view layer name based lookups. */ - DEG_id_tag_update(&scene->id, 0); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); } /* LayerCollection */ diff --git a/source/blender/blenkernel/intern/layer_utils.c b/source/blender/blenkernel/intern/layer_utils.c index 0903c2a2cac..13e0a0bcf84 100644 --- a/source/blender/blenkernel/intern/layer_utils.c +++ b/source/blender/blenkernel/intern/layer_utils.c @@ -149,6 +149,65 @@ Object **BKE_view_layer_array_from_objects_in_mode_params(ViewLayer *view_layer, return (Object **)base_array; } +struct Object **BKE_view_layer_array_from_objects_in_edit_mode(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + return BKE_view_layer_array_from_objects_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Base **BKE_view_layer_array_from_bases_in_edit_mode(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + return BKE_view_layer_array_from_bases_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Object **BKE_view_layer_array_from_objects_in_edit_mode_unique_data(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + params.no_dup_data = true; + return BKE_view_layer_array_from_objects_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Base **BKE_view_layer_array_from_bases_in_edit_mode_unique_data(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + params.no_dup_data = true; + return BKE_view_layer_array_from_bases_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Object **BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + ViewLayer *view_layer, const View3D *v3d, uint *r_len) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = OB_MODE_EDIT; + params.no_dup_data = true; + params.filter_fn = BKE_view_layer_filter_edit_mesh_has_uvs; + return BKE_view_layer_array_from_objects_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + +struct Object **BKE_view_layer_array_from_objects_in_mode_unique_data(ViewLayer *view_layer, + const View3D *v3d, + uint *r_len, + const eObjectMode mode) +{ + struct ObjectsInModeParams params = {0}; + params.object_mode = mode; + params.no_dup_data = true; + return BKE_view_layer_array_from_objects_in_mode_params(view_layer, v3d, r_len, ¶ms); +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 3778e308db6..5a394a05d86 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -59,6 +59,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "RNA_access.h" @@ -708,6 +709,58 @@ ID *BKE_id_copy_for_duplicate(Main *bmain, return id->newid; } +static int foreach_assign_id_to_orig_callback(LibraryIDLinkCallbackData *cb_data) +{ + ID **id_p = cb_data->id_pointer; + + if (*id_p) { + ID *id = *id_p; + *id_p = DEG_get_original_id(id); + + /* If the ID changes increase the user count. + * + * This means that the reference to evaluated ID has been changed with a reference to the + * original ID which implies that the user count of the original ID is increased. + * + * The evaluated IDs do not maintain their user counter, so do not change it to avoid issues + * with the user counter going negative. */ + if (*id_p != id) { + if ((cb_data->cb_flag & IDWALK_CB_USER) != 0) { + id_us_plus(*id_p); + } + } + } + + return IDWALK_RET_NOP; +} + +ID *BKE_id_copy_for_use_in_bmain(Main *bmain, const ID *id) +{ + ID *newid = BKE_id_copy(bmain, id); + + if (newid == NULL) { + return newid; + } + + /* Assign ID references directly used by the given ID to their original complementary parts. + * + * For example, when is called on an evaluated object will assign object->data to its original + * pointer, the evaluated object->data will be kept unchanged. */ + BKE_library_foreach_ID_link(NULL, newid, foreach_assign_id_to_orig_callback, NULL, IDWALK_NOP); + + /* Shape keys reference on evaluated ID is preserved to keep driver paths available, but the key + * data is likely to be invalid now due to modifiers, so clear the shape key reference avoiding + * any possible shape corruption. */ + if (DEG_is_evaluated_id(id)) { + Key **key_p = BKE_key_from_id_p(newid); + if (key_p) { + *key_p = NULL; + } + } + + return newid; +} + /** * Does a mere memory swap over the whole IDs data (including type-specific memory). * \note Most internal ID data itself is not swapped (only IDProperties are). diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 6b9d2afe87a..38d1a30592d 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -696,8 +696,8 @@ static void lib_query_unused_ids_tag_recurse(Main *bmain, bool has_valid_from_users = false; /* Preemptively consider this ID as unused. That way if there is a loop of dependency leading * back to it, it won't create a fake 'valid user' detection. - * NOTE: This can only only be done for a subset of IDs, some types are never 'indirectly - * unused', same for IDs with a fake user. */ + * NOTE: This can only be done for a subset of IDs, some types are never 'indirectly unused', + * same for IDs with a fake user. */ if ((id->flag & LIB_FAKEUSER) == 0 && !ELEM(GS(id->name), ID_SCE, ID_WM, ID_SCR, ID_WS, ID_LI)) { id->tag |= tag; } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index dd58c9cc4fe..9424b615031 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -122,7 +122,7 @@ void BKE_library_filepath_set(Main *bmain, Library *lib, const char *filepath) /* Not essential but set `filepath_abs` is an absolute copy of value which * is more useful if its kept in sync. */ if (BLI_path_is_rel(lib->filepath_abs)) { - /* NOTE(campbell): the file may be unsaved, in this case, setting the + /* NOTE(@campbellbarton): the file may be unsaved, in this case, setting the * `filepath_abs` on an indirectly linked path is not allowed from the * outliner, and its not really supported but allow from here for now * since making local could cause this to be directly linked. diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index f899901b54e..248d292664a 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -852,7 +852,7 @@ void BKE_object_material_resize(Main *bmain, Object *ob, const short totcol, boo ob->mat = newmatar; ob->matbits = newmatbits; } - /* XXX(campbell): why not realloc on shrink? */ + /* XXX(@campbellbarton): why not realloc on shrink? */ ob->totcol = totcol; if (ob->totcol && ob->actcol == 0) { diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.cc index 2a1c940493c..2ff8e6fc061 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.cc @@ -4,19 +4,16 @@ /** \file * \ingroup bke * - * MetaBalls are created from a single Object (with a name without number in it), - * here the DispList and BoundBox also is located. + * MetaBalls are created from a single Object (with a name without number in it). * All objects with the same name (but with a number in it) are added to this. - * - * texture coordinates are patched within the displist */ -#include <ctype.h> -#include <float.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include <cctype> +#include <cfloat> +#include <cmath> +#include <cstdio> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -25,6 +22,7 @@ #include "DNA_defaults.h" #include "DNA_material_types.h" +#include "DNA_mesh_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -41,11 +39,15 @@ #include "BKE_anim_data.h" #include "BKE_curve.h" #include "BKE_displist.h" +#include "BKE_geometry_set.hh" #include "BKE_idtype.h" +#include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_material.h" #include "BKE_mball.h" +#include "BKE_mball_tessellate.h" +#include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -72,19 +74,16 @@ static void metaball_copy_data(Main *UNUSED(bmain), BLI_duplicatelist(&metaball_dst->elems, &metaball_src->elems); - metaball_dst->mat = MEM_dupallocN(metaball_src->mat); + metaball_dst->mat = static_cast<Material **>(MEM_dupallocN(metaball_src->mat)); - metaball_dst->editelems = NULL; - metaball_dst->lastelem = NULL; - metaball_dst->batch_cache = NULL; + metaball_dst->editelems = nullptr; + metaball_dst->lastelem = nullptr; } static void metaball_free_data(ID *id) { MetaBall *metaball = (MetaBall *)id; - BKE_mball_batch_cache_free(metaball); - MEM_SAFE_FREE(metaball->mat); BLI_freelistN(&metaball->elems); @@ -107,11 +106,10 @@ static void metaball_blend_write(BlendWriter *writer, ID *id, const void *id_add /* Clean up, important in undo case to reduce false detection of changed datablocks. */ BLI_listbase_clear(&mb->disp); - mb->editelems = NULL; + mb->editelems = nullptr; /* Must always be cleared (meta's don't have their own edit-data). */ mb->needs_flush_to_id = 0; - mb->lastelem = NULL; - mb->batch_cache = NULL; + mb->lastelem = nullptr; /* write LibData */ BLO_write_id_struct(writer, MetaBall, id_address, &mb->id); @@ -139,12 +137,11 @@ static void metaball_blend_read_data(BlendDataReader *reader, ID *id) BLO_read_list(reader, &(mb->elems)); BLI_listbase_clear(&mb->disp); - mb->editelems = NULL; + mb->editelems = nullptr; /* Must always be cleared (meta's don't have their own edit-data). */ mb->needs_flush_to_id = 0; - // mb->edit_elems.first = mb->edit_elems.last = NULL; - mb->lastelem = NULL; - mb->batch_cache = NULL; + // mb->edit_elems.first = mb->edit_elems.last = nullptr; + mb->lastelem = nullptr; } static void metaball_blend_read_lib(BlendLibReader *reader, ID *id) @@ -166,49 +163,46 @@ static void metaball_blend_read_expand(BlendExpander *expander, ID *id) } IDTypeInfo IDType_ID_MB = { - .id_code = ID_MB, - .id_filter = FILTER_ID_MB, - .main_listbase_index = INDEX_ID_MB, - .struct_size = sizeof(MetaBall), - .name = "Metaball", - .name_plural = "metaballs", - .translation_context = BLT_I18NCONTEXT_ID_METABALL, - .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, - .asset_type_info = NULL, - - .init_data = metaball_init_data, - .copy_data = metaball_copy_data, - .free_data = metaball_free_data, - .make_local = NULL, - .foreach_id = metaball_foreach_id, - .foreach_cache = NULL, - .foreach_path = NULL, - .owner_get = NULL, - - .blend_write = metaball_blend_write, - .blend_read_data = metaball_blend_read_data, - .blend_read_lib = metaball_blend_read_lib, - .blend_read_expand = metaball_blend_read_expand, - - .blend_read_undo_preserve = NULL, - - .lib_override_apply_post = NULL, + /* id_code */ ID_MB, + /* id_filter */ FILTER_ID_MB, + /* main_listbase_index */ INDEX_ID_MB, + /* struct_size */ sizeof(MetaBall), + /* name */ "Metaball", + /* name_plural */ "metaballs", + /* translation_context */ BLT_I18NCONTEXT_ID_METABALL, + /* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, + /* asset_type_info */ nullptr, + + /* init_data */ metaball_init_data, + /* copy_data */ metaball_copy_data, + /* free_data */ metaball_free_data, + /* make_local */ nullptr, + /* foreach_id */ metaball_foreach_id, + /* foreach_cache */ nullptr, + /* foreach_path */ nullptr, + /* owner_get */ nullptr, + + /* blend_write */ metaball_blend_write, + /* blend_read_data */ metaball_blend_read_data, + /* blend_read_lib */ metaball_blend_read_lib, + /* blend_read_expand */ metaball_blend_read_expand, + + /* blend_read_undo_preserve */ nullptr, + + /* lib_override_apply_post */ nullptr, }; /* Functions */ MetaBall *BKE_mball_add(Main *bmain, const char *name) { - MetaBall *mb; - - mb = BKE_id_new(bmain, ID_MB, name); - + MetaBall *mb = static_cast<MetaBall *>(BKE_id_new(bmain, ID_MB, name)); return mb; } MetaElem *BKE_mball_element_add(MetaBall *mb, const int type) { - MetaElem *ml = MEM_callocN(sizeof(MetaElem), "metaelem"); + MetaElem *ml = MEM_cnew<MetaElem>(__func__); unit_qt(ml->quat); @@ -252,99 +246,37 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type) return ml; } -void BKE_mball_texspace_calc(Object *ob) -{ - DispList *dl; - BoundBox *bb; - float *data, min[3], max[3] /*, loc[3], size[3] */; - int tot; - bool do_it = false; - - if (ob->runtime.bb == NULL) { - ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "mb boundbox"); - } - bb = ob->runtime.bb; - - /* Weird one, this. */ - // INIT_MINMAX(min, max); - (min)[0] = (min)[1] = (min)[2] = 1.0e30f; - (max)[0] = (max)[1] = (max)[2] = -1.0e30f; - - dl = ob->runtime.curve_cache->disp.first; - while (dl) { - tot = dl->nr; - if (tot) { - do_it = true; - } - data = dl->verts; - while (tot--) { - /* Also weird... but longer. From utildefines. */ - minmax_v3v3_v3(min, max, data); - data += 3; - } - dl = dl->next; - } - - if (!do_it) { - min[0] = min[1] = min[2] = -1.0f; - max[0] = max[1] = max[2] = 1.0f; - } - - BKE_boundbox_init_from_minmax(bb, min, max); - - bb->flag &= ~BOUNDBOX_DIRTY; -} BoundBox *BKE_mball_boundbox_get(Object *ob) { BLI_assert(ob->type == OB_MBALL); - - if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { + if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { return ob->runtime.bb; } - - /* This should always only be called with evaluated objects, - * but currently RNA is a problem here... */ - if (ob->runtime.curve_cache != NULL) { - BKE_mball_texspace_calc(ob); + if (ob->runtime.bb == nullptr) { + ob->runtime.bb = MEM_cnew<BoundBox>(__func__); } - return ob->runtime.bb; -} - -float *BKE_mball_make_orco(Object *ob, ListBase *dispbase) -{ - BoundBox *bb; - DispList *dl; - float *data, *orco, *orcodata; - float loc[3], size[3]; - int a; - - /* restore size and loc */ - bb = ob->runtime.bb; - loc[0] = (bb->vec[0][0] + bb->vec[4][0]) / 2.0f; - size[0] = bb->vec[4][0] - loc[0]; - loc[1] = (bb->vec[0][1] + bb->vec[2][1]) / 2.0f; - size[1] = bb->vec[2][1] - loc[1]; - loc[2] = (bb->vec[0][2] + bb->vec[1][2]) / 2.0f; - size[2] = bb->vec[1][2] - loc[2]; - - dl = dispbase->first; - orcodata = MEM_mallocN(sizeof(float[3]) * dl->nr, "MballOrco"); - - data = dl->verts; - orco = orcodata; - a = dl->nr; - while (a--) { - orco[0] = (data[0] - loc[0]) / size[0]; - orco[1] = (data[1] - loc[1]) / size[1]; - orco[2] = (data[2] - loc[2]) / size[2]; - - data += 3; - orco += 3; + /* Expect that this function is only called for evaluated objects. */ + const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + float min[3]; + float max[3]; + if (mesh_eval) { + INIT_MINMAX(min, max); + if (!BKE_mesh_minmax(mesh_eval, min, max)) { + copy_v3_fl(min, -1.0f); + copy_v3_fl(max, 1.0f); + } + } + else { + copy_v3_fl(min, 0.0f); + copy_v3_fl(max, 0.0f); } - return orcodata; + BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); + ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; + + return ob->runtime.bb; } bool BKE_mball_is_basis(const Object *ob) @@ -393,7 +325,7 @@ bool BKE_mball_is_basis_for(const Object *ob1, const Object *ob2) bool BKE_mball_is_any_selected(const MetaBall *mb) { - for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) { + LISTBASE_FOREACH (const MetaElem *, ml, mb->editelems) { if (ml->flag & SELECT) { return true; } @@ -415,7 +347,7 @@ bool BKE_mball_is_any_selected_multi(Base **bases, int bases_len) bool BKE_mball_is_any_unselected(const MetaBall *mb) { - for (const MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) { + LISTBASE_FOREACH (const MetaElem *, ml, mb->editelems) { if ((ml->flag & SELECT) == 0) { return true; } @@ -451,9 +383,10 @@ void BKE_mball_properties_copy(Main *bmain, MetaBall *metaball_src) * Solving this case would drastically increase the complexity of this code though, so don't * think it would be worth it. */ - for (Object *ob_src = bmain->objects.first; ob_src != NULL && !ID_IS_LINKED(ob_src);) { + for (Object *ob_src = static_cast<Object *>(bmain->objects.first); + ob_src != nullptr && !ID_IS_LINKED(ob_src);) { if (ob_src->data != metaball_src) { - ob_src = ob_src->id.next; + ob_src = static_cast<Object *>(ob_src->id.next); continue; } @@ -466,12 +399,13 @@ void BKE_mball_properties_copy(Main *bmain, MetaBall *metaball_src) * Using this, it is possible to process the whole set of meta-balls with a single loop on the * whole list of Objects, though additionally going backward on part of the list in some cases. */ - Object *ob_iter = NULL; + Object *ob_iter = nullptr; int obactive_nr, ob_nr; char obactive_name[MAX_ID_NAME], ob_name[MAX_ID_NAME]; BLI_split_name_num(obactive_name, &obactive_nr, ob_src->id.name + 2, '.'); - for (ob_iter = ob_src->id.prev; ob_iter != NULL; ob_iter = ob_iter->id.prev) { + for (ob_iter = static_cast<Object *>(ob_src->id.prev); ob_iter != nullptr; + ob_iter = static_cast<Object *>(ob_iter->id.prev)) { if (ob_iter->id.name[2] != obactive_name[0]) { break; } @@ -483,10 +417,11 @@ void BKE_mball_properties_copy(Main *bmain, MetaBall *metaball_src) break; } - mball_data_properties_copy(ob_iter->data, metaball_src); + mball_data_properties_copy(static_cast<MetaBall *>(ob_iter->data), metaball_src); } - for (ob_iter = ob_src->id.next; ob_iter != NULL; ob_iter = ob_iter->id.next) { + for (ob_iter = static_cast<Object *>(ob_src->id.next); ob_iter != nullptr; + ob_iter = static_cast<Object *>(ob_iter->id.next)) { if (ob_iter->id.name[2] != obactive_name[0] || ID_IS_LINKED(ob_iter)) { break; } @@ -498,7 +433,7 @@ void BKE_mball_properties_copy(Main *bmain, MetaBall *metaball_src) break; } - mball_data_properties_copy(ob_iter->data, metaball_src); + mball_data_properties_copy(static_cast<MetaBall *>(ob_iter->data), metaball_src); } ob_src = ob_iter; @@ -556,7 +491,7 @@ bool BKE_mball_minmax_ex( copy_v3_v3(centroid, &ml->x); } - /* TODO(campbell): non circle shapes cubes etc, probably nobody notices. */ + /* TODO(@campbellbarton): non circle shapes cubes etc, probably nobody notices. */ for (int i = -1; i != 3; i += 2) { copy_v3_v3(vec, centroid); add_v3_fl(vec, scale_mb * i); @@ -682,7 +617,7 @@ bool BKE_mball_select_all_multi_ex(Base **bases, int bases_len) bool changed_multi = false; for (uint ob_index = 0; ob_index < bases_len; ob_index++) { Object *obedit = bases[ob_index]->object; - MetaBall *mb = obedit->data; + MetaBall *mb = static_cast<MetaBall *>(obedit->data); changed_multi |= BKE_mball_select_all(mb); } return changed_multi; @@ -705,7 +640,7 @@ bool BKE_mball_deselect_all_multi_ex(Base **bases, int bases_len) bool changed_multi = false; for (uint ob_index = 0; ob_index < bases_len; ob_index++) { Object *obedit = bases[ob_index]->object; - MetaBall *mb = obedit->data; + MetaBall *mb = static_cast<MetaBall *>(obedit->data); changed_multi |= BKE_mball_deselect_all(mb); DEG_id_tag_update(&mb->id, ID_RECALC_SELECT); } @@ -735,20 +670,44 @@ bool BKE_mball_select_swap_multi_ex(Base **bases, int bases_len) /* **** Depsgraph evaluation **** */ -/* Draw Engine */ +void BKE_mball_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + BLI_assert(ob->type == OB_MBALL); -void (*BKE_mball_batch_cache_dirty_tag_cb)(MetaBall *mb, int mode) = NULL; -void (*BKE_mball_batch_cache_free_cb)(MetaBall *mb) = NULL; + BKE_object_free_derived_caches(ob); -void BKE_mball_batch_cache_dirty_tag(MetaBall *mb, int mode) -{ - if (mb->batch_cache) { - BKE_mball_batch_cache_dirty_tag_cb(mb, mode); + const Object *basis_object = BKE_mball_basis_find(scene, ob); + if (ob != basis_object) { + return; } -} -void BKE_mball_batch_cache_free(MetaBall *mb) -{ - if (mb->batch_cache) { - BKE_mball_batch_cache_free_cb(mb); + + Mesh *mesh = BKE_mball_polygonize(depsgraph, scene, ob); + if (mesh == nullptr) { + return; } -} + + const MetaBall *mball = static_cast<MetaBall *>(ob->data); + mesh->mat = static_cast<Material **>(MEM_dupallocN(mball->mat)); + mesh->totcol = mball->totcol; + + if (ob->parent && ob->parent->type == OB_LATTICE && ob->partype == PARSKEL) { + int verts_num; + float(*positions)[3] = BKE_mesh_vert_coords_alloc(mesh, &verts_num); + BKE_lattice_deform_coords(ob->parent, ob, positions, verts_num, 0, nullptr, 1.0f); + BKE_mesh_vert_coords_apply(mesh, positions); + MEM_freeN(positions); + } + + ob->runtime.geometry_set_eval = new GeometrySet(GeometrySet::create_with_mesh(mesh)); + + if (ob->runtime.bb == nullptr) { + ob->runtime.bb = MEM_cnew<BoundBox>(__func__); + } + blender::float3 min(std::numeric_limits<float>::max()); + blender::float3 max(-std::numeric_limits<float>::max()); + if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) { + min = blender::float3(0); + max = blender::float3(0); + } + BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); +}; diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 54def0189b1..bfa11b74782 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -14,6 +14,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -24,10 +26,11 @@ #include "BLI_string_utils.h" #include "BLI_utildefines.h" -#include "BKE_global.h" - #include "BKE_displist.h" +#include "BKE_global.h" +#include "BKE_lib_id.h" #include "BKE_mball_tessellate.h" /* own include */ +#include "BKE_mesh.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -427,8 +430,6 @@ static float metaball(PROCESS *process, float x, float y, float z) */ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4) { - int *cur; - #ifdef USE_ACCUM_NORMAL float n[3]; #endif @@ -438,10 +439,9 @@ static void make_face(PROCESS *process, int i1, int i2, int i3, int i4) process->indices = MEM_reallocN(process->indices, sizeof(int[4]) * process->totindex); } - cur = process->indices[process->curindex++]; - - /* #DispList supports array drawing, treat tri's as fake quad. */ + int *cur = process->indices[process->curindex++]; + /* Treat triangles as fake quads. */ cur[0] = i1; cur[1] = i2; cur[2] = i3; @@ -1371,7 +1371,7 @@ static void init_meta(Depsgraph *depsgraph, PROCESS *process, Scene *scene, Obje } } -void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBase *dispbase) +Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) { PROCESS process = {0}; const bool is_render = DEG_get_mode(depsgraph) == DAG_EVAL_RENDER; @@ -1394,10 +1394,10 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa } if (!is_render && (mb->flag == MB_UPDATE_NEVER)) { - return; + return NULL; } if ((G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT)) && mb->flag == MB_UPDATE_FAST) { - return; + return NULL; } if (is_render) { @@ -1418,7 +1418,7 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa init_meta(depsgraph, &process, scene, ob); if (process.totelem == 0) { freepolygonize(&process); - return; + return NULL; } build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); @@ -1430,40 +1430,64 @@ void BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob, ListBa ob->scale[1] < 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) || ob->scale[2] < 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) { freepolygonize(&process); - return; + return NULL; } polygonize(&process); if (process.curindex == 0) { freepolygonize(&process); - return; + return NULL; } - /* add resulting surface to displist */ + freepolygonize(&process); + + Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name + 2); - /* Avoid over-allocation since this is stored in the displist. */ - if (process.curindex != process.totindex) { - process.indices = MEM_reallocN(process.indices, sizeof(int[4]) * process.curindex); + mesh->totvert = (int)process.curvertex; + MVert *mvert = CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CONSTRUCT, NULL, mesh->totvert); + for (int i = 0; i < mesh->totvert; i++) { + copy_v3_v3(mvert[i].co, process.co[i]); + mvert->bweight = 0; + mvert->flag = 0; } - if (process.curvertex != process.totvertex) { - process.co = MEM_reallocN(process.co, process.curvertex * sizeof(float[3])); - process.no = MEM_reallocN(process.no, process.curvertex * sizeof(float[3])); + MEM_freeN(process.co); + + mesh->totpoly = (int)process.curindex; + MPoly *mpoly = CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CONSTRUCT, NULL, mesh->totpoly); + MLoop *mloop = CustomData_add_layer( + &mesh->ldata, CD_MLOOP, CD_CONSTRUCT, NULL, mesh->totpoly * 4); + + int loop_offset = 0; + for (int i = 0; i < mesh->totpoly; i++) { + const int *indices = process.indices[i]; + + const int count = indices[2] != indices[3] ? 4 : 3; + mpoly[i].loopstart = loop_offset; + mpoly[i].totloop = count; + mpoly[i].flag = ME_SMOOTH; + + mloop[loop_offset].v = (uint32_t)indices[0]; + mloop[loop_offset + 1].v = (uint32_t)indices[1]; + mloop[loop_offset + 2].v = (uint32_t)indices[2]; + if (count == 4) { + mloop[loop_offset + 3].v = (uint32_t)indices[3]; + } + + loop_offset += count; } + MEM_freeN(process.indices); - DispList *dl = MEM_callocN(sizeof(DispList), "mballdisp"); - BLI_addtail(dispbase, dl); - dl->type = DL_INDEX4; - dl->nr = (int)process.curvertex; - dl->parts = (int)process.curindex; + for (int i = 0; i < mesh->totvert; i++) { + normalize_v3(process.no[i]); + } + mesh->runtime.vert_normals = process.no; + BKE_mesh_vertex_normals_clear_dirty(mesh); - dl->index = (int *)process.indices; + mesh->totloop = loop_offset; - for (uint a = 0; a < process.curvertex; a++) { - normalize_v3(process.no[a]); - } + BKE_mesh_update_customdata_pointers(mesh, false); - dl->verts = (float *)process.co; - dl->nors = (float *)process.no; + BKE_mesh_calc_edges(mesh, false, false); - freepolygonize(&process); + return mesh; } diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index afd8e49f884..b44a956eec4 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -28,14 +28,17 @@ #include "BLI_math.h" #include "BLI_math_vector.hh" #include "BLI_memarena.h" +#include "BLI_span.hh" #include "BLI_string.h" #include "BLI_task.hh" #include "BLI_utildefines.h" #include "BLI_vector.hh" +#include "BLI_virtual_array.hh" #include "BLT_translation.h" #include "BKE_anim_data.h" +#include "BKE_attribute.hh" #include "BKE_bpath.h" #include "BKE_deform.h" #include "BKE_editmesh.h" @@ -62,6 +65,8 @@ #include "BLO_read_write.h" using blender::float3; +using blender::MutableSpan; +using blender::VArray; using blender::Vector; static void mesh_clear_geometry(Mesh *mesh); @@ -113,7 +118,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int * * While this could be the callers responsibility, keep here since it's * highly unlikely we want to create a duplicate and not use it for drawing. */ - mesh_dst->runtime.is_original = false; + mesh_dst->runtime.is_original_bmesh = false; /* Only do tessface if we have no polys. */ const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0)); @@ -212,6 +217,7 @@ static void mesh_foreach_path(ID *id, BPathForeachPathData *bpath_data) static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address) { + using namespace blender; Mesh *mesh = (Mesh *)id; const bool is_undo = BLO_write_is_undo(writer); @@ -245,10 +251,18 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address memset(&mesh->pdata, 0, sizeof(mesh->pdata)); } else { - CustomData_blend_write_prepare(mesh->vdata, vert_layers); - CustomData_blend_write_prepare(mesh->edata, edge_layers); - CustomData_blend_write_prepare(mesh->ldata, loop_layers); - CustomData_blend_write_prepare(mesh->pdata, poly_layers); + Set<std::string> names_to_skip; + if (!BLO_write_is_undo(writer)) { + BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); + BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh); + /* When converting to the old mesh format, don't save redundant attributes. */ + names_to_skip.add_multiple_new({".hide_vert", ".hide_edge", ".hide_poly"}); + } + + CustomData_blend_write_prepare(mesh->vdata, vert_layers, names_to_skip); + CustomData_blend_write_prepare(mesh->edata, edge_layers, names_to_skip); + CustomData_blend_write_prepare(mesh->ldata, loop_layers, names_to_skip); + CustomData_blend_write_prepare(mesh->pdata, poly_layers, names_to_skip); } BLO_write_id_struct(writer, Mesh, id_address, &mesh->id); @@ -327,6 +341,11 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) } } + if (!BLO_read_data_is_undo(reader)) { + BKE_mesh_legacy_convert_flags_to_hide_layers(mesh); + BKE_mesh_legacy_convert_mpoly_to_material_indices(mesh); + } + /* We don't expect to load normals from files, since they are derived data. */ BKE_mesh_normals_tag_dirty(mesh); BKE_mesh_assert_normals_dirty_or_calculated(mesh); @@ -465,7 +484,8 @@ static int customdata_compare( } if (layer_count1 != layer_count2) { - return MESHCMP_CDLAYERS_MISMATCH; + /* TODO(@HooglyBoogly): Reenable after tests are updated for material index refactor. */ + // return MESHCMP_CDLAYERS_MISMATCH; } l1 = c1->layers; @@ -764,10 +784,10 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) /* TODO: add some `--debug-mesh` option. */ if (G.debug & G_DEBUG) { - /* NOTE(campbell): this warning may be un-called for if we are initializing the mesh for - * the first time from #BMesh, rather than giving a warning about this we could be smarter - * and check if there was any data to begin with, for now just print the warning with - * some info to help troubleshoot what's going on. */ + /* NOTE(@campbellbarton): this warning may be un-called for if we are initializing the mesh + * for the first time from #BMesh, rather than giving a warning about this we could be + * smarter and check if there was any data to begin with, for now just print the warning + * with some info to help troubleshoot what's going on. */ printf( "%s: warning! Tessellation uvs or vcol data got out of sync, " "had to reset!\n CD_MTFACE: %d != CD_MLOOPUV: %d || CD_MCOL: %d != " @@ -806,7 +826,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) else { if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { vs = (MVertSkin *)CustomData_add_layer( - &me->vdata, CD_MVERT_SKIN, CD_DEFAULT, nullptr, me->totvert); + &me->vdata, CD_MVERT_SKIN, CD_SET_DEFAULT, nullptr, me->totvert); /* Mark an arbitrary vertex as root */ if (vs) { @@ -828,7 +848,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) } else { if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { - CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, nullptr, me->totpoly); + CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, nullptr, me->totpoly); changed = true; } } @@ -971,20 +991,20 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) { if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) { - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, mesh->totvert); } if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh->totedge); } if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); } if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); } if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) { - CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, nullptr, mesh->totface); + CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_SET_DEFAULT, nullptr, mesh->totface); } } @@ -1081,12 +1101,12 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, me_dst->cd_flag = me_src->cd_flag; BKE_mesh_copy_parameters_for_eval(me_dst, me_src); - CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_CALLOC, verts_len); - CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_CALLOC, edges_len); - CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_CALLOC, loops_len); - CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_CALLOC, polys_len); + CustomData_copy(&me_src->vdata, &me_dst->vdata, mask.vmask, CD_SET_DEFAULT, verts_len); + CustomData_copy(&me_src->edata, &me_dst->edata, mask.emask, CD_SET_DEFAULT, edges_len); + CustomData_copy(&me_src->ldata, &me_dst->ldata, mask.lmask, CD_SET_DEFAULT, loops_len); + CustomData_copy(&me_src->pdata, &me_dst->pdata, mask.pmask, CD_SET_DEFAULT, polys_len); if (do_tessface) { - CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_CALLOC, tessface_len); + CustomData_copy(&me_src->fdata, &me_dst->fdata, mask.fmask, CD_SET_DEFAULT, tessface_len); } else { mesh_tessface_clear_intern(me_dst, false); @@ -1187,7 +1207,7 @@ static void ensure_orig_index_layer(CustomData &data, const int size) if (CustomData_has_layer(&data, CD_ORIGINDEX)) { return; } - int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_DEFAULT, nullptr, size); + int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, size); range_vn_i(indices, size, 0); } @@ -1400,61 +1420,57 @@ void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) void BKE_mesh_material_index_remove(Mesh *me, short index) { - MPoly *mp; - MFace *mf; - int i; - - for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { - if (mp->mat_nr && mp->mat_nr >= index) { - mp->mat_nr--; - } + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index"); + if (!material_indices) { + return; } - - for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { - if (mf->mat_nr && mf->mat_nr >= index) { - mf->mat_nr--; + if (material_indices.domain != ATTR_DOMAIN_FACE) { + BLI_assert_unreachable(); + return; + } + MutableVArraySpan<int> indices_span(material_indices.varray); + for (const int i : indices_span.index_range()) { + if (indices_span[i] > 0 && indices_span[i] > index) { + indices_span[i]--; } } + indices_span.save(); + material_indices.finish(); + + BKE_mesh_tessface_clear(me); } bool BKE_mesh_material_index_used(Mesh *me, short index) { - MPoly *mp; - MFace *mf; - int i; - - for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { - if (mp->mat_nr == index) { - return true; - } - } - - for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { - if (mf->mat_nr == index) { - return true; - } + using namespace blender; + using namespace blender::bke; + const AttributeAccessor attributes = mesh_attributes(*me); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + if (material_indices.is_single()) { + return material_indices.get_internal_single() == index; } - - return false; + const VArraySpan<int> indices_span(material_indices); + return indices_span.contains(index); } void BKE_mesh_material_index_clear(Mesh *me) { - MPoly *mp; - MFace *mf; - int i; - - for (mp = me->mpoly, i = 0; i < me->totpoly; i++, mp++) { - mp->mat_nr = 0; - } + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + attributes.remove("material_index"); - for (mf = me->mface, i = 0; i < me->totface; i++, mf++) { - mf->mat_nr = 0; - } + BKE_mesh_tessface_clear(me); } void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) { + using namespace blender; + using namespace blender::bke; const short remap_len_short = (short)remap_len; #define MAT_NR_REMAP(n) \ @@ -1474,10 +1490,21 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) } } else { - int i; - for (i = 0; i < me->totpoly; i++) { - MAT_NR_REMAP(me->mpoly[i].mat_nr); + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index"); + if (!material_indices) { + return; + } + if (material_indices.domain != ATTR_DOMAIN_FACE) { + BLI_assert_unreachable(); + return; + } + MutableVArraySpan<int> indices_span(material_indices.varray); + for (const int i : indices_span.index_range()) { + MAT_NR_REMAP(indices_span[i]); } + indices_span.save(); + material_indices.finish(); } #undef MAT_NR_REMAP @@ -1866,7 +1893,7 @@ static float (*ensure_corner_normal_layer(Mesh &mesh))[3] } else { r_loopnors = (float(*)[3])CustomData_add_layer( - &mesh.ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh.totloop); + &mesh.ldata, CD_NORMAL, CD_SET_DEFAULT, nullptr, mesh.totloop); CustomData_set_layer_flag(&mesh.ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } return r_loopnors; diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index a1ef2d2e6b5..fb4a9248d8d 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -9,6 +9,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_material.h" #include "BKE_mesh.h" @@ -23,6 +24,7 @@ #include "BLI_mesh_intersect.hh" #include "BLI_span.hh" #include "BLI_task.hh" +#include "BLI_virtual_array.hh" namespace blender::meshintersect { @@ -405,13 +407,17 @@ static void copy_poly_attributes(Mesh *dest_mesh, const Mesh *orig_me, int mp_index, int index_in_orig_me, - Span<short> material_remap) + Span<short> material_remap, + MutableSpan<int> dst_material_indices) { - if (material_remap.size() > 0 && material_remap.index_range().contains(orig_mp->mat_nr)) { - mp->mat_nr = material_remap[orig_mp->mat_nr]; + const VArray<int> src_material_indices = bke::mesh_attributes(*orig_me).lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + const int src_index = src_material_indices[index_in_orig_me]; + if (material_remap.size() > 0 && material_remap.index_range().contains(src_index)) { + dst_material_indices[mp_index] = material_remap[src_index]; } else { - mp->mat_nr = orig_mp->mat_nr; + dst_material_indices[mp_index] = src_index; } mp->flag = orig_mp->flag; @@ -663,15 +669,15 @@ static void merge_vertex_loop_poly_customdata_layers(Mesh *target, MeshesToIMesh const Mesh *me = mim.meshes[mesh_index]; if (me->totvert) { CustomData_merge( - &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_DEFAULT, target->totvert); + &me->vdata, &target->vdata, CD_MASK_MESH.vmask, CD_SET_DEFAULT, target->totvert); } if (me->totloop) { CustomData_merge( - &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_DEFAULT, target->totloop); + &me->ldata, &target->ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, target->totloop); } if (me->totpoly) { CustomData_merge( - &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_DEFAULT, target->totpoly); + &me->pdata, &target->pdata, CD_MASK_MESH.pmask, CD_SET_DEFAULT, target->totpoly); } } } @@ -682,7 +688,7 @@ static void merge_edge_customdata_layers(Mesh *target, MeshesToIMeshInfo &mim) const Mesh *me = mim.meshes[mesh_index]; if (me->totedge) { CustomData_merge( - &me->edata, &target->edata, CD_MASK_MESH.emask, CD_DEFAULT, target->totedge); + &me->edata, &target->edata, CD_MASK_MESH.emask, CD_SET_DEFAULT, target->totedge); } } } @@ -722,6 +728,9 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) /* Set the loopstart and totloop for each output poly, * and set the vertices in the appropriate loops. */ + bke::SpanAttributeWriter<int> dst_material_indices = + bke::mesh_attributes_for_write(*result).lookup_or_add_for_write_only_span<int>( + "material_index", ATTR_DOMAIN_FACE); int cur_loop_index = 0; MLoop *l = result->mloop; for (int fi : im->face_index_range()) { @@ -750,9 +759,11 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) index_in_orig_me, (mim.material_remaps.size() > 0) ? mim.material_remaps[orig_me_index].as_span() : - Span<short>()); + Span<short>(), + dst_material_indices.span); copy_or_interp_loop_attributes(result, f, mp, orig_mp, orig_me, orig_me_index, mim); } + dst_material_indices.finish(); /* BKE_mesh_calc_edges will calculate and populate all the * MEdges from the MPolys. */ diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 81bab9f796f..393d54bb03e 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -22,6 +22,7 @@ #include "BLI_index_range.hh" #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_span.hh" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -54,6 +55,8 @@ #include "DEG_depsgraph_query.h" using blender::IndexRange; +using blender::MutableSpan; +using blender::Span; /* Define for cases when you want extra validation of mesh * after certain modifications. @@ -69,87 +72,31 @@ using blender::IndexRange; static CLG_LogRef LOG = {"bke.mesh_convert"}; -void BKE_mesh_from_metaball(ListBase *lb, Mesh *me) -{ - DispList *dl; - MVert *mvert; - MLoop *mloop, *allloop; - MPoly *mpoly; - int a, *index; - - dl = (DispList *)lb->first; - if (dl == nullptr) { - return; - } - - if (dl->type == DL_INDEX4) { - mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, dl->nr); - allloop = mloop = (MLoop *)CustomData_add_layer( - &me->ldata, CD_MLOOP, CD_CALLOC, nullptr, dl->parts * 4); - mpoly = (MPoly *)CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CALLOC, nullptr, dl->parts); - me->mvert = mvert; - me->mloop = mloop; - me->mpoly = mpoly; - me->totvert = dl->nr; - me->totpoly = dl->parts; - - for (const int i : IndexRange(dl->nr)) { - copy_v3_v3(me->mvert[i].co, &dl->verts[3 * i]); - } - - a = dl->parts; - index = dl->index; - while (a--) { - int count = index[2] != index[3] ? 4 : 3; - - mloop[0].v = index[0]; - mloop[1].v = index[1]; - mloop[2].v = index[2]; - if (count == 4) { - mloop[3].v = index[3]; - } - - mpoly->totloop = count; - mpoly->loopstart = (int)(mloop - allloop); - mpoly->flag = ME_SMOOTH; - - mpoly++; - mloop += count; - me->totloop += count; - index += 4; - } - - BKE_mesh_update_customdata_pointers(me, true); - BKE_mesh_calc_edges(me, true, false); - } -} - /** * Specialized function to use when we _know_ existing edges don't overlap with poly edges. */ -static void make_edges_mdata_extend( - MEdge **r_alledge, int *r_totedge, const MPoly *mpoly, MLoop *mloop, const int totpoly) +static void make_edges_mdata_extend(Mesh &mesh) { - int totedge = *r_totedge; - int totedge_new; - EdgeHash *eh; - uint eh_reserve; + int totedge = mesh.totedge; const MPoly *mp; int i; - eh_reserve = max_ii(totedge, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(totpoly)); - eh = BLI_edgehash_new_ex(__func__, eh_reserve); + Span<MPoly> polys(mesh.mpoly, mesh.totpoly); + MutableSpan<MLoop> loops(mesh.mloop, mesh.totloop); - for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { - BKE_mesh_poly_edgehash_insert(eh, mp, mloop + mp->loopstart); + const int eh_reserve = max_ii(totedge, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(mesh.totpoly)); + EdgeHash *eh = BLI_edgehash_new_ex(__func__, eh_reserve); + + for (const MPoly &poly : polys) { + BKE_mesh_poly_edgehash_insert(eh, &poly, &loops[poly.loopstart]); } - totedge_new = BLI_edgehash_len(eh); + const int totedge_new = BLI_edgehash_len(eh); #ifdef DEBUG /* ensure that there's no overlap! */ if (totedge_new) { - MEdge *medge = *r_alledge; + MEdge *medge = mesh.medge; for (i = 0; i < totedge; i++, medge++) { BLI_assert(BLI_edgehash_haskey(eh, medge->v1, medge->v2) == false); } @@ -157,19 +104,15 @@ static void make_edges_mdata_extend( #endif if (totedge_new) { - EdgeHashIterator *ehi; - MEdge *medge; - uint e_index = totedge; + CustomData_realloc(&mesh.edata, totedge + totedge_new); + BKE_mesh_update_customdata_pointers(&mesh, false); - *r_alledge = medge = (MEdge *)(*r_alledge ? - MEM_reallocN(*r_alledge, - sizeof(MEdge) * (totedge + totedge_new)) : - MEM_calloc_arrayN(totedge_new, sizeof(MEdge), __func__)); - medge += totedge; + MEdge *medge = mesh.medge + totedge; - totedge += totedge_new; + mesh.totedge += totedge_new; - /* --- */ + EdgeHashIterator *ehi; + uint e_index = totedge; for (ehi = BLI_edgehashIterator_new(eh); BLI_edgehashIterator_isDone(ehi) == false; BLI_edgehashIterator_step(ehi), ++medge, e_index++) { BLI_edgehashIterator_getKey(ehi, &medge->v1, &medge->v2); @@ -180,10 +123,8 @@ static void make_edges_mdata_extend( } BLI_edgehashIterator_free(ehi); - *r_totedge = totedge; - - for (i = 0, mp = mpoly; i < totpoly; i++, mp++) { - MLoop *l = &mloop[mp->loopstart]; + for (i = 0, mp = mesh.mpoly; i < mesh.totpoly; i++, mp++) { + MLoop *l = &loops[mp->loopstart]; MLoop *l_prev = (l + (mp->totloop - 1)); int j; for (j = 0; j < mp->totloop; j++, l++) { @@ -197,25 +138,9 @@ static void make_edges_mdata_extend( BLI_edgehash_free(eh, nullptr); } -/* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */ -/* use specified dispbase */ -static int mesh_nurbs_displist_to_mdata(const Curve *cu, - const ListBase *dispbase, - MVert **r_allvert, - int *r_totvert, - MEdge **r_alledge, - int *r_totedge, - MLoop **r_allloop, - MPoly **r_allpoly, - MLoopUV **r_alluv, - int *r_totloop, - int *r_totpoly) +static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispbase) { - MVert *mvert; - MPoly *mpoly; - MLoop *mloop; - MLoopUV *mloopuv = nullptr; - MEdge *medge; + using namespace blender::bke; const float *data; int a, b, ofs, vertcount, startvert, totvert = 0, totedge = 0, totloop = 0, totpoly = 0; int p1, p2, p3, p4, *index; @@ -257,21 +182,24 @@ static int mesh_nurbs_displist_to_mdata(const Curve *cu, } if (totvert == 0) { - /* Make Sure you check ob->data is a curve. */ - // error("can't convert"); - return -1; + return BKE_mesh_new_nomain(0, 0, 0, 0, 0); } - *r_allvert = mvert = (MVert *)MEM_calloc_arrayN(totvert, sizeof(MVert), "nurbs_init mvert"); - *r_alledge = medge = (MEdge *)MEM_calloc_arrayN(totedge, sizeof(MEdge), "nurbs_init medge"); - *r_allloop = mloop = (MLoop *)MEM_calloc_arrayN( - totpoly, sizeof(MLoop[4]), "nurbs_init mloop"); /* totloop */ - *r_allpoly = mpoly = (MPoly *)MEM_calloc_arrayN(totpoly, sizeof(MPoly), "nurbs_init mloop"); + Mesh *mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly); + MutableSpan<MVert> verts(mesh->mvert, mesh->totvert); + MutableSpan<MEdge> edges(mesh->medge, mesh->totedge); + MutableSpan<MPoly> polys(mesh->mpoly, mesh->totpoly); + MutableSpan<MLoop> loops(mesh->mloop, mesh->totloop); - if (r_alluv) { - *r_alluv = mloopuv = (MLoopUV *)MEM_calloc_arrayN( - totpoly, sizeof(MLoopUV[4]), "nurbs_init mloopuv"); - } + MVert *mvert = verts.data(); + MEdge *medge = edges.data(); + MPoly *mpoly = polys.data(); + MLoop *mloop = loops.data(); + MutableAttributeAccessor attributes = mesh_attributes_for_write(*mesh); + SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_only_span<int>( + "material_index", ATTR_DOMAIN_FACE); + MLoopUV *mloopuv = static_cast<MLoopUV *>(CustomData_add_layer_named( + &mesh->ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, mesh->totloop, "UVMap")); /* verts and faces */ vertcount = 0; @@ -346,9 +274,9 @@ static int mesh_nurbs_displist_to_mdata(const Curve *cu, mloop[0].v = startvert + index[0]; mloop[1].v = startvert + index[2]; mloop[2].v = startvert + index[1]; - mpoly->loopstart = (int)(mloop - (*r_allloop)); + mpoly->loopstart = (int)(mloop - loops.data()); mpoly->totloop = 3; - mpoly->mat_nr = dl->col; + material_indices.span[mpoly - polys.data()] = dl->col; if (mloopuv) { for (int i = 0; i < 3; i++, mloopuv++) { @@ -406,9 +334,9 @@ static int mesh_nurbs_displist_to_mdata(const Curve *cu, mloop[1].v = p3; mloop[2].v = p4; mloop[3].v = p2; - mpoly->loopstart = (int)(mloop - (*r_allloop)); + mpoly->loopstart = (int)(mloop - loops.data()); mpoly->totloop = 4; - mpoly->mat_nr = dl->col; + material_indices.span[mpoly - polys.data()] = dl->col; if (mloopuv) { int orco_sizeu = dl->nr - 1; @@ -458,15 +386,12 @@ static int mesh_nurbs_displist_to_mdata(const Curve *cu, } if (totpoly) { - make_edges_mdata_extend(r_alledge, &totedge, *r_allpoly, *r_allloop, totpoly); + make_edges_mdata_extend(*mesh); } - *r_totpoly = totpoly; - *r_totloop = totloop; - *r_totedge = totedge; - *r_totvert = totvert; + material_indices.finish(); - return 0; + return mesh; } /** @@ -487,60 +412,12 @@ static void mesh_copy_texture_space_from_curve_type(const Curve *cu, Mesh *me) Mesh *BKE_mesh_new_nomain_from_curve_displist(const Object *ob, const ListBase *dispbase) { const Curve *cu = (const Curve *)ob->data; - Mesh *mesh; - MVert *allvert; - MEdge *alledge; - MLoop *allloop; - MPoly *allpoly; - MLoopUV *alluv = nullptr; - int totvert, totedge, totloop, totpoly; - - if (mesh_nurbs_displist_to_mdata(cu, - dispbase, - &allvert, - &totvert, - &alledge, - &totedge, - &allloop, - &allpoly, - &alluv, - &totloop, - &totpoly) != 0) { - /* Error initializing mdata. This often happens when curve is empty */ - return BKE_mesh_new_nomain(0, 0, 0, 0, 0); - } - - mesh = BKE_mesh_new_nomain(totvert, totedge, 0, totloop, totpoly); - - if (totvert != 0) { - memcpy(mesh->mvert, allvert, totvert * sizeof(MVert)); - } - if (totedge != 0) { - memcpy(mesh->medge, alledge, totedge * sizeof(MEdge)); - } - if (totloop != 0) { - memcpy(mesh->mloop, allloop, totloop * sizeof(MLoop)); - } - if (totpoly != 0) { - memcpy(mesh->mpoly, allpoly, totpoly * sizeof(MPoly)); - } - - if (alluv) { - const char *uvname = "UVMap"; - CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, totloop, uvname); - } + Mesh *mesh = mesh_nurbs_displist_to_mesh(cu, dispbase); mesh_copy_texture_space_from_curve_type(cu, mesh); - - /* Copy curve materials. */ mesh->mat = (Material **)MEM_dupallocN(cu->mat); mesh->totcol = cu->totcol; - MEM_freeN(allvert); - MEM_freeN(alledge); - MEM_freeN(allloop); - MEM_freeN(allpoly); - return mesh; } @@ -805,7 +682,8 @@ void BKE_mesh_from_pointcloud(const PointCloud *pointcloud, Mesh *me) &pointcloud->pdata, &me->vdata, CD_MASK_PROP_ALL, CD_DUPLICATE, pointcloud->totpoint); /* Convert the Position attribute to a mesh vertex. */ - me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, nullptr, me->totvert); + me->mvert = (MVert *)CustomData_add_layer( + &me->vdata, CD_MVERT, CD_SET_DEFAULT, nullptr, me->totvert); CustomData_update_typemap(&me->vdata); const int layer_idx = CustomData_get_named_layer_index( @@ -1003,32 +881,21 @@ static Mesh *mesh_new_from_curve_type_object(const Object *object) static Mesh *mesh_new_from_mball_object(Object *object) { - MetaBall *mball = (MetaBall *)object->data; - /* NOTE: We can only create mesh for a polygonized meta ball. This figures out all original meta * balls and all evaluated child meta balls (since polygonization is only stored in the mother * ball). * * Create empty mesh so script-authors don't run into None objects. */ - if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == nullptr || - BLI_listbase_is_empty(&object->runtime.curve_cache->disp)) { + if (!DEG_is_evaluated_object(object)) { return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); } - Mesh *mesh_result = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); - BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result); - BKE_mesh_texspace_copy_from_object(mesh_result, object); - - /* Copy materials. */ - mesh_result->totcol = mball->totcol; - mesh_result->mat = (Material **)MEM_dupallocN(mball->mat); - if (mball->mat != nullptr) { - for (int i = mball->totcol; i-- > 0;) { - mesh_result->mat[i] = BKE_object_material_get(object, i + 1); - } + const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object); + if (mesh_eval == nullptr) { + return (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); } - return mesh_result; + return BKE_mesh_copy_for_eval(mesh_eval, false); } static Mesh *mesh_new_from_mesh(Object *object, Mesh *mesh) diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc index 6f12726d364..1826a77d6f4 100644 --- a/source/blender/blenkernel/intern/mesh_debug.cc +++ b/source/blender/blenkernel/intern/mesh_debug.cc @@ -58,7 +58,8 @@ char *BKE_mesh_debug_info(const Mesh *me) BLI_dynstr_appendf(dynstr, " 'totpoly': %d,\n", me->totpoly); BLI_dynstr_appendf(dynstr, " 'runtime.deformed_only': %d,\n", me->runtime.deformed_only); - BLI_dynstr_appendf(dynstr, " 'runtime.is_original': %d,\n", me->runtime.is_original); + BLI_dynstr_appendf( + dynstr, " 'runtime.is_original_bmesh': %d,\n", me->runtime.is_original_bmesh); BLI_dynstr_append(dynstr, " 'vert_layers': (\n"); CustomData_debug_info_from_layers(&me->vdata, indent8, dynstr); diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc index 7d26262a504..9dba8eab340 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.cc +++ b/source/blender/blenkernel/intern/mesh_evaluate.cc @@ -22,15 +22,17 @@ #include "BLI_math.h" #include "BLI_span.hh" #include "BLI_utildefines.h" +#include "BLI_virtual_array.hh" #include "BKE_customdata.h" +#include "BKE_attribute.hh" #include "BKE_mesh.h" #include "BKE_multires.h" -using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; /* -------------------------------------------------------------------- */ /** \name Polygon Calculations @@ -732,75 +734,90 @@ void BKE_mesh_polygons_flip(MPoly *mpoly, MLoop *mloop, CustomData *ldata, int t /** \name Mesh Flag Flushing * \{ */ -void BKE_mesh_flush_hidden_from_verts_ex(const MVert *mvert, - const MLoop *mloop, - MEdge *medge, - const int totedge, - MPoly *mpoly, - const int totpoly) +void BKE_mesh_flush_hidden_from_verts(Mesh *me) { - int i, j; + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); - for (i = 0; i < totedge; i++) { - MEdge *e = &medge[i]; - if (mvert[e->v1].flag & ME_HIDE || mvert[e->v2].flag & ME_HIDE) { - e->flag |= ME_HIDE; - } - else { - e->flag &= ~ME_HIDE; - } + const VArray<bool> hide_vert = attributes.lookup_or_default<bool>( + ".hide_vert", ATTR_DOMAIN_POINT, false); + if (hide_vert.is_single() && !hide_vert.get_internal_single()) { + attributes.remove(".hide_edge"); + attributes.remove(".hide_poly"); + return; } - for (i = 0; i < totpoly; i++) { - MPoly *p = &mpoly[i]; - p->flag &= (char)~ME_HIDE; - for (j = 0; j < p->totloop; j++) { - if (mvert[mloop[p->loopstart + j].v].flag & ME_HIDE) { - p->flag |= ME_HIDE; - } - } + const VArraySpan<bool> hide_vert_span{hide_vert}; + const Span<MEdge> edges(me->medge, me->totedge); + const Span<MPoly> polys(me->mpoly, me->totpoly); + const Span<MLoop> loops(me->mloop, me->totloop); + + /* Hide edges when either of their vertices are hidden. */ + SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_edge", ATTR_DOMAIN_EDGE); + for (const int i : edges.index_range()) { + const MEdge &edge = edges[i]; + hide_edge.span[i] = hide_vert_span[edge.v1] || hide_vert_span[edge.v2]; } -} -void BKE_mesh_flush_hidden_from_verts(Mesh *me) -{ - BKE_mesh_flush_hidden_from_verts_ex( - me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly); + hide_edge.finish(); + + /* Hide polygons when any of their vertices are hidden. */ + SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_poly", ATTR_DOMAIN_FACE); + for (const int i : polys.index_range()) { + const MPoly &poly = polys[i]; + const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop); + hide_poly.span[i] = std::any_of(poly_loops.begin(), poly_loops.end(), [&](const MLoop &loop) { + return hide_vert_span[loop.v]; + }); + } + hide_poly.finish(); } -void BKE_mesh_flush_hidden_from_polys_ex(MVert *mvert, - const MLoop *mloop, - MEdge *medge, - const int UNUSED(totedge), - const MPoly *mpoly, - const int totpoly) +void BKE_mesh_flush_hidden_from_polys(Mesh *me) { - int i = totpoly; - for (const MPoly *mp = mpoly; i--; mp++) { - if (mp->flag & ME_HIDE) { - const MLoop *ml; - int j = mp->totloop; - for (ml = &mloop[mp->loopstart]; j--; ml++) { - mvert[ml->v].flag |= ME_HIDE; - medge[ml->e].flag |= ME_HIDE; + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*me); + + const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( + ".hide_poly", ATTR_DOMAIN_FACE, false); + if (hide_poly.is_single() && !hide_poly.get_internal_single()) { + attributes.remove(".hide_vert"); + attributes.remove(".hide_edge"); + return; + } + const VArraySpan<bool> hide_poly_span{hide_poly}; + const Span<MPoly> polys(me->mpoly, me->totpoly); + const Span<MLoop> loops(me->mloop, me->totloop); + SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_vert", ATTR_DOMAIN_POINT); + SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_edge", ATTR_DOMAIN_EDGE); + + /* Hide all edges or vertices connected to hidden polygons. */ + for (const int i : polys.index_range()) { + if (hide_poly_span[i]) { + const MPoly &poly = polys[i]; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + hide_vert.span[loop.v] = true; + hide_edge.span[loop.e] = true; } } } - - i = totpoly; - for (const MPoly *mp = mpoly; i--; mp++) { - if ((mp->flag & ME_HIDE) == 0) { - const MLoop *ml; - int j = mp->totloop; - for (ml = &mloop[mp->loopstart]; j--; ml++) { - mvert[ml->v].flag &= (char)~ME_HIDE; - medge[ml->e].flag &= (short)~ME_HIDE; + /* Unhide vertices and edges connected to visible polygons. */ + for (const int i : polys.index_range()) { + if (!hide_poly_span[i]) { + const MPoly &poly = polys[i]; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + hide_vert.span[loop.v] = false; + hide_edge.span[loop.e] = false; } } } -} -void BKE_mesh_flush_hidden_from_polys(Mesh *me) -{ - BKE_mesh_flush_hidden_from_polys_ex( - me->mvert, me->mloop, me->medge, me->totedge, me->mpoly, me->totpoly); + + hide_vert.finish(); + hide_edge.finish(); } void BKE_mesh_flush_select_from_polys_ex(MVert *mvert, @@ -848,11 +865,13 @@ void BKE_mesh_flush_select_from_polys(Mesh *me) static void mesh_flush_select_from_verts(const Span<MVert> verts, const Span<MLoop> loops, + const VArray<bool> &hide_edge, + const VArray<bool> &hide_poly, MutableSpan<MEdge> edges, MutableSpan<MPoly> polys) { for (const int i : edges.index_range()) { - if ((edges[i].flag & ME_HIDE) == 0) { + if (!hide_edge[i]) { MEdge &edge = edges[i]; if ((verts[edge.v1].flag & SELECT) && (verts[edge.v2].flag & SELECT)) { edge.flag |= SELECT; @@ -864,7 +883,7 @@ static void mesh_flush_select_from_verts(const Span<MVert> verts, } for (const int i : polys.index_range()) { - if (polys[i].flag & ME_HIDE) { + if (hide_poly[i]) { continue; } MPoly &poly = polys[i]; @@ -885,10 +904,14 @@ static void mesh_flush_select_from_verts(const Span<MVert> verts, void BKE_mesh_flush_select_from_verts(Mesh *me) { - mesh_flush_select_from_verts({me->mvert, me->totvert}, - {me->mloop, me->totloop}, - {me->medge, me->totedge}, - {me->mpoly, me->totpoly}); + const blender::bke::AttributeAccessor attributes = blender::bke::mesh_attributes(*me); + mesh_flush_select_from_verts( + {me->mvert, me->totvert}, + {me->mloop, me->totloop}, + attributes.lookup_or_default<bool>(".hide_edge", ATTR_DOMAIN_EDGE, false), + attributes.lookup_or_default<bool>(".hide_poly", ATTR_DOMAIN_FACE, false), + {me->medge, me->totedge}, + {me->mpoly, me->totpoly}); } /** \} */ diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 479dd6a012a..2fc984997b8 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -7,7 +7,7 @@ * Functions to convert mesh data to and from legacy formats like #MFace. */ -// #include <climits> +#define DNA_DEPRECATED_ALLOW #include "MEM_guardedalloc.h" @@ -18,8 +18,10 @@ #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_polyfill_2d.h" +#include "BLI_task.hh" #include "BLI_utildefines.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_mesh.h" #include "BKE_mesh_legacy_convert.h" @@ -135,19 +137,19 @@ static void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int to for (int i = 0; i < fdata->totlayer; i++) { if (fdata->layers[i].type == CD_MTFACE) { CustomData_add_layer_named( - ldata, CD_MLOOPUV, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_MLOOPUV, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MCOL) { CustomData_add_layer_named( - ldata, CD_PROP_BYTE_COLOR, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MDISPS) { CustomData_add_layer_named( - ldata, CD_MDISPS, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) { CustomData_add_layer_named( - ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); + ldata, CD_NORMAL, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); } } } @@ -847,26 +849,27 @@ void BKE_mesh_add_mface_layers(CustomData *fdata, CustomData *ldata, int total) for (int i = 0; i < ldata->totlayer; i++) { if (ldata->layers[i].type == CD_MLOOPUV) { CustomData_add_layer_named( - fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_MTFACE, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } if (ldata->layers[i].type == CD_PROP_BYTE_COLOR) { - CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + CustomData_add_layer_named( + fdata, CD_MCOL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) { CustomData_add_layer_named( - fdata, CD_PREVIEW_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_PREVIEW_MCOL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) { CustomData_add_layer_named( - fdata, CD_ORIGSPACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_ORIGSPACE, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_NORMAL) { CustomData_add_layer_named( - fdata, CD_TESSLOOPNORMAL, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_TESSLOOPNORMAL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_TANGENT) { CustomData_add_layer_named( - fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name); + fdata, CD_TANGENT, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); } } @@ -874,3 +877,128 @@ void BKE_mesh_add_mface_layers(CustomData *fdata, CustomData *ldata, int total) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide Attribute and Legacy Flag Conversion + * \{ */ + +void BKE_mesh_legacy_convert_hide_layers_to_flags(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + const AttributeAccessor attributes = mesh_attributes(*mesh); + + MutableSpan<MVert> verts(mesh->mvert, mesh->totvert); + const VArray<bool> hide_vert = attributes.lookup_or_default<bool>( + ".hide_vert", ATTR_DOMAIN_POINT, false); + threading::parallel_for(verts.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + SET_FLAG_FROM_TEST(verts[i].flag, hide_vert[i], ME_HIDE); + } + }); + + MutableSpan<MEdge> edges(mesh->medge, mesh->totedge); + const VArray<bool> hide_edge = attributes.lookup_or_default<bool>( + ".hide_edge", ATTR_DOMAIN_EDGE, false); + threading::parallel_for(edges.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + SET_FLAG_FROM_TEST(edges[i].flag, hide_edge[i], ME_HIDE); + } + }); + + MutableSpan<MPoly> polys(mesh->mpoly, mesh->totpoly); + const VArray<bool> hide_poly = attributes.lookup_or_default<bool>( + ".hide_poly", ATTR_DOMAIN_FACE, false); + threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + SET_FLAG_FROM_TEST(polys[i].flag, hide_poly[i], ME_HIDE); + } + }); +} + +void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*mesh); + + const Span<MVert> verts(mesh->mvert, mesh->totvert); + if (std::any_of( + verts.begin(), verts.end(), [](const MVert &vert) { return vert.flag & ME_HIDE; })) { + SpanAttributeWriter<bool> hide_vert = attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_vert", ATTR_DOMAIN_POINT); + threading::parallel_for(verts.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + hide_vert.span[i] = verts[i].flag & ME_HIDE; + } + }); + hide_vert.finish(); + } + + const Span<MEdge> edges(mesh->medge, mesh->totedge); + if (std::any_of( + edges.begin(), edges.end(), [](const MEdge &edge) { return edge.flag & ME_HIDE; })) { + SpanAttributeWriter<bool> hide_edge = attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_edge", ATTR_DOMAIN_EDGE); + threading::parallel_for(edges.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + hide_edge.span[i] = edges[i].flag & ME_HIDE; + } + }); + hide_edge.finish(); + } + + const Span<MPoly> polys(mesh->mpoly, mesh->totpoly); + if (std::any_of( + polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_HIDE; })) { + SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_poly", ATTR_DOMAIN_FACE); + threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + hide_poly.span[i] = polys[i].flag & ME_HIDE; + } + }); + hide_poly.finish(); + } +} + +/** \} */ +/* -------------------------------------------------------------------- */ +/** \name Material Index Conversion + * \{ */ + +void BKE_mesh_legacy_convert_material_indices_to_mpoly(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + const AttributeAccessor attributes = mesh_attributes(*mesh); + MutableSpan<MPoly> polys(mesh->mpoly, mesh->totpoly); + const VArray<int> material_indices = attributes.lookup_or_default<int>( + "material_index", ATTR_DOMAIN_FACE, 0); + threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + polys[i].mat_nr = material_indices[i]; + } + }); +} + +void BKE_mesh_legacy_convert_mpoly_to_material_indices(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = mesh_attributes_for_write(*mesh); + const Span<MPoly> polys(mesh->mpoly, mesh->totpoly); + if (std::any_of( + polys.begin(), polys.end(), [](const MPoly &poly) { return poly.mat_nr != 0; })) { + SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_only_span<int>( + "material_index", ATTR_DOMAIN_FACE); + threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { + for (const int i : range) { + material_indices.span[i] = polys[i].mat_nr; + } + }); + material_indices.finish(); + } +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c index 9c4098e2db6..798fe087ea8 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.c +++ b/source/blender/blenkernel/intern/mesh_mapping.c @@ -29,6 +29,7 @@ /* ngon version wip, based on BM_uv_vert_map_create */ UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly, + const bool *hide_poly, const MLoop *mloop, const MLoopUV *mloopuv, uint totpoly, @@ -51,7 +52,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly, /* generate UvMapVert array */ mp = mpoly; for (a = 0; a < totpoly; a++, mp++) { - if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) { + if (!selected || (!(hide_poly && hide_poly[a]) && (mp->flag & ME_FACE_SEL))) { totuv += mp->totloop; } } @@ -74,7 +75,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly, mp = mpoly; for (a = 0; a < totpoly; a++, mp++) { - if (!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) { + if (!selected || (!(hide_poly && hide_poly[a]) && (mp->flag & ME_FACE_SEL))) { float(*tf_uv)[2] = NULL; if (use_winding) { diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 2366b7526a1..f90a2e1b887 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -2054,7 +2054,7 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const } else { clnors = (short(*)[2])CustomData_add_layer( - &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_CALLOC, nullptr, numloops); + &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, numloops); } mesh_normals_loop_custom_set(mesh->mvert, diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c index 3a37c29c1d0..4c6ee0ae3ee 100644 --- a/source/blender/blenkernel/intern/mesh_remap.c +++ b/source/blender/blenkernel/intern/mesh_remap.c @@ -312,15 +312,10 @@ void BKE_mesh_remap_calc_source_cddata_masks_from_map_modes(const int UNUSED(ver { /* vert, edge and poly mapping modes never need extra cddata from source object. */ const bool need_lnors_src = (loop_mode & MREMAP_USE_LOOP) && (loop_mode & MREMAP_USE_NORMAL); - const bool need_pnors_src = need_lnors_src || - ((loop_mode & MREMAP_USE_POLY) && (loop_mode & MREMAP_USE_NORMAL)); if (need_lnors_src) { r_cddata_mask->lmask |= CD_MASK_NORMAL; } - if (need_pnors_src) { - r_cddata_mask->pmask |= CD_MASK_NORMAL; - } } void BKE_mesh_remap_init(MeshPairRemap *map, const int items_num) @@ -1357,7 +1352,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, const bool do_loop_nors_dst = (loop_nors_dst == NULL); if (!loop_nors_dst) { loop_nors_dst = CustomData_add_layer( - ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst); + ldata_dst, CD_NORMAL, CD_SET_DEFAULT, NULL, numloops_dst); CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } if (dirty_nors_dst || do_loop_nors_dst) { diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index 85aed01ce52..5a4fd0d7d96 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -275,11 +275,15 @@ Mesh *BKE_mesh_remesh_voxel(const Mesh *mesh, #endif } -void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, Mesh *source) +void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, const Mesh *source) { BVHTreeFromMesh bvhtree = {nullptr}; BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2); - MVert *target_verts = (MVert *)CustomData_get_layer(&target->vdata, CD_MVERT); + const MVert *target_verts = (const MVert *)CustomData_get_layer(&target->vdata, CD_MVERT); + const float *source_mask = (const float *)CustomData_get_layer(&source->vdata, CD_PAINT_MASK); + if (source_mask == nullptr) { + return; + } float *target_mask; if (CustomData_has_layer(&target->vdata, CD_PAINT_MASK)) { @@ -287,16 +291,7 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, Mesh *source) } else { target_mask = (float *)CustomData_add_layer( - &target->vdata, CD_PAINT_MASK, CD_CALLOC, nullptr, target->totvert); - } - - const float *source_mask; - if (CustomData_has_layer(&source->vdata, CD_PAINT_MASK)) { - source_mask = (float *)CustomData_get_layer(&source->vdata, CD_PAINT_MASK); - } - else { - source_mask = (float *)CustomData_add_layer( - &source->vdata, CD_PAINT_MASK, CD_CALLOC, nullptr, source->totvert); + &target->vdata, CD_PAINT_MASK, CD_CONSTRUCT, nullptr, target->totvert); } for (int i = 0; i < target->totvert; i++) { @@ -313,13 +308,16 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, Mesh *source) free_bvhtree_from_mesh(&bvhtree); } -void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, Mesh *source) +void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) { - BVHTreeFromMesh bvhtree = {nullptr}; - const MPoly *target_polys = (const MPoly *)CustomData_get_layer(&target->pdata, CD_MPOLY); const MVert *target_verts = (const MVert *)CustomData_get_layer(&target->vdata, CD_MVERT); const MLoop *target_loops = (const MLoop *)CustomData_get_layer(&target->ldata, CD_MLOOP); + const int *source_face_sets = (const int *)CustomData_get_layer(&source->pdata, + CD_SCULPT_FACE_SETS); + if (source_face_sets == nullptr) { + return; + } int *target_face_sets; if (CustomData_has_layer(&target->pdata, CD_SCULPT_FACE_SETS)) { @@ -327,19 +325,11 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, Mesh *source) } else { target_face_sets = (int *)CustomData_add_layer( - &target->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, target->totpoly); - } - - const int *source_face_sets; - if (CustomData_has_layer(&source->pdata, CD_SCULPT_FACE_SETS)) { - source_face_sets = (const int *)CustomData_get_layer(&source->pdata, CD_SCULPT_FACE_SETS); - } - else { - source_face_sets = (const int *)CustomData_add_layer( - &source->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, nullptr, source->totpoly); + &target->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, target->totpoly); } const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(source); + BVHTreeFromMesh bvhtree = {nullptr}; BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_LOOPTRI, 2); for (int i = 0; i < target->totpoly; i++) { @@ -386,7 +376,7 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) int elem_num = domain == ATTR_DOMAIN_POINT ? target->totvert : target->totloop; CustomData_add_layer_named( - target_cdata, layer->type, CD_CALLOC, nullptr, elem_num, layer->name); + target_cdata, layer->type, CD_SET_DEFAULT, nullptr, elem_num, layer->name); layer_i = CustomData_get_named_layer_index(target_cdata, layer->type, layer->name); } diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc index dd09a3d6917..e54f2e6d687 100644 --- a/source/blender/blenkernel/intern/mesh_sample.cc +++ b/source/blender/blenkernel/intern/mesh_sample.cc @@ -16,9 +16,9 @@ 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 VArray<T> &src, const IndexMask mask, - const MutableSpan<T> data_out) + const MutableSpan<T> dst) { const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh), BKE_mesh_runtime_looptri_len(&mesh)}; @@ -32,30 +32,30 @@ BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh, 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 v0 = src[v0_index]; + const T v1 = src[v1_index]; + const T v2 = src[v2_index]; const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2); - data_out[i] = interpolated_value; + dst[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 GVArray &src, const IndexMask mask, - const GMutableSpan data_out) + const GMutableSpan dst) { - BLI_assert(data_in.size() == mesh.totvert); - BLI_assert(data_in.type() == data_out.type()); + BLI_assert(src.size() == mesh.totvert); + BLI_assert(src.type() == dst.type()); - const CPPType &type = data_in.type(); + const CPPType &type = src.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>(), mask, data_out.typed<T>()); + mesh, looptri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>()); }); } @@ -63,9 +63,9 @@ 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 VArray<T> &src, const IndexMask mask, - const MutableSpan<T> data_out) + const MutableSpan<T> dst) { const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh), BKE_mesh_runtime_looptri_len(&mesh)}; @@ -79,39 +79,39 @@ BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh, 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 v0 = src[loop_index_0]; + const T v1 = src[loop_index_1]; + const T v2 = src[loop_index_2]; const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2); - data_out[i] = interpolated_value; + dst[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 GVArray &src, const IndexMask mask, - const GMutableSpan data_out) + const GMutableSpan dst) { - BLI_assert(data_in.size() == mesh.totloop); - BLI_assert(data_in.type() == data_out.type()); + BLI_assert(src.size() == mesh.totloop); + BLI_assert(src.type() == dst.type()); - const CPPType &type = data_in.type(); + const CPPType &type = src.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>(), mask, data_out.typed<T>()); + mesh, looptri_indices, bary_coords, src.typed<T>(), mask, dst.typed<T>()); }); } template<typename T> void sample_face_attribute(const Mesh &mesh, const Span<int> looptri_indices, - const VArray<T> &data_in, + const VArray<T> &src, const IndexMask mask, - const MutableSpan<T> data_out) + const MutableSpan<T> dst) { const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh), BKE_mesh_runtime_looptri_len(&mesh)}; @@ -120,23 +120,23 @@ void sample_face_attribute(const Mesh &mesh, 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]; + dst[i] = src[poly_index]; } } void sample_face_attribute(const Mesh &mesh, const Span<int> looptri_indices, - const GVArray &data_in, + const GVArray &src, const IndexMask mask, - const GMutableSpan data_out) + const GMutableSpan dst) { - BLI_assert(data_in.size() == mesh.totpoly); - BLI_assert(data_in.type() == data_out.type()); + BLI_assert(src.size() == mesh.totpoly); + BLI_assert(src.type() == dst.type()); - const CPPType &type = data_in.type(); + const CPPType &type = src.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>(), mask, data_out.typed<T>()); + sample_face_attribute<T>(mesh, looptri_indices, src.typed<T>(), mask, dst.typed<T>()); }); } @@ -219,45 +219,31 @@ void MeshAttributeInterpolator::sample_data(const GVArray &src, if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { switch (mode) { case eAttributeMapMode::INTERPOLATED: - weights = ensure_barycentric_coords(); + weights = this->ensure_barycentric_coords(); break; case eAttributeMapMode::NEAREST: - weights = ensure_nearest_weights(); + weights = this->ensure_nearest_weights(); break; } } /* Interpolate the source attributes on the surface. */ switch (domain) { - case ATTR_DOMAIN_POINT: { + case ATTR_DOMAIN_POINT: sample_point_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst); break; - } - case ATTR_DOMAIN_FACE: { + case ATTR_DOMAIN_FACE: sample_face_attribute(*mesh_, looptri_indices_, src, mask_, dst); break; - } - case ATTR_DOMAIN_CORNER: { + case ATTR_DOMAIN_CORNER: sample_corner_attribute(*mesh_, looptri_indices_, weights, src, mask_, dst); break; - } - case ATTR_DOMAIN_EDGE: { + case ATTR_DOMAIN_EDGE: /* Not yet supported. */ break; - } - default: { + default: BLI_assert_unreachable(); break; - } - } -} - -void MeshAttributeInterpolator::sample_attribute(const GAttributeReader &src_attribute, - GSpanAttributeWriter &dst_attribute, - eAttributeMapMode mode) -{ - if (src_attribute && dst_attribute) { - this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.span); } } diff --git a/source/blender/blenkernel/intern/mesh_tangent.c b/source/blender/blenkernel/intern/mesh_tangent.c index a677a0d6ebb..497f9ff3cbd 100644 --- a/source/blender/blenkernel/intern/mesh_tangent.c +++ b/source/blender/blenkernel/intern/mesh_tangent.c @@ -452,7 +452,8 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data, { if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && CustomData_get_named_layer_index(uv_data, CD_MLOOPUV, layer_name) != -1) { - CustomData_add_layer_named(tan_data, CD_TANGENT, CD_CALLOC, NULL, numLoopData, layer_name); + CustomData_add_layer_named( + tan_data, CD_TANGENT, CD_SET_DEFAULT, NULL, numLoopData, layer_name); } } @@ -581,7 +582,7 @@ void BKE_mesh_calc_loop_tangent_ex(const MVert *mvert, if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1) { CustomData_add_layer_named( - loopdata_out, CD_TANGENT, CD_CALLOC, NULL, (int)loopdata_out_len, ""); + loopdata_out, CD_TANGENT, CD_SET_DEFAULT, NULL, (int)loopdata_out_len, ""); } if (calc_act && act_uv_name[0]) { BKE_mesh_add_loop_tangent_named_layer_for_uv( @@ -716,7 +717,7 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval, { BKE_mesh_runtime_looptri_ensure(me_eval); - /* TODO(campbell): store in Mesh.runtime to avoid recalculation. */ + /* TODO(@campbellbarton): store in Mesh.runtime to avoid recalculation. */ short tangent_mask = 0; BKE_mesh_calc_loop_tangent_ex(me_eval->mvert, me_eval->mpoly, diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc index d17885e1214..bc56120ca57 100644 --- a/source/blender/blenkernel/intern/mesh_validate.cc +++ b/source/blender/blenkernel/intern/mesh_validate.cc @@ -24,6 +24,7 @@ #include "BLI_math_vector.h" #include "BLI_utildefines.h" +#include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_mesh.h" @@ -238,6 +239,10 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, } \ (void)0 + blender::bke::AttributeWriter<int> material_indices = + blender::bke::mesh_attributes_for_write(*mesh).lookup_for_write<int>("material_index"); + blender::MutableVArraySpan<int> material_indices_span(material_indices.varray); + MVert *mv = mverts; MEdge *me; MLoop *ml; @@ -559,10 +564,10 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, /* Material index, isolated from other tests here. While large indices are clamped, * negative indices aren't supported by drawing, exporters etc. * To check the indices are in range, use #BKE_mesh_validate_material_indices */ - if (mp->mat_nr < 0) { - PRINT_ERR("\tPoly %u has invalid material (%d)", sp->index, mp->mat_nr); + if (material_indices && material_indices_span[i] < 0) { + PRINT_ERR("\tPoly %u has invalid material (%d)", sp->index, material_indices_span[i]); if (do_fixes) { - mp->mat_nr = 0; + material_indices_span[i] = 0; } } @@ -916,6 +921,9 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, } } + material_indices_span.save(); + material_indices.finish(); + PRINT_MSG("%s: finished\n\n", __func__); *r_changed = (fix_flag.as_flag || free_flag.as_flag || recalc_flag.as_flag); @@ -1001,10 +1009,6 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData_MeshMasks mask = {0}; if (check_meshmask) { mask = CD_MASK_MESH; - /* Normal data isn't in the mask since it is derived data, - * but it is valid and should not be removed. */ - mask.vmask |= CD_MASK_NORMAL; - mask.pmask |= CD_MASK_NORMAL; } is_valid &= mesh_validate_customdata( @@ -1133,19 +1137,20 @@ bool BKE_mesh_is_valid(Mesh *me) bool BKE_mesh_validate_material_indices(Mesh *me) { - /* Cast to unsigned to catch negative indices too. */ - const uint16_t mat_nr_max = max_ii(0, me->totcol - 1); - MPoly *mp; - const int totpoly = me->totpoly; - int i; + const int mat_nr_max = max_ii(0, me->totcol - 1); bool is_valid = true; - for (mp = me->mpoly, i = 0; i < totpoly; i++, mp++) { - if ((uint16_t)mp->mat_nr > mat_nr_max) { - mp->mat_nr = 0; + blender::bke::AttributeWriter<int> material_indices = + blender::bke::mesh_attributes_for_write(*me).lookup_for_write<int>("material_index"); + blender::MutableVArraySpan<int> material_indices_span(material_indices.varray); + for (const int i : material_indices_span.index_range()) { + if (material_indices_span[i] < 0 || material_indices_span[i] > mat_nr_max) { + material_indices_span[i] = 0; is_valid = false; } } + material_indices_span.save(); + material_indices.finish(); if (!is_valid) { DEG_id_tag_update(&me->id, ID_RECALC_GEOMETRY_ALL_MODES); @@ -1545,8 +1550,8 @@ void BKE_mesh_calc_edges_tessface(Mesh *mesh) /* write new edges into a temporary CustomData */ CustomData edgeData; CustomData_reset(&edgeData); - CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, nullptr, numEdges); - CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, nullptr, numEdges); + CustomData_add_layer(&edgeData, CD_MEDGE, CD_SET_DEFAULT, nullptr, numEdges); + CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, numEdges); MEdge *med = (MEdge *)CustomData_get_layer(&edgeData, CD_MEDGE); int *index = (int *)CustomData_get_layer(&edgeData, CD_ORIGINDEX); diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc index 0b61b876abe..19d4444aa2f 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.cc +++ b/source/blender/blenkernel/intern/mesh_wrapper.cc @@ -61,7 +61,7 @@ Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em, } /* Use edit-mesh directly where possible. */ - me->runtime.is_original = true; + me->runtime.is_original_bmesh = true; me->edit_mesh = static_cast<BMEditMesh *>(MEM_dupallocN(em)); me->edit_mesh->is_shallow_copy = true; @@ -133,7 +133,7 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me) EditMeshData *edit_data = me->runtime.edit_data; if (edit_data->vertexCos) { BKE_mesh_vert_coords_apply(me, edit_data->vertexCos); - me->runtime.is_original = false; + me->runtime.is_original_bmesh = false; } break; } @@ -343,7 +343,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *me) if (use_clnors) { float(*lnors)[3] = static_cast<float(*)[3]>( CustomData_get_layer(&subdiv_mesh->ldata, CD_NORMAL)); - BLI_assert(lnors != NULL); + BLI_assert(lnors != nullptr); BKE_mesh_set_custom_normals(subdiv_mesh, lnors); CustomData_set_layer_flag(&me->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); CustomData_set_layer_flag(&subdiv_mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 01eb4970f7e..60d6b51594a 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -142,7 +142,8 @@ static ModifierData *modifier_allocate_and_init(int type) md->type = type; md->mode = eModifierMode_Realtime | eModifierMode_Render; md->flag = eModifierFlag_OverrideLibrary_Local; - md->ui_expand_flag = 1; /* Only open the main panel at the beginning, not the sub-panels. */ + /* Only open the main panel at the beginning, not the sub-panels. */ + md->ui_expand_flag = UI_PANEL_DATA_EXPAND_ROOT; if (mti->flags & eModifierTypeFlag_EnableInEditmode) { md->mode |= eModifierMode_Editmode; diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 63945f9ed42..5c382a4e864 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -960,7 +960,7 @@ static void multiresModifier_disp_run( if (!mdisps) { if (op == CALC_DISPLACEMENTS) { - mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop); + mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, me->totloop); } else { return; @@ -1487,7 +1487,7 @@ void multires_ensure_external_read(struct Mesh *mesh, int top_level) MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); if (mdisps == NULL) { - mdisps = CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_DEFAULT, NULL, mesh->totloop); + mdisps = CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, mesh->totloop); } const int totloop = mesh->totloop; diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index b50a0787fe3..17e4860ab1b 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -181,7 +181,8 @@ void multiresModifier_subdivide_to_level(struct Object *object, * are allocated at a proper level and return. */ const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); if (!has_mdisps) { - CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); + CustomData_add_layer( + &coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, coarse_mesh->totloop); } /* NOTE: Subdivision happens from the top level of the existing multires modifier. If it is set diff --git a/source/blender/blenkernel/intern/multires_reshape_subdivide.c b/source/blender/blenkernel/intern/multires_reshape_subdivide.c index 9fa3e93a1e6..cecb57f4de4 100644 --- a/source/blender/blenkernel/intern/multires_reshape_subdivide.c +++ b/source/blender/blenkernel/intern/multires_reshape_subdivide.c @@ -68,7 +68,8 @@ void multires_subdivide_create_tangent_displacement_linear_grids(Object *object, const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); if (!has_mdisps) { - CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, coarse_mesh->totloop); + CustomData_add_layer( + &coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, coarse_mesh->totloop); } if (new_top_level == 1) { diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.c b/source/blender/blenkernel/intern/multires_unsubdivide.c index cad680ecedd..27a1f84579e 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.c +++ b/source/blender/blenkernel/intern/multires_unsubdivide.c @@ -901,10 +901,10 @@ static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh) multires_unsubdivide_free_original_datalayers(mesh); int *l_index = CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totloop, lname); + &mesh->ldata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totloop, lname); int *v_index = CustomData_add_layer_named( - &mesh->vdata, CD_PROP_INT32, CD_CALLOC, NULL, mesh->totvert, vname); + &mesh->vdata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totvert, vname); /* Initialize these data-layer with the indices in the current mesh. */ for (int i = 0; i < mesh->totloop; i++) { @@ -1174,7 +1174,7 @@ static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideC CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop); } MDisps *mdisps = CustomData_add_layer( - &base_mesh->ldata, CD_MDISPS, CD_CALLOC, NULL, base_mesh->totloop); + &base_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, NULL, base_mesh->totloop); const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2); const int totloop = base_mesh->totloop; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index d50b8662f82..4eb48e9edc9 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -72,7 +72,6 @@ #include "NOD_function.h" #include "NOD_geometry.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_shader.h" #include "NOD_socket.h" #include "NOD_texture.h" @@ -104,7 +103,6 @@ using blender::nodes::NodeDeclaration; using blender::nodes::OutputFieldDependency; using blender::nodes::OutputSocketFieldType; using blender::nodes::SocketDeclaration; -using namespace blender::nodes::node_tree_ref_types; /* Fallback types for undefined tree, nodes, sockets */ static bNodeTreeType NodeTreeTypeUndefined; @@ -3383,8 +3381,10 @@ struct bNodeSocket *ntreeAddSocketInterfaceFromSocket(bNodeTree *ntree, bNode *from_node, bNodeSocket *from_sock) { - bNodeSocket *iosock = ntreeAddSocketInterface( - ntree, static_cast<eNodeSocketInOut>(from_sock->in_out), from_sock->idname, from_sock->name); + bNodeSocket *iosock = ntreeAddSocketInterface(ntree, + static_cast<eNodeSocketInOut>(from_sock->in_out), + from_sock->idname, + DATA_(from_sock->name)); if (iosock) { if (iosock->typeinfo->interface_from_socket) { iosock->typeinfo->interface_from_socket(ntree, iosock, from_node, from_sock); @@ -4581,6 +4581,7 @@ static void registerShaderNodes() register_node_type_sh_wavelength(); register_node_type_sh_blackbody(); register_node_type_sh_mix_rgb(); + register_node_type_sh_mix(); register_node_type_sh_valtorgb(); register_node_type_sh_rgbtobw(); register_node_type_sh_shadertorgb(); diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc new file mode 100644 index 00000000000..0c78c0f09d1 --- /dev/null +++ b/source/blender/blenkernel/intern/node_runtime.cc @@ -0,0 +1,405 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BKE_node.h" +#include "BKE_node_runtime.hh" + +#include "DNA_node_types.h" + +#include "BLI_function_ref.hh" +#include "BLI_stack.hh" +#include "BLI_task.hh" +#include "BLI_timeit.hh" + +namespace blender::bke::node_tree_runtime { + +static void double_checked_lock(std::mutex &mutex, bool &data_is_dirty, FunctionRef<void()> fn) +{ + if (!data_is_dirty) { + return; + } + std::lock_guard lock{mutex}; + if (!data_is_dirty) { + return; + } + fn(); + data_is_dirty = false; +} + +static void double_checked_lock_with_task_isolation(std::mutex &mutex, + bool &data_is_dirty, + FunctionRef<void()> fn) +{ + double_checked_lock(mutex, data_is_dirty, [&]() { threading::isolate_task(fn); }); +} + +static void update_node_vector(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.nodes.clear(); + tree_runtime.has_undefined_nodes_or_sockets = false; + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + node->runtime->index_in_tree = tree_runtime.nodes.append_and_get_index(node); + node->runtime->owner_tree = const_cast<bNodeTree *>(&ntree); + tree_runtime.has_undefined_nodes_or_sockets |= node->typeinfo == &NodeTypeUndefined; + } +} + +static void update_link_vector(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.links.clear(); + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + tree_runtime.links.append(link); + } +} + +static void update_internal_links(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + for (bNode *node : tree_runtime.nodes) { + node->runtime->internal_links.clear(); + for (bNodeSocket *socket : node->runtime->outputs) { + socket->runtime->internal_link_input = nullptr; + } + LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) { + node->runtime->internal_links.append(link); + link->tosock->runtime->internal_link_input = link->fromsock; + } + } +} + +static void update_socket_vectors_and_owner_node(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.sockets.clear(); + tree_runtime.input_sockets.clear(); + tree_runtime.output_sockets.clear(); + for (bNode *node : tree_runtime.nodes) { + bNodeRuntime &node_runtime = *node->runtime; + node_runtime.inputs.clear(); + node_runtime.outputs.clear(); + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + socket->runtime->index_in_node = node_runtime.inputs.append_and_get_index(socket); + socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket); + socket->runtime->index_in_inout_sockets = tree_runtime.input_sockets.append_and_get_index( + socket); + socket->runtime->owner_node = node; + tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined; + } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + socket->runtime->index_in_node = node_runtime.outputs.append_and_get_index(socket); + socket->runtime->index_in_all_sockets = tree_runtime.sockets.append_and_get_index(socket); + socket->runtime->index_in_inout_sockets = tree_runtime.output_sockets.append_and_get_index( + socket); + socket->runtime->owner_node = node; + tree_runtime.has_undefined_nodes_or_sockets |= socket->typeinfo == &NodeSocketTypeUndefined; + } + } +} + +static void update_directly_linked_links_and_sockets(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + for (bNode *node : tree_runtime.nodes) { + for (bNodeSocket *socket : node->runtime->inputs) { + socket->runtime->directly_linked_links.clear(); + socket->runtime->directly_linked_sockets.clear(); + } + for (bNodeSocket *socket : node->runtime->outputs) { + socket->runtime->directly_linked_links.clear(); + socket->runtime->directly_linked_sockets.clear(); + } + node->runtime->has_linked_inputs = false; + node->runtime->has_linked_outputs = false; + } + for (bNodeLink *link : tree_runtime.links) { + link->fromsock->runtime->directly_linked_links.append(link); + link->fromsock->runtime->directly_linked_sockets.append(link->tosock); + link->tosock->runtime->directly_linked_links.append(link); + link->fromnode->runtime->has_linked_outputs = true; + link->tonode->runtime->has_linked_inputs = true; + } + for (bNodeSocket *socket : tree_runtime.input_sockets) { + if (socket->flag & SOCK_MULTI_INPUT) { + std::sort(socket->runtime->directly_linked_links.begin(), + socket->runtime->directly_linked_links.end(), + [&](const bNodeLink *a, const bNodeLink *b) { + return a->multi_input_socket_index > b->multi_input_socket_index; + }); + } + } + for (bNodeSocket *socket : tree_runtime.input_sockets) { + for (bNodeLink *link : socket->runtime->directly_linked_links) { + /* Do this after sorting the input links. */ + socket->runtime->directly_linked_sockets.append(link->fromsock); + } + } +} + +static void find_logical_origins_for_socket_recursive( + bNodeSocket &input_socket, + bool only_follow_first_input_link, + Vector<bNodeSocket *, 16> &sockets_in_current_chain, + Vector<bNodeSocket *> &r_logical_origins, + Vector<bNodeSocket *> &r_skipped_origins) +{ + if (sockets_in_current_chain.contains(&input_socket)) { + /* Protect against reroute recursions. */ + return; + } + sockets_in_current_chain.append(&input_socket); + + Span<bNodeLink *> links_to_check = input_socket.runtime->directly_linked_links; + if (only_follow_first_input_link) { + links_to_check = links_to_check.take_front(1); + } + for (bNodeLink *link : links_to_check) { + if (link->flag & NODE_LINK_MUTED) { + continue; + } + bNodeSocket &origin_socket = *link->fromsock; + bNode &origin_node = *link->fromnode; + if (!origin_socket.is_available()) { + /* Non available sockets are ignored. */ + continue; + } + if (origin_node.type == NODE_REROUTE) { + bNodeSocket &reroute_input = *origin_node.runtime->inputs[0]; + bNodeSocket &reroute_output = *origin_node.runtime->outputs[0]; + r_skipped_origins.append(&reroute_input); + r_skipped_origins.append(&reroute_output); + find_logical_origins_for_socket_recursive( + reroute_input, false, sockets_in_current_chain, r_logical_origins, r_skipped_origins); + continue; + } + if (origin_node.is_muted()) { + if (bNodeSocket *mute_input = origin_socket.runtime->internal_link_input) { + r_skipped_origins.append(&origin_socket); + r_skipped_origins.append(mute_input); + find_logical_origins_for_socket_recursive( + *mute_input, true, sockets_in_current_chain, r_logical_origins, r_skipped_origins); + } + continue; + } + r_logical_origins.append(&origin_socket); + } + + sockets_in_current_chain.pop_last(); +} + +static void update_logical_origins(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) { + for (const int i : range) { + bNode &node = *tree_runtime.nodes[i]; + for (bNodeSocket *socket : node.runtime->inputs) { + Vector<bNodeSocket *, 16> sockets_in_current_chain; + socket->runtime->logically_linked_sockets.clear(); + socket->runtime->logically_linked_skipped_sockets.clear(); + find_logical_origins_for_socket_recursive( + *socket, + false, + sockets_in_current_chain, + socket->runtime->logically_linked_sockets, + socket->runtime->logically_linked_skipped_sockets); + } + } + }); +} + +static void update_nodes_by_type(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + tree_runtime.nodes_by_type.clear(); + for (bNode *node : tree_runtime.nodes) { + tree_runtime.nodes_by_type.add(node->typeinfo, node); + } +} + +static void update_sockets_by_identifier(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + threading::parallel_for(tree_runtime.nodes.index_range(), 128, [&](const IndexRange range) { + for (bNode *node : tree_runtime.nodes.as_span().slice(range)) { + node->runtime->inputs_by_identifier.clear(); + node->runtime->outputs_by_identifier.clear(); + for (bNodeSocket *socket : node->runtime->inputs) { + node->runtime->inputs_by_identifier.add_new(socket->identifier, socket); + } + for (bNodeSocket *socket : node->runtime->outputs) { + node->runtime->outputs_by_identifier.add_new(socket->identifier, socket); + } + } + }); +} + +enum class ToposortDirection { + LeftToRight, + RightToLeft, +}; + +struct ToposortNodeState { + bool is_done = false; + bool is_in_stack = false; +}; + +static void toposort_from_start_node(const ToposortDirection direction, + bNode &start_node, + MutableSpan<ToposortNodeState> node_states, + Vector<bNode *> &r_sorted_nodes, + bool &r_cycle_detected) +{ + struct Item { + bNode *node; + int socket_index = 0; + int link_index = 0; + }; + + Stack<Item, 64> nodes_to_check; + nodes_to_check.push({&start_node}); + while (!nodes_to_check.is_empty()) { + Item &item = nodes_to_check.peek(); + bNode &node = *item.node; + const Span<bNodeSocket *> sockets = (direction == ToposortDirection::LeftToRight) ? + node.runtime->inputs : + node.runtime->outputs; + while (true) { + if (item.socket_index == sockets.size()) { + /* All sockets have already been visited. */ + break; + } + bNodeSocket &socket = *sockets[item.socket_index]; + const Span<bNodeSocket *> linked_sockets = socket.runtime->directly_linked_sockets; + if (item.link_index == linked_sockets.size()) { + /* All links connected to this socket have already been visited. */ + item.socket_index++; + item.link_index = 0; + continue; + } + bNodeSocket &linked_socket = *linked_sockets[item.link_index]; + bNode &linked_node = *linked_socket.runtime->owner_node; + ToposortNodeState &linked_node_state = node_states[linked_node.runtime->index_in_tree]; + if (linked_node_state.is_done) { + /* The linked node has already been visited. */ + item.link_index++; + continue; + } + if (linked_node_state.is_in_stack) { + r_cycle_detected = true; + } + else { + nodes_to_check.push({&linked_node}); + linked_node_state.is_in_stack = true; + } + break; + } + + /* If no other element has been pushed, the current node can be pushed to the sorted list. */ + if (&item == &nodes_to_check.peek()) { + ToposortNodeState &node_state = node_states[node.runtime->index_in_tree]; + node_state.is_done = true; + node_state.is_in_stack = false; + r_sorted_nodes.append(&node); + nodes_to_check.pop(); + } + } +} + +static void update_toposort(const bNodeTree &ntree, + const ToposortDirection direction, + Vector<bNode *> &r_sorted_nodes, + bool &r_cycle_detected) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + r_sorted_nodes.clear(); + r_sorted_nodes.reserve(tree_runtime.nodes.size()); + r_cycle_detected = false; + + Array<ToposortNodeState> node_states(tree_runtime.nodes.size()); + for (bNode *node : tree_runtime.nodes) { + if (node_states[node->runtime->index_in_tree].is_done) { + /* Ignore nodes that are done already. */ + continue; + } + if ((direction == ToposortDirection::LeftToRight) ? node->runtime->has_linked_outputs : + node->runtime->has_linked_inputs) { + /* Ignore non-start nodes. */ + continue; + } + toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected); + } + + if (r_sorted_nodes.size() < tree_runtime.nodes.size()) { + r_cycle_detected = true; + for (bNode *node : tree_runtime.nodes) { + if (node_states[node->runtime->index_in_tree].is_done) { + /* Ignore nodes that are done already. */ + continue; + } + /* Start toposort at this node which is somewhere in the middle of a loop. */ + toposort_from_start_node(direction, *node, node_states, r_sorted_nodes, r_cycle_detected); + } + } + + BLI_assert(tree_runtime.nodes.size() == r_sorted_nodes.size()); +} + +static void update_group_output_node(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + const bNodeType *node_type = nodeTypeFind("NodeGroupOutput"); + const Span<bNode *> group_output_nodes = tree_runtime.nodes_by_type.lookup(node_type); + if (group_output_nodes.is_empty()) { + tree_runtime.group_output_node = nullptr; + } + else if (group_output_nodes.size() == 1) { + tree_runtime.group_output_node = group_output_nodes[0]; + } + else { + for (bNode *group_output : group_output_nodes) { + if (group_output->flag & NODE_DO_OUTPUT) { + tree_runtime.group_output_node = group_output; + break; + } + } + } +} + +static void ensure_topology_cache(const bNodeTree &ntree) +{ + bNodeTreeRuntime &tree_runtime = *ntree.runtime; + double_checked_lock_with_task_isolation( + tree_runtime.topology_cache_mutex, tree_runtime.topology_cache_is_dirty, [&]() { + update_node_vector(ntree); + update_link_vector(ntree); + update_socket_vectors_and_owner_node(ntree); + update_internal_links(ntree); + update_directly_linked_links_and_sockets(ntree); + threading::parallel_invoke([&]() { update_logical_origins(ntree); }, + [&]() { update_nodes_by_type(ntree); }, + [&]() { update_sockets_by_identifier(ntree); }, + [&]() { + update_toposort(ntree, + ToposortDirection::LeftToRight, + tree_runtime.toposort_left_to_right, + tree_runtime.has_link_cycle); + }, + [&]() { + bool dummy; + update_toposort(ntree, + ToposortDirection::RightToLeft, + tree_runtime.toposort_right_to_left, + dummy); + }); + update_group_output_node(ntree); + tree_runtime.topology_cache_exists = true; + }); +} + +} // namespace blender::bke::node_tree_runtime + +void bNodeTree::ensure_topology_cache() const +{ + blender::bke::node_tree_runtime::ensure_topology_cache(*this); +} diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc index 58084226b00..a9097bcb94a 100644 --- a/source/blender/blenkernel/intern/node_tree_update.cc +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -5,6 +5,7 @@ #include "BLI_noise.hh" #include "BLI_set.hh" #include "BLI_stack.hh" +#include "BLI_timeit.hh" #include "BLI_vector_set.hh" #include "DNA_anim_types.h" @@ -21,7 +22,6 @@ #include "MOD_nodes.h" #include "NOD_node_declaration.hh" -#include "NOD_node_tree_ref.hh" #include "NOD_texture.h" #include "DEG_depsgraph_query.h" @@ -50,6 +50,7 @@ enum eNodeTreeChangedFlag { static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag) { ntree->runtime->changed_flag |= flag; + ntree->runtime->topology_cache_is_dirty = true; } static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag) @@ -73,31 +74,32 @@ static bool is_field_socket_type(eNodeSocketDatatype type) return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA); } -static bool is_field_socket_type(const SocketRef &socket) +static bool is_field_socket_type(const bNodeSocket &socket) { - return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type); + return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo->type); } -static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, - const InputSocketRef &socket) +static InputSocketFieldType get_interface_input_field_type(const bNode &node, + const bNodeSocket &socket) { if (!is_field_socket_type(socket)) { return InputSocketFieldType::None; } - if (node.is_reroute_node()) { + if (node.type == NODE_REROUTE) { return InputSocketFieldType::IsSupported; } - if (node.is_group_output_node()) { + if (node.type == NODE_GROUP_OUTPUT) { /* Outputs always support fields when the data type is correct. */ return InputSocketFieldType::IsSupported; } - if (node.is_undefined()) { + if (node.typeinfo == &NodeTypeUndefined) { return InputSocketFieldType::None; } - if (node.bnode()->type == NODE_CUSTOM) { + if (node.type == NODE_CUSTOM) { return InputSocketFieldType::None; } + /* TODO: Ensure declaration exists. */ const NodeDeclaration *node_decl = node.declaration(); /* Node declarations should be implemented for nodes involved here. */ @@ -116,25 +118,25 @@ static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, return field_type; } -static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node, - const OutputSocketRef &socket) +static OutputFieldDependency get_interface_output_field_dependency(const bNode &node, + const bNodeSocket &socket) { if (!is_field_socket_type(socket)) { /* Non-field sockets always output data. */ return OutputFieldDependency::ForDataSource(); } - if (node.is_reroute_node()) { + if (node.type == NODE_REROUTE) { /* The reroute just forwards what is passed in. */ return OutputFieldDependency::ForDependentField(); } - if (node.is_group_input_node()) { + if (node.type == NODE_GROUP_INPUT) { /* Input nodes get special treatment in #determine_group_input_states. */ return OutputFieldDependency::ForDependentField(); } - if (node.is_undefined()) { + if (node.typeinfo == &NodeTypeUndefined) { return OutputFieldDependency::ForDataSource(); } - if (node.bnode()->type == NODE_CUSTOM) { + if (node.type == NODE_CUSTOM) { return OutputFieldDependency::ForDataSource(); } @@ -153,12 +155,13 @@ static OutputFieldDependency get_interface_output_field_dependency(const NodeRef return socket_decl.output_field_dependency(); } -static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node) +static FieldInferencingInterface get_dummy_field_inferencing_interface(const bNode &node) { FieldInferencingInterface inferencing_interface; - inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size()); + inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, + node.input_sockets().size()); inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(), - node.outputs().size()); + node.output_sockets().size()); return inferencing_interface; } @@ -167,11 +170,11 @@ static FieldInferencingInterface get_dummy_field_inferencing_interface(const Nod * In the future, this information can be stored in the node declaration. This would allow this * function to return a reference, making it more efficient. */ -static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node) +static FieldInferencingInterface get_node_field_inferencing_interface(const bNode &node) { /* Node groups already reference all required information, so just return that. */ - if (node.is_group_node()) { - bNodeTree *group = (bNodeTree *)node.bnode()->id; + if (node.is_group()) { + bNodeTree *group = (bNodeTree *)node.id; if (group == nullptr) { return FieldInferencingInterface(); } @@ -187,11 +190,11 @@ static FieldInferencingInterface get_node_field_inferencing_interface(const Node } FieldInferencingInterface inferencing_interface; - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket)); } - for (const OutputSocketRef *output_socket : node.outputs()) { + for (const bNodeSocket *output_socket : node.output_sockets()) { inferencing_interface.outputs.append( get_interface_output_field_dependency(node, *output_socket)); } @@ -215,11 +218,11 @@ struct SocketFieldState { bool requires_single = false; }; -static Vector<const InputSocketRef *> gather_input_socket_dependencies( - const OutputFieldDependency &field_dependency, const NodeRef &node) +static Vector<const bNodeSocket *> gather_input_socket_dependencies( + const OutputFieldDependency &field_dependency, const bNode &node) { const OutputSocketFieldType type = field_dependency.field_type(); - Vector<const InputSocketRef *> input_sockets; + Vector<const bNodeSocket *> input_sockets; switch (type) { case OutputSocketFieldType::FieldSource: case OutputSocketFieldType::None: { @@ -227,13 +230,13 @@ static Vector<const InputSocketRef *> gather_input_socket_dependencies( } case OutputSocketFieldType::DependentField: { /* This output depends on all inputs. */ - input_sockets.extend(node.inputs()); + input_sockets.extend(node.input_sockets()); break; } case OutputSocketFieldType::PartiallyDependent: { /* This output depends only on a few inputs. */ for (const int i : field_dependency.linked_input_indices()) { - input_sockets.append(&node.input(i)); + input_sockets.append(&node.input_socket(i)); } break; } @@ -246,8 +249,7 @@ static Vector<const InputSocketRef *> gather_input_socket_dependencies( * to figure out if it is always a field or if it depends on any group inputs. */ static OutputFieldDependency find_group_output_dependencies( - const InputSocketRef &group_output_socket, - const Span<SocketFieldState> field_state_by_socket_id) + const bNodeSocket &group_output_socket, const Span<SocketFieldState> field_state_by_socket_id) { if (!is_field_socket_type(group_output_socket)) { return OutputFieldDependency::ForDataSource(); @@ -255,8 +257,8 @@ static OutputFieldDependency find_group_output_dependencies( /* Use a Set here instead of an array indexed by socket id, because we my only need to look at * very few sockets. */ - Set<const InputSocketRef *> handled_sockets; - Stack<const InputSocketRef *> sockets_to_check; + Set<const bNodeSocket *> handled_sockets; + Stack<const bNodeSocket *> sockets_to_check; handled_sockets.add(&group_output_socket); sockets_to_check.push(&group_output_socket); @@ -265,20 +267,21 @@ static OutputFieldDependency find_group_output_dependencies( Vector<int> linked_input_indices; while (!sockets_to_check.is_empty()) { - const InputSocketRef *input_socket = sockets_to_check.pop(); + const bNodeSocket *input_socket = sockets_to_check.pop(); if (!input_socket->is_directly_linked() && - !field_state_by_socket_id[input_socket->id()].is_single) { + !field_state_by_socket_id[input_socket->index_in_tree()].is_single) { /* This socket uses a field as input by default. */ return OutputFieldDependency::ForFieldSource(); } - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - const NodeRef &origin_node = origin_socket->node(); - const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()]; + for (const bNodeSocket *origin_socket : input_socket->directly_linked_sockets()) { + const bNode &origin_node = origin_socket->owner_node(); + const SocketFieldState &origin_state = + field_state_by_socket_id[origin_socket->index_in_tree()]; if (origin_state.is_field_source) { - if (origin_node.is_group_input_node()) { + if (origin_node.type == NODE_GROUP_INPUT) { /* Found a group input that the group output depends on. */ linked_input_indices.append_non_duplicates(origin_socket->index()); } @@ -294,12 +297,12 @@ static OutputFieldDependency find_group_output_dependencies( inferencing_interface.outputs[origin_socket->index()]; /* Propagate search further to the left. */ - for (const InputSocketRef *origin_input_socket : + for (const bNodeSocket *origin_input_socket : gather_input_socket_dependencies(field_dependency, origin_node)) { if (!origin_input_socket->is_available()) { continue; } - if (!field_state_by_socket_id[origin_input_socket->id()].is_single) { + if (!field_state_by_socket_id[origin_input_socket->index_in_tree()].is_single) { if (handled_sockets.add(origin_input_socket)) { sockets_to_check.push(origin_input_socket); } @@ -312,17 +315,16 @@ static OutputFieldDependency find_group_output_dependencies( } static void propagate_data_requirements_from_right_to_left( - const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) + const bNodeTree &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) { - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::RightToLeft); + const Span<const bNode *> toposort_result = tree.toposort_right_to_left(); - for (const NodeRef *node : toposort_result.sorted_nodes) { + for (const bNode *node : toposort_result) { const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface( *node); - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNodeSocket *output_socket : node->output_sockets()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const OutputFieldDependency &field_dependency = inferencing_interface.outputs[output_socket->index()]; @@ -338,17 +340,18 @@ static void propagate_data_requirements_from_right_to_left( /* The output is required to be a single value when it is connected to any input that does * not support fields. */ - for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) { + for (const bNodeSocket *target_socket : output_socket->directly_linked_sockets()) { if (target_socket->is_available()) { - state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single; + state.requires_single |= + field_state_by_socket_id[target_socket->index_in_tree()].requires_single; } } if (state.requires_single) { bool any_input_is_field_implicitly = false; - const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies( + const Vector<const bNodeSocket *> connected_inputs = gather_input_socket_dependencies( field_dependency, *node); - for (const InputSocketRef *input_socket : connected_inputs) { + for (const bNodeSocket *input_socket : connected_inputs) { if (!input_socket->is_available()) { continue; } @@ -367,16 +370,16 @@ static void propagate_data_requirements_from_right_to_left( else { /* If the output is required to be a single value, the connected inputs in the same node * must not be fields as well. */ - for (const InputSocketRef *input_socket : connected_inputs) { - field_state_by_socket_id[input_socket->id()].requires_single = true; + for (const bNodeSocket *input_socket : connected_inputs) { + field_state_by_socket_id[input_socket->index_in_tree()].requires_single = true; } } } } /* Some inputs do not require fields independent of what the outputs are connected to. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + for (const bNodeSocket *input_socket : node->input_sockets()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->index_in_tree()]; if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) { state.requires_single = true; state.is_always_single = true; @@ -386,14 +389,14 @@ static void propagate_data_requirements_from_right_to_left( } static void determine_group_input_states( - const NodeTreeRef &tree, + const bNodeTree &tree, FieldInferencingInterface &new_inferencing_interface, const MutableSpan<SocketFieldState> field_state_by_socket_id) { { /* Non-field inputs never support fields. */ int index; - LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) { + LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.inputs, index) { if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) { new_inferencing_interface.inputs[index] = InputSocketFieldType::None; } @@ -401,18 +404,18 @@ static void determine_group_input_states( } /* Check if group inputs are required to be single values, because they are (indirectly) * connected to some socket that does not support fields. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) { + for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; if (state.requires_single) { new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None; } } } /* If an input does not support fields, this should be reflected in all Group Input nodes. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNode *node : tree.nodes_by_type("NodeGroupInput")) { + for (const bNodeSocket *output_socket : node->output_sockets().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] != InputSocketFieldType::None; if (supports_field) { @@ -423,19 +426,19 @@ static void determine_group_input_states( state.requires_single = true; } } - SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()]; + SocketFieldState &dummy_socket_state = + field_state_by_socket_id[node->output_sockets().last()->index_in_tree()]; dummy_socket_state.requires_single = true; } } static void propagate_field_status_from_left_to_right( - const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) + const bNodeTree &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) { - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::LeftToRight); + const Span<const bNode *> toposort_result = tree.toposort_left_to_right(); - for (const NodeRef *node : toposort_result.sorted_nodes) { - if (node->is_group_input_node()) { + for (const bNode *node : toposort_result) { + if (node->type == NODE_GROUP_INPUT) { continue; } @@ -443,22 +446,22 @@ static void propagate_field_status_from_left_to_right( *node); /* Update field state of input sockets, also taking into account linked origin sockets. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + for (const bNodeSocket *input_socket : node->input_sockets()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->index_in_tree()]; if (state.is_always_single) { state.is_single = true; continue; } state.is_single = true; - if (input_socket->directly_linked_sockets().is_empty()) { + if (!input_socket->is_directly_linked()) { if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::Implicit) { state.is_single = false; } } else { - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - if (!field_state_by_socket_id[origin_socket->id()].is_single) { + for (const bNodeSocket *origin_socket : input_socket->directly_linked_sockets()) { + if (!field_state_by_socket_id[origin_socket->index_in_tree()].is_single) { state.is_single = false; break; } @@ -467,8 +470,8 @@ static void propagate_field_status_from_left_to_right( } /* Update field state of output sockets, also taking into account input sockets. */ - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + for (const bNodeSocket *output_socket : node->output_sockets()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->index_in_tree()]; const OutputFieldDependency &field_dependency = inferencing_interface.outputs[output_socket->index()]; @@ -484,12 +487,12 @@ static void propagate_field_status_from_left_to_right( } case OutputSocketFieldType::PartiallyDependent: case OutputSocketFieldType::DependentField: { - for (const InputSocketRef *input_socket : + for (const bNodeSocket *input_socket : gather_input_socket_dependencies(field_dependency, *node)) { if (!input_socket->is_available()) { continue; } - if (!field_state_by_socket_id[input_socket->id()].is_single) { + if (!field_state_by_socket_id[input_socket->index_in_tree()].is_single) { state.is_single = false; break; } @@ -501,17 +504,18 @@ static void propagate_field_status_from_left_to_right( } } -static void determine_group_output_states(const NodeTreeRef &tree, +static void determine_group_output_states(const bNodeTree &tree, FieldInferencingInterface &new_inferencing_interface, const Span<SocketFieldState> field_state_by_socket_id) { - for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { + for (const bNode *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { /* Ignore inactive group output nodes. */ - if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) { + if (!(group_output_node->flag & NODE_DO_OUTPUT)) { continue; } /* Determine dependencies of all group outputs. */ - for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) { + for (const bNodeSocket *group_output_socket : + group_output_node->input_sockets().drop_back(1)) { OutputFieldDependency field_dependency = find_group_output_dependencies( *group_output_socket, field_state_by_socket_id); new_inferencing_interface.outputs[group_output_socket->index()] = std::move( @@ -521,7 +525,7 @@ static void determine_group_output_states(const NodeTreeRef &tree, } } -static void update_socket_shapes(const NodeTreeRef &tree, +static void update_socket_shapes(const bNodeTree &tree, const Span<SocketFieldState> field_state_by_socket_id) { const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE; @@ -541,32 +545,30 @@ static void update_socket_shapes(const NodeTreeRef &tree, return data_but_can_be_field_shape; }; - for (const InputSocketRef *socket : tree.input_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); + for (const bNodeSocket *socket : tree.all_input_sockets()) { + const SocketFieldState &state = field_state_by_socket_id[socket->index_in_tree()]; + const_cast<bNodeSocket *>(socket)->display_shape = get_shape_for_state(state); } - for (const OutputSocketRef *socket : tree.output_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); + for (const bNodeSocket *socket : tree.all_sockets()) { + const SocketFieldState &state = field_state_by_socket_id[socket->index_in_tree()]; + const_cast<bNodeSocket *>(socket)->display_shape = get_shape_for_state(state); } } -static bool update_field_inferencing(const NodeTreeRef &tree) +static bool update_field_inferencing(const bNodeTree &tree) { - bNodeTree &btree = *tree.btree(); + tree.ensure_topology_cache(); /* Create new inferencing interface for this node group. */ std::unique_ptr<FieldInferencingInterface> new_inferencing_interface = std::make_unique<FieldInferencingInterface>(); - new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs), + new_inferencing_interface->inputs.resize(BLI_listbase_count(&tree.inputs), InputSocketFieldType::IsSupported); - new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs), + new_inferencing_interface->outputs.resize(BLI_listbase_count(&tree.outputs), OutputFieldDependency::ForDataSource()); /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */ - Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size()); + Array<SocketFieldState> field_state_by_socket_id(tree.all_sockets().size()); propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id); determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id); @@ -575,10 +577,10 @@ static bool update_field_inferencing(const NodeTreeRef &tree) update_socket_shapes(tree, field_state_by_socket_id); /* Update the previous group interface. */ - const bool group_interface_changed = !btree.runtime->field_inferencing_interface || - *btree.runtime->field_inferencing_interface != + const bool group_interface_changed = !tree.runtime->field_inferencing_interface || + *tree.runtime->field_inferencing_interface != *new_inferencing_interface; - btree.runtime->field_inferencing_interface = std::move(new_inferencing_interface); + tree.runtime->field_inferencing_interface = std::move(new_inferencing_interface); return group_interface_changed; } @@ -979,29 +981,22 @@ class NodeTreeMainUpdater { { TreeUpdateResult result; - /* Use a #NodeTreeRef to speedup certain queries. It is rebuilt whenever the node tree topology - * changes, which typically happens zero or one times during the entire update of the node - * tree. */ - std::unique_ptr<NodeTreeRef> tree_ref; - this->ensure_tree_ref(ntree, tree_ref); - - this->update_socket_link_and_use(*tree_ref); - this->update_individual_nodes(ntree, tree_ref); - this->update_internal_links(ntree, tree_ref); - this->update_generic_callback(ntree, tree_ref); + this->update_socket_link_and_use(ntree); + this->update_individual_nodes(ntree); + this->update_internal_links(ntree); + this->update_generic_callback(ntree); this->remove_unused_previews_when_necessary(ntree); - this->ensure_tree_ref(ntree, tree_ref); - this->propagate_runtime_flags(*tree_ref); + this->propagate_runtime_flags(ntree); if (ntree.type == NTREE_GEOMETRY) { - if (node_field_inferencing::update_field_inferencing(*tree_ref)) { + if (node_field_inferencing::update_field_inferencing(ntree)) { result.interface_changed = true; } } - result.output_changed = this->check_if_output_changed(*tree_ref); + result.output_changed = this->check_if_output_changed(ntree); - this->update_socket_link_and_use(*tree_ref); + this->update_socket_link_and_use(ntree); this->update_node_levels(ntree); this->update_link_validation(ntree); @@ -1021,86 +1016,69 @@ class NodeTreeMainUpdater { return result; } - void ensure_tree_ref(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) - { - if (!tree_ref) { - tree_ref = std::make_unique<NodeTreeRef>(&ntree); - } - } - - void update_socket_link_and_use(const NodeTreeRef &tree) + void update_socket_link_and_use(bNodeTree &tree) { - for (const InputSocketRef *socket : tree.input_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); + tree.ensure_topology_cache(); + for (bNodeSocket *socket : tree.all_input_sockets()) { if (socket->directly_linked_links().is_empty()) { - bsocket->link = nullptr; + socket->link = nullptr; } else { - bsocket->link = socket->directly_linked_links()[0]->blink(); + socket->link = socket->directly_linked_links()[0]; } } this->update_socket_used_tags(tree); } - void update_socket_used_tags(const NodeTreeRef &tree) + void update_socket_used_tags(bNodeTree &tree) { - for (const SocketRef *socket : tree.sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - bsocket->flag &= ~SOCK_IN_USE; - for (const LinkRef *link : socket->directly_linked_links()) { + tree.ensure_topology_cache(); + for (bNodeSocket *socket : tree.all_sockets()) { + socket->flag &= ~SOCK_IN_USE; + for (const bNodeLink *link : socket->directly_linked_links()) { if (!link->is_muted()) { - bsocket->flag |= SOCK_IN_USE; + socket->flag |= SOCK_IN_USE; break; } } } } - void update_individual_nodes(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + void update_individual_nodes(bNodeTree &ntree) { - /* Iterate over nodes instead of #NodeTreeRef, because the #tree_ref might be outdated after - * some update functions. */ - LISTBASE_FOREACH (bNode *, bnode, &ntree.nodes) { - this->ensure_tree_ref(ntree, tree_ref); - const NodeRef &node = *tree_ref->find_node(*bnode); - if (this->should_update_individual_node(node)) { - const uint32_t old_changed_flag = ntree.runtime->changed_flag; - ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING; - - /* This may set #ntree.runtime->changed_flag which is detected below. */ - this->update_individual_node(node); - - if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - /* The tree ref is outdated and needs to be rebuilt. Generally, only very few update - * functions change the node. Typically zero or one nodes change after an update. */ - tree_ref.reset(); + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + if (this->should_update_individual_node(ntree, *node)) { + bNodeType &ntype = *node->typeinfo; + if (ntype.group_update_func) { + ntype.group_update_func(&ntree, node); + } + if (ntype.updatefunc) { + ntype.updatefunc(&ntree, node); } - ntree.runtime->changed_flag |= old_changed_flag; } } } - bool should_update_individual_node(const NodeRef &node) + bool should_update_individual_node(const bNodeTree &ntree, const bNode &node) { - bNodeTree &ntree = *node.btree(); - bNode &bnode = *node.bnode(); if (ntree.runtime->changed_flag & NTREE_CHANGED_ANY) { return true; } - if (bnode.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { + if (node.runtime->changed_flag & NTREE_CHANGED_NODE_PROPERTY) { return true; } if (ntree.runtime->changed_flag & NTREE_CHANGED_LINK) { + ntree.ensure_topology_cache(); /* Node groups currently always rebuilt their sockets when they are updated. * So avoid calling the update method when no new link was added to it. */ - if (node.is_group_input_node()) { - if (node.outputs().last()->is_directly_linked()) { + if (node.type == NODE_GROUP_INPUT) { + if (node.output_sockets().last()->is_directly_linked()) { return true; } } - else if (node.is_group_output_node()) { - if (node.inputs().last()->is_directly_linked()) { + else if (node.type == NODE_GROUP_OUTPUT) { + if (node.input_sockets().last()->is_directly_linked()) { return true; } } @@ -1110,95 +1088,76 @@ class NodeTreeMainUpdater { } } if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) { - if (node.is_group_input_node() || node.is_group_output_node()) { + if (ELEM(node.type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { return true; } } return false; } - void update_individual_node(const NodeRef &node) - { - bNodeTree &ntree = *node.btree(); - bNode &bnode = *node.bnode(); - bNodeType &ntype = *bnode.typeinfo; - if (ntype.group_update_func) { - ntype.group_update_func(&ntree, &bnode); - } - if (ntype.updatefunc) { - ntype.updatefunc(&ntree, &bnode); - } - } - - void update_internal_links(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + void update_internal_links(bNodeTree &ntree) { - bool any_internal_links_updated = false; - this->ensure_tree_ref(ntree, tree_ref); - for (const NodeRef *node : tree_ref->nodes()) { - if (!this->should_update_individual_node(*node)) { + bke::node_tree_runtime::AllowUsingOutdatedInfo allow_outdated_info{ntree}; + ntree.ensure_topology_cache(); + for (bNode *node : ntree.all_nodes()) { + if (!this->should_update_individual_node(ntree, *node)) { continue; } /* Find all expected internal links. */ Vector<std::pair<bNodeSocket *, bNodeSocket *>> expected_internal_links; - for (const OutputSocketRef *output_socket : node->outputs()) { + for (const bNodeSocket *output_socket : node->output_sockets()) { if (!output_socket->is_available()) { continue; } if (!output_socket->is_directly_linked()) { continue; } - if (output_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + if (output_socket->flag & SOCK_NO_INTERNAL_LINK) { continue; } - const InputSocketRef *input_socket = this->find_internally_linked_input(output_socket); + const bNodeSocket *input_socket = this->find_internally_linked_input(output_socket); if (input_socket != nullptr) { - expected_internal_links.append({input_socket->bsocket(), output_socket->bsocket()}); + expected_internal_links.append( + {const_cast<bNodeSocket *>(input_socket), const_cast<bNodeSocket *>(output_socket)}); } } - /* rebuilt internal links if they have changed. */ - if (node->internal_links().size() != expected_internal_links.size()) { - this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); - any_internal_links_updated = true; + /* Rebuilt internal links if they have changed. */ + if (node->internal_links_span().size() != expected_internal_links.size()) { + this->update_internal_links_in_node(ntree, *node, expected_internal_links); } else { for (auto &item : expected_internal_links) { const bNodeSocket *from_socket = item.first; const bNodeSocket *to_socket = item.second; bool found = false; - for (const InternalLinkRef *internal_link : node->internal_links()) { - if (from_socket == internal_link->from().bsocket() && - to_socket == internal_link->to().bsocket()) { + for (const bNodeLink *internal_link : node->internal_links_span()) { + if (from_socket == internal_link->fromsock && to_socket == internal_link->tosock) { found = true; } } if (!found) { - this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); - any_internal_links_updated = true; + this->update_internal_links_in_node(ntree, *node, expected_internal_links); break; } } } } - - if (any_internal_links_updated) { - tree_ref.reset(); - } } - const InputSocketRef *find_internally_linked_input(const OutputSocketRef *output_socket) + const bNodeSocket *find_internally_linked_input(const bNodeSocket *output_socket) { - const InputSocketRef *selected_socket = nullptr; + const bNodeSocket *selected_socket = nullptr; int selected_priority = -1; bool selected_is_linked = false; - for (const InputSocketRef *input_socket : output_socket->node().inputs()) { + for (const bNodeSocket *input_socket : output_socket->owner_node().input_sockets()) { if (!input_socket->is_available()) { continue; } - if (input_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + if (input_socket->flag & SOCK_NO_INTERNAL_LINK) { continue; } - const int priority = get_internal_link_type_priority(input_socket->bsocket()->typeinfo, - output_socket->bsocket()->typeinfo); + const int priority = get_internal_link_type_priority(input_socket->typeinfo, + output_socket->typeinfo); if (priority < 0) { continue; } @@ -1233,23 +1192,12 @@ class NodeTreeMainUpdater { BKE_ntree_update_tag_node_internal_link(&ntree, &node); } - void update_generic_callback(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + void update_generic_callback(bNodeTree &ntree) { if (ntree.typeinfo->update == nullptr) { return; } - - /* Reset the changed_flag to allow detecting when the update callback changed the node tree. */ - const uint32_t old_changed_flag = ntree.runtime->changed_flag; - ntree.runtime->changed_flag = NTREE_CHANGED_NOTHING; - ntree.typeinfo->update(&ntree); - - if (ntree.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - /* The tree ref is outdated and needs to be rebuilt. */ - tree_ref.reset(); - } - ntree.runtime->changed_flag |= old_changed_flag; } void remove_unused_previews_when_necessary(bNodeTree &ntree) @@ -1264,25 +1212,26 @@ class NodeTreeMainUpdater { BKE_node_preview_remove_unused(&ntree); } - void propagate_runtime_flags(const NodeTreeRef &tree_ref) + void propagate_runtime_flags(const bNodeTree &ntree) { - bNodeTree &ntree = *tree_ref.btree(); + ntree.ensure_topology_cache(); + ntree.runtime->runtime_flag = 0; if (ntree.type != NTREE_SHADER) { return; } /* Check if a used node group has an animated image. */ - for (const NodeRef *group_node : tree_ref.nodes_by_type("ShaderNodeGroup")) { - const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->bnode()->id); + for (const bNode *group_node : ntree.nodes_by_type("ShaderNodeGroup")) { + const bNodeTree *group = reinterpret_cast<bNodeTree *>(group_node->id); if (group != nullptr) { ntree.runtime->runtime_flag |= group->runtime->runtime_flag; } } /* Check if the tree itself has an animated image. */ for (const StringRefNull idname : {"ShaderNodeTexImage", "ShaderNodeTexEnvironment"}) { - for (const NodeRef *node : tree_ref.nodes_by_type(idname)) { - Image *image = reinterpret_cast<Image *>(node->bnode()->id); + for (const bNode *node : ntree.nodes_by_type(idname)) { + Image *image = reinterpret_cast<Image *>(node->id); if (image != nullptr && BKE_image_is_animated(image)) { ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION; break; @@ -1294,7 +1243,7 @@ class NodeTreeMainUpdater { "ShaderNodeOutputLight", "ShaderNodeOutputWorld", "ShaderNodeOutputAOV"}) { - const Span<const NodeRef *> nodes = tree_ref.nodes_by_type(idname); + const Span<const bNode *> nodes = ntree.nodes_by_type(idname); if (!nodes.is_empty()) { ntree.runtime->runtime_flag |= NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT; break; @@ -1325,20 +1274,20 @@ class NodeTreeMainUpdater { } } - bool check_if_output_changed(const NodeTreeRef &tree) + bool check_if_output_changed(const bNodeTree &tree) { - bNodeTree &btree = *tree.btree(); + tree.ensure_topology_cache(); /* Compute a hash that represents the node topology connected to the output. This always has to * be updated even if it is not used to detect changes right now. Otherwise * #btree.runtime.output_topology_hash will go out of date. */ - const Vector<const SocketRef *> tree_output_sockets = this->find_output_sockets(tree); - const uint32_t old_topology_hash = btree.runtime->output_topology_hash; + const Vector<const bNodeSocket *> tree_output_sockets = this->find_output_sockets(tree); + const uint32_t old_topology_hash = tree.runtime->output_topology_hash; const uint32_t new_topology_hash = this->get_combined_socket_topology_hash( tree, tree_output_sockets); - btree.runtime->output_topology_hash = new_topology_hash; + tree.runtime->output_topology_hash = new_topology_hash; - if (const AnimData *adt = BKE_animdata_from_id(&btree.id)) { + if (const AnimData *adt = BKE_animdata_from_id(&tree.id)) { /* Drivers may copy values in the node tree around arbitrarily and may cause the output to * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can * be used without causing updates all the time currently. In the future we could try to @@ -1360,7 +1309,7 @@ class NodeTreeMainUpdater { } } - if (btree.runtime->changed_flag & NTREE_CHANGED_ANY) { + if (tree.runtime->changed_flag & NTREE_CHANGED_ANY) { return true; } @@ -1369,8 +1318,8 @@ class NodeTreeMainUpdater { } /* The topology hash can only be used when only topology-changing operations have been done. */ - if (btree.runtime->changed_flag == - (btree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) { + if (tree.runtime->changed_flag == + (tree.runtime->changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) { if (old_topology_hash == new_topology_hash) { return false; } @@ -1383,15 +1332,15 @@ class NodeTreeMainUpdater { return true; } - Vector<const SocketRef *> find_output_sockets(const NodeTreeRef &tree) + Vector<const bNodeSocket *> find_output_sockets(const bNodeTree &tree) { - Vector<const SocketRef *> sockets; - for (const NodeRef *node : tree.nodes()) { + Vector<const bNodeSocket *> sockets; + for (const bNode *node : tree.all_nodes()) { if (!this->is_output_node(*node)) { continue; } - for (const InputSocketRef *socket : node->inputs()) { - if (socket->idname() != "NodeSocketVirtual") { + for (const bNodeSocket *socket : node->input_sockets()) { + if (!STREQ(socket->idname, "NodeSocketVirtual")) { sockets.append(socket); } } @@ -1399,18 +1348,17 @@ class NodeTreeMainUpdater { return sockets; } - bool is_output_node(const NodeRef &node) const + bool is_output_node(const bNode &node) const { - const bNode &bnode = *node.bnode(); - if (bnode.typeinfo->nclass == NODE_CLASS_OUTPUT) { + if (node.typeinfo->nclass == NODE_CLASS_OUTPUT) { return true; } - if (bnode.type == NODE_GROUP_OUTPUT) { + if (node.type == NODE_GROUP_OUTPUT) { return true; } /* Assume node groups without output sockets are outputs. */ - if (bnode.type == NODE_GROUP) { - const bNodeTree *node_group = reinterpret_cast<const bNodeTree *>(bnode.id); + if (node.type == NODE_GROUP) { + const bNodeTree *node_group = reinterpret_cast<const bNodeTree *>(node.id); if (node_group != nullptr && node_group->runtime->runtime_flag & NTREE_RUNTIME_FLAG_HAS_MATERIAL_OUTPUT) { return true; @@ -1423,10 +1371,10 @@ class NodeTreeMainUpdater { * Computes a hash that changes when the node tree topology connected to an output node changes. * Adding reroutes does not have an effect on the hash. */ - uint32_t get_combined_socket_topology_hash(const NodeTreeRef &tree, - Span<const SocketRef *> sockets) + uint32_t get_combined_socket_topology_hash(const bNodeTree &tree, + Span<const bNodeSocket *> sockets) { - if (tree.has_link_cycles()) { + if (tree.has_link_cycle()) { /* Return dummy value when the link has any cycles. The algorithm below could be improved to * handle cycles more gracefully. */ return 0; @@ -1439,29 +1387,28 @@ class NodeTreeMainUpdater { return combined_hash; } - Array<uint32_t> get_socket_topology_hashes(const NodeTreeRef &tree, - Span<const SocketRef *> sockets) + Array<uint32_t> get_socket_topology_hashes(const bNodeTree &tree, + Span<const bNodeSocket *> sockets) { - BLI_assert(!tree.has_link_cycles()); - Array<std::optional<uint32_t>> hash_by_socket_id(tree.sockets().size()); - Stack<const SocketRef *> sockets_to_check = sockets; + BLI_assert(!tree.has_link_cycle()); + Array<std::optional<uint32_t>> hash_by_socket_id(tree.all_sockets().size()); + Stack<const bNodeSocket *> sockets_to_check = sockets; while (!sockets_to_check.is_empty()) { - const SocketRef &in_out_socket = *sockets_to_check.peek(); - const NodeRef &node = in_out_socket.node(); + const bNodeSocket &socket = *sockets_to_check.peek(); + const bNode &node = socket.owner_node(); - if (hash_by_socket_id[in_out_socket.id()].has_value()) { + if (hash_by_socket_id[socket.index_in_tree()].has_value()) { sockets_to_check.pop(); /* Socket is handled already. */ continue; } - if (in_out_socket.is_input()) { + if (socket.is_input()) { /* For input sockets, first compute the hashes of all linked sockets. */ - const InputSocketRef &socket = in_out_socket.as_input(); bool all_origins_computed = true; - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - if (!hash_by_socket_id[origin_socket->id()].has_value()) { + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + if (!hash_by_socket_id[origin_socket->index_in_tree()].has_value()) { sockets_to_check.push(origin_socket); all_origins_computed = false; } @@ -1471,22 +1418,21 @@ class NodeTreeMainUpdater { } /* When the hashes for the linked sockets are ready, combine them into a hash for the input * socket. */ - const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + const uint64_t socket_ptr = (uintptr_t)&socket; uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->id()]; + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->index_in_tree()]; socket_hash = noise::hash(socket_hash, origin_socket_hash); } - hash_by_socket_id[socket.id()] = socket_hash; + hash_by_socket_id[socket.index_in_tree()] = socket_hash; sockets_to_check.pop(); } else { /* For output sockets, first compute the hashes of all available input sockets. */ - const OutputSocketRef &socket = in_out_socket.as_output(); bool all_available_inputs_computed = true; - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - if (!hash_by_socket_id[input_socket->id()].has_value()) { + if (!hash_by_socket_id[input_socket->index_in_tree()].has_value()) { sockets_to_check.push(input_socket); all_available_inputs_computed = false; } @@ -1497,25 +1443,25 @@ class NodeTreeMainUpdater { } /* When all input socket hashes have been computed, combine them into a hash for the output * socket. */ - const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + const uint64_t socket_ptr = (uintptr_t)&socket; uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->id()]; + const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->index_in_tree()]; socket_hash = noise::hash(socket_hash, input_socket_hash); } } /* The Image Texture node has a special case. The behavior of the color output changes * depending on whether the Alpha output is linked. */ - if (node.bnode()->type == SH_NODE_TEX_IMAGE && socket.index() == 0) { - BLI_assert(socket.name() == "Color"); - const OutputSocketRef &alpha_socket = node.output(1); - BLI_assert(alpha_socket.name() == "Alpha"); + if (node.type == SH_NODE_TEX_IMAGE && socket.index() == 0) { + BLI_assert(STREQ(socket.name, "Color")); + const bNodeSocket &alpha_socket = node.output_socket(1); + BLI_assert(STREQ(alpha_socket.name, "Alpha")); if (alpha_socket.is_directly_linked()) { socket_hash = noise::hash(socket_hash); } } - hash_by_socket_id[socket.id()] = socket_hash; + hash_by_socket_id[socket.index_in_tree()] = socket_hash; sockets_to_check.pop(); } } @@ -1523,7 +1469,7 @@ class NodeTreeMainUpdater { /* Create output array. */ Array<uint32_t> hashes(sockets.size()); for (const int i : sockets.index_range()) { - hashes[i] = *hash_by_socket_id[sockets[i]->id()]; + hashes[i] = *hash_by_socket_id[sockets[i]->index_in_tree()]; } return hashes; } @@ -1532,37 +1478,34 @@ class NodeTreeMainUpdater { * Returns true when any of the provided sockets changed its values. A change is detected by * checking the #changed_flag on connected sockets and nodes. */ - bool check_if_socket_outputs_changed_based_on_flags(const NodeTreeRef &tree, - Span<const SocketRef *> sockets) + bool check_if_socket_outputs_changed_based_on_flags(const bNodeTree &tree, + Span<const bNodeSocket *> sockets) { /* Avoid visiting the same socket twice when multiple links point to the same socket. */ - Array<bool> pushed_by_socket_id(tree.sockets().size(), false); - Stack<const SocketRef *> sockets_to_check = sockets; + Array<bool> pushed_by_socket_id(tree.all_sockets().size(), false); + Stack<const bNodeSocket *> sockets_to_check = sockets; - for (const SocketRef *socket : sockets) { - pushed_by_socket_id[socket->id()] = true; + for (const bNodeSocket *socket : sockets) { + pushed_by_socket_id[socket->index_in_tree()] = true; } while (!sockets_to_check.is_empty()) { - const SocketRef &in_out_socket = *sockets_to_check.pop(); - const NodeRef &node = in_out_socket.node(); - const bNode &bnode = *node.bnode(); - const bNodeSocket &bsocket = *in_out_socket.bsocket(); - if (bsocket.runtime->changed_flag != NTREE_CHANGED_NOTHING) { + const bNodeSocket &socket = *sockets_to_check.pop(); + const bNode &node = socket.owner_node(); + if (socket.runtime->changed_flag != NTREE_CHANGED_NOTHING) { return true; } - if (bnode.runtime->changed_flag != NTREE_CHANGED_NOTHING) { - const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 && - bnode.runtime->changed_flag == + if (node.runtime->changed_flag != NTREE_CHANGED_NOTHING) { + const bool only_unused_internal_link_changed = !node.is_muted() && + node.runtime->changed_flag == NTREE_CHANGED_INTERNAL_LINK; if (!only_unused_internal_link_changed) { return true; } } - if (in_out_socket.is_input()) { - const InputSocketRef &socket = in_out_socket.as_input(); - for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { - bool &pushed = pushed_by_socket_id[origin_socket->id()]; + if (socket.is_input()) { + for (const bNodeSocket *origin_socket : socket.logically_linked_sockets()) { + bool &pushed = pushed_by_socket_id[origin_socket->index_in_tree()]; if (!pushed) { sockets_to_check.push(origin_socket); pushed = true; @@ -1570,10 +1513,9 @@ class NodeTreeMainUpdater { } } else { - const OutputSocketRef &socket = in_out_socket.as_output(); - for (const InputSocketRef *input_socket : node.inputs()) { + for (const bNodeSocket *input_socket : node.input_sockets()) { if (input_socket->is_available()) { - bool &pushed = pushed_by_socket_id[input_socket->id()]; + bool &pushed = pushed_by_socket_id[input_socket->index_in_tree()]; if (!pushed) { sockets_to_check.push(input_socket); pushed = true; @@ -1582,11 +1524,11 @@ class NodeTreeMainUpdater { } /* The Normal node has a special case, because the value stored in the first output socket * is used as input in the node. */ - if (bnode.type == SH_NODE_NORMAL && socket.index() == 1) { - BLI_assert(socket.name() == "Dot"); - const OutputSocketRef &normal_output = node.output(0); - BLI_assert(normal_output.name() == "Normal"); - bool &pushed = pushed_by_socket_id[normal_output.id()]; + if (node.type == SH_NODE_NORMAL && socket.index() == 1) { + BLI_assert(STREQ(socket.name, "Dot")); + const bNodeSocket &normal_output = node.output_socket(0); + BLI_assert(STREQ(normal_output.name, "Normal")); + bool &pushed = pushed_by_socket_id[normal_output.index_in_tree()]; if (!pushed) { sockets_to_check.push(&normal_output); pushed = true; diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 2a85811e2e8..c90c83074bd 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1665,7 +1665,7 @@ static void copy_ccg_data(Mesh *mesh_destination, Mesh *mesh_source, int layer_t const int layer_index = CustomData_get_layer_index(data_destination, layer_type); CustomData_free_layer(data_destination, layer_type, num_elements, layer_index); BLI_assert(!CustomData_has_layer(data_destination, layer_type)); - CustomData_add_layer(data_destination, layer_type, CD_CALLOC, nullptr, num_elements); + CustomData_add_layer(data_destination, layer_type, CD_SET_DEFAULT, nullptr, num_elements); BLI_assert(CustomData_has_layer(data_destination, layer_type)); CustomData_copy_layer_type_data(data_source, data_destination, layer_type, 0, 0, num_elements); } diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index 310ec7678bd..08d98775e34 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -115,7 +115,8 @@ MDeformVert *BKE_object_defgroup_data_create(ID *id) { if (GS(id->name) == ID_ME) { Mesh *me = (Mesh *)id; - me->dvert = CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, me->totvert); + me->dvert = CustomData_add_layer( + &me->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, me->totvert); return me->dvert; } if (GS(id->name) == ID_LT) { diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index 407a2c8955c..228bc682ddd 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -29,6 +29,7 @@ #include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" #include "DNA_vfont_types.h" +#include "DNA_volume_types.h" #include "BKE_collection.h" #include "BKE_duplilist.h" @@ -164,10 +165,8 @@ static bool copy_dupli_context( * * \param mat: is transform of the object relative to current context (including #Object.obmat). */ -static DupliObject *make_dupli(const DupliContext *ctx, - Object *ob, - const float mat[4][4], - int index) +static DupliObject *make_dupli( + const DupliContext *ctx, Object *ob, const ID *object_data, const float mat[4][4], int index) { DupliObject *dob; int i; @@ -182,7 +181,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, } dob->ob = ob; - dob->ob_data = (ID *)ob->data; + dob->ob_data = const_cast<ID *>(object_data); mul_m4_m4m4(dob->mat, (float(*)[4])ctx->space_mat, mat); dob->type = ctx->gen->type; @@ -202,7 +201,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, /* Meta-balls never draw in duplis, they are instead merged into one by the basis * meta-ball outside of the group. this does mean that if that meta-ball is not in the * scene, they will not show up at all, limitation that should be solved once. */ - if (ob->type == OB_MBALL) { + if (object_data && GS(object_data->name) == ID_MB) { dob->no_draw = true; } @@ -226,6 +225,14 @@ static DupliObject *make_dupli(const DupliContext *ctx, return dob; } +static DupliObject *make_dupli(const DupliContext *ctx, + Object *ob, + const float mat[4][4], + int index) +{ + return make_dupli(ctx, ob, static_cast<ID *>(ob->data), mat, index); +} + /** * Recursive dupli-objects. * @@ -777,28 +784,24 @@ static void make_duplis_geometry_set_impl(const DupliContext *ctx, int component_index = 0; if (ctx->object->type != OB_MESH || geometry_set_is_instance) { if (const Mesh *mesh = geometry_set.get_mesh_for_read()) { - DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); - dupli->ob_data = (ID *)mesh; + make_dupli(ctx, ctx->object, &mesh->id, parent_transform, component_index++); } } if (ctx->object->type != OB_VOLUME || geometry_set_is_instance) { if (const Volume *volume = geometry_set.get_volume_for_read()) { - DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); - dupli->ob_data = (ID *)volume; + make_dupli(ctx, ctx->object, &volume->id, parent_transform, component_index++); } } if (!ELEM(ctx->object->type, OB_CURVES_LEGACY, OB_FONT, OB_CURVES) || geometry_set_is_instance) { if (const CurveComponent *component = geometry_set.get_component_for_read<CurveComponent>()) { if (const Curve *curve = component->get_curve_for_render()) { - DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); - dupli->ob_data = (ID *)curve; + make_dupli(ctx, ctx->object, &curve->id, parent_transform, component_index++); } } } if (ctx->object->type != OB_POINTCLOUD || geometry_set_is_instance) { if (const PointCloud *pointcloud = geometry_set.get_pointcloud_for_read()) { - DupliObject *dupli = make_dupli(ctx, ctx->object, parent_transform, component_index++); - dupli->ob_data = (ID *)pointcloud; + make_dupli(ctx, ctx->object, &pointcloud->id, parent_transform, component_index++); } } const bool creates_duplis_for_components = component_index >= 1; @@ -1560,6 +1563,13 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) return nullptr; } + /* Metaball objects can't create instances, but the dupli system is used to "instance" their + * evaluated mesh to render engines. We need to exit early to avoid recursively instancing the + * evaluated metaball mesh on metaball instances that already contribute to the basis. */ + if (ctx->object->type == OB_MBALL && ctx->level > 0) { + return nullptr; + } + /* Should the dupli's be generated for this object? - Respect restrict flags. */ if (DEG_get_mode(ctx->depsgraph) == DAG_EVAL_RENDER ? (visibility_flag & OB_HIDE_RENDER) : (visibility_flag & OB_HIDE_VIEWPORT)) { diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 8ff02c7e698..5656a9f6c92 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -110,7 +110,6 @@ void BKE_object_eval_constraints(Depsgraph *depsgraph, Scene *scene, Object *ob) * - post (i.e. BKE_constraints_clear_evalob) * * Not sure why, this is from Joshua - sergey - * */ cob = BKE_constraints_make_evalob(depsgraph, scene, ob, NULL, CONSTRAINT_OBTYPE_OBJECT); BKE_constraints_solve(depsgraph, &ob->constraints, cob, ctime); @@ -149,10 +148,6 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o cddata_masks.pmask |= CD_MASK_PROP_ALL; cddata_masks.lmask |= CD_MASK_PROP_ALL; - /* Also copy over normal layers to avoid recomputation. */ - cddata_masks.pmask |= CD_MASK_NORMAL; - cddata_masks.vmask |= CD_MASK_NORMAL; - /* Make sure Freestyle edge/face marks appear in DM for render (see T40315). * Due to Line Art implementation, edge marks should also be shown in viewport. */ #ifdef WITH_FREESTYLE @@ -173,7 +168,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o break; case OB_MBALL: - BKE_displist_make_mball(depsgraph, scene, ob); + BKE_mball_data_update(depsgraph, scene, ob); break; case OB_CURVES_LEGACY: @@ -285,45 +280,45 @@ void BKE_object_eval_uber_transform(Depsgraph *UNUSED(depsgraph), Object *UNUSED { } -void BKE_object_data_batch_cache_dirty_tag(ID *object_data) +void BKE_object_batch_cache_dirty_tag(Object *ob) { - switch (GS(object_data->name)) { - case ID_ME: - BKE_mesh_batch_cache_dirty_tag((struct Mesh *)object_data, BKE_MESH_BATCH_DIRTY_ALL); + switch (ob->type) { + case OB_MESH: + BKE_mesh_batch_cache_dirty_tag((struct Mesh *)ob->data, BKE_MESH_BATCH_DIRTY_ALL); break; - case ID_LT: - BKE_lattice_batch_cache_dirty_tag((struct Lattice *)object_data, - BKE_LATTICE_BATCH_DIRTY_ALL); + case OB_LATTICE: + BKE_lattice_batch_cache_dirty_tag((struct Lattice *)ob->data, BKE_LATTICE_BATCH_DIRTY_ALL); break; - case ID_CU_LEGACY: - BKE_curve_batch_cache_dirty_tag((struct Curve *)object_data, BKE_CURVE_BATCH_DIRTY_ALL); + case OB_CURVES_LEGACY: + BKE_curve_batch_cache_dirty_tag((struct Curve *)ob->data, BKE_CURVE_BATCH_DIRTY_ALL); break; - case ID_MB: - BKE_mball_batch_cache_dirty_tag((struct MetaBall *)object_data, BKE_MBALL_BATCH_DIRTY_ALL); + case OB_MBALL: { + /* This function is currently called on original objects, so to properly + * clear the actual displayed geometry, we have to tag the evaluated mesh. */ + Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(ob); + if (mesh) { + BKE_mesh_batch_cache_dirty_tag(mesh, BKE_MESH_BATCH_DIRTY_ALL); + } break; - case ID_GD: - BKE_gpencil_batch_cache_dirty_tag((struct bGPdata *)object_data); + } + case OB_GPENCIL: + BKE_gpencil_batch_cache_dirty_tag((struct bGPdata *)ob->data); break; - case ID_CV: - BKE_curves_batch_cache_dirty_tag((struct Curves *)object_data, BKE_CURVES_BATCH_DIRTY_ALL); + case OB_CURVES: + BKE_curves_batch_cache_dirty_tag((struct Curves *)ob->data, BKE_CURVES_BATCH_DIRTY_ALL); break; - case ID_PT: - BKE_pointcloud_batch_cache_dirty_tag((struct PointCloud *)object_data, + case OB_POINTCLOUD: + BKE_pointcloud_batch_cache_dirty_tag((struct PointCloud *)ob->data, BKE_POINTCLOUD_BATCH_DIRTY_ALL); break; - case ID_VO: - BKE_volume_batch_cache_dirty_tag((struct Volume *)object_data, BKE_VOLUME_BATCH_DIRTY_ALL); + case OB_VOLUME: + BKE_volume_batch_cache_dirty_tag((struct Volume *)ob->data, BKE_VOLUME_BATCH_DIRTY_ALL); break; default: break; } } -void BKE_object_batch_cache_dirty_tag(Object *ob) -{ - BKE_object_data_batch_cache_dirty_tag(ob->data); -} - void BKE_object_eval_uber_data(Depsgraph *depsgraph, Scene *scene, Object *ob) { DEG_debug_print_eval(depsgraph, __func__, ob->id.name, ob); diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index dec9a594938..cd1f24fee37 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -1385,9 +1385,8 @@ void BKE_ocean_bake(struct Ocean *o, void (*update_cb)(void *, float progress, int *cancel), void *update_cb_data) { - /* NOTE(campbell): some of these values remain uninitialized unless certain options - * are enabled, take care that BKE_ocean_eval_ij() initializes a member - * before use. */ + /* NOTE(@campbellbarton): some of these values remain uninitialized unless certain options + * are enabled, take care that #BKE_ocean_eval_ij() initializes a member before use. */ OceanResult ocr; ImageFormatData imf = {0}; @@ -1441,7 +1440,7 @@ void BKE_ocean_bake(struct Ocean *o, rgb_to_rgba_unit_alpha(&ibuf_disp->rect_float[4 * (res_x * y + x)], ocr.disp); if (o->_do_jacobian) { - /* TODO(campbell): cleanup unused code. */ + /* TODO(@campbellbarton): cleanup unused code. */ float /* r, */ /* UNUSED */ pr = 0.0f, foam_result; float neg_disp, neg_eplus; diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c deleted file mode 100644 index 09e2baf2be1..00000000000 --- a/source/blender/blenkernel/intern/outliner_treehash.c +++ /dev/null @@ -1,256 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup bke - * - * Tree hash for the outliner space. - */ - -#include <stdlib.h> -#include <string.h> - -#include "BLI_ghash.h" -#include "BLI_mempool.h" -#include "BLI_utildefines.h" - -#include "DNA_outliner_types.h" - -#include "BKE_outliner_treehash.h" - -#include "MEM_guardedalloc.h" - -typedef struct TseGroup { - TreeStoreElem **elems; - /* Index of last used #TreeStoreElem item, to speed up search for another one. */ - int lastused; - /* Counter used to reduce the amount of 'rests' of `lastused` index, otherwise search for unused - * item is exponential and becomes critically slow when there are a lot of items in the group. */ - int lastused_reset_count; - /* Number of items currently in use. */ - int size; - /* Number of items currently allocated. */ - int allocated; -} TseGroup; - -/* Only allow reset of #TseGroup.lastused counter to 0 once every 1k search. */ -#define TSEGROUP_LASTUSED_RESET_VALUE 10000 - -/* Allocate structure for TreeStoreElements; - * Most of elements in treestore have no duplicates, - * so there is no need to preallocate memory for more than one pointer */ -static TseGroup *tse_group_create(void) -{ - TseGroup *tse_group = MEM_mallocN(sizeof(TseGroup), "TseGroup"); - tse_group->elems = MEM_mallocN(sizeof(TreeStoreElem *), "TseGroupElems"); - tse_group->size = 0; - tse_group->allocated = 1; - tse_group->lastused = 0; - return tse_group; -} - -static void tse_group_add_element(TseGroup *tse_group, TreeStoreElem *elem) -{ - if (UNLIKELY(tse_group->size == tse_group->allocated)) { - tse_group->allocated *= 2; - tse_group->elems = MEM_reallocN(tse_group->elems, - sizeof(TreeStoreElem *) * tse_group->allocated); - } - tse_group->elems[tse_group->size] = elem; - tse_group->lastused = tse_group->size; - tse_group->size++; -} - -static void tse_group_remove_element(TseGroup *tse_group, TreeStoreElem *elem) -{ - int min_allocated = MAX2(1, tse_group->allocated / 2); - BLI_assert(tse_group->allocated == 1 || (tse_group->allocated % 2) == 0); - - tse_group->size--; - BLI_assert(tse_group->size >= 0); - for (int i = 0; i < tse_group->size; i++) { - if (tse_group->elems[i] == elem) { - memcpy(tse_group->elems[i], - tse_group->elems[i + 1], - (tse_group->size - (i + 1)) * sizeof(TreeStoreElem *)); - break; - } - } - - if (UNLIKELY(tse_group->size > 0 && tse_group->size <= min_allocated)) { - tse_group->allocated = min_allocated; - tse_group->elems = MEM_reallocN(tse_group->elems, - sizeof(TreeStoreElem *) * tse_group->allocated); - } -} - -static void tse_group_free(TseGroup *tse_group) -{ - MEM_freeN(tse_group->elems); - MEM_freeN(tse_group); -} - -static unsigned int tse_hash(const void *ptr) -{ - const TreeStoreElem *tse = ptr; - union { - short h_pair[2]; - unsigned int u_int; - } hash; - - BLI_assert((tse->type != TSE_SOME_ID) || !tse->nr); - - hash.h_pair[0] = tse->type; - hash.h_pair[1] = tse->nr; - - hash.u_int ^= BLI_ghashutil_ptrhash(tse->id); - - return hash.u_int; -} - -static bool tse_cmp(const void *a, const void *b) -{ - const TreeStoreElem *tse_a = a; - const TreeStoreElem *tse_b = b; - return tse_a->type != tse_b->type || tse_a->nr != tse_b->nr || tse_a->id != tse_b->id; -} - -static void fill_treehash(void *treehash, BLI_mempool *treestore) -{ - TreeStoreElem *tselem; - BLI_mempool_iter iter; - BLI_mempool_iternew(treestore, &iter); - - BLI_assert(treehash); - - while ((tselem = BLI_mempool_iterstep(&iter))) { - BKE_outliner_treehash_add_element(treehash, tselem); - } -} - -void *BKE_outliner_treehash_create_from_treestore(BLI_mempool *treestore) -{ - GHash *treehash = BLI_ghash_new_ex(tse_hash, tse_cmp, "treehash", BLI_mempool_len(treestore)); - fill_treehash(treehash, treestore); - return treehash; -} - -static void free_treehash_group(void *key) -{ - tse_group_free(key); -} - -void BKE_outliner_treehash_clear_used(void *treehash) -{ - GHashIterator gh_iter; - - GHASH_ITER (gh_iter, treehash) { - TseGroup *group = BLI_ghashIterator_getValue(&gh_iter); - group->lastused = 0; - group->lastused_reset_count = 0; - } -} - -void *BKE_outliner_treehash_rebuild_from_treestore(void *treehash, BLI_mempool *treestore) -{ - BLI_assert(treehash); - - BLI_ghash_clear_ex(treehash, NULL, free_treehash_group, BLI_mempool_len(treestore)); - fill_treehash(treehash, treestore); - return treehash; -} - -void BKE_outliner_treehash_add_element(void *treehash, TreeStoreElem *elem) -{ - TseGroup *group; - void **val_p; - - if (!BLI_ghash_ensure_p(treehash, elem, &val_p)) { - *val_p = tse_group_create(); - } - group = *val_p; - tse_group_add_element(group, elem); -} - -void BKE_outliner_treehash_remove_element(void *treehash, TreeStoreElem *elem) -{ - TseGroup *group = BLI_ghash_lookup(treehash, elem); - - BLI_assert(group != NULL); - if (group->size <= 1) { - /* one element -> remove group completely */ - BLI_ghash_remove(treehash, elem, NULL, free_treehash_group); - } - else { - tse_group_remove_element(group, elem); - } -} - -static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short nr, struct ID *id) -{ - TreeStoreElem tse_template; - tse_template.type = type; - tse_template.nr = (type == TSE_SOME_ID) ? 0 : nr; /* we're picky! :) */ - tse_template.id = id; - - BLI_assert(th); - - return BLI_ghash_lookup(th, &tse_template); -} - -TreeStoreElem *BKE_outliner_treehash_lookup_unused(void *treehash, - short type, - short nr, - struct ID *id) -{ - TseGroup *group; - - BLI_assert(treehash); - - group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); - if (group) { - /* Find unused element, with optimization to start from previously - * found element assuming we do repeated lookups. */ - int size = group->size; - int offset = group->lastused; - - for (int i = 0; i < size; i++, offset++) { - /* Once at the end of the array of items, in most cases it just means that all items are - * used, so only check the whole array once every TSEGROUP_LASTUSED_RESET_VALUE times. */ - if (offset >= size) { - if (LIKELY(group->lastused_reset_count <= TSEGROUP_LASTUSED_RESET_VALUE)) { - group->lastused_reset_count++; - group->lastused = group->size - 1; - break; - } - group->lastused_reset_count = 0; - offset = 0; - } - - if (!group->elems[offset]->used) { - group->lastused = offset; - return group->elems[offset]; - } - } - } - return NULL; -} - -TreeStoreElem *BKE_outliner_treehash_lookup_any(void *treehash, - short type, - short nr, - struct ID *id) -{ - TseGroup *group; - - BLI_assert(treehash); - - group = BKE_outliner_treehash_lookup_group(treehash, type, nr, id); - return group ? group->elems[0] : NULL; -} - -void BKE_outliner_treehash_free(void *treehash) -{ - BLI_assert(treehash); - - BLI_ghash_free(treehash, NULL, free_treehash_group); -} diff --git a/source/blender/blenkernel/intern/outliner_treehash.cc b/source/blender/blenkernel/intern/outliner_treehash.cc new file mode 100644 index 00000000000..3f66f6bb745 --- /dev/null +++ b/source/blender/blenkernel/intern/outliner_treehash.cc @@ -0,0 +1,209 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bke + * + * Tree hash for the outliner space. + */ + +#include <stdlib.h> +#include <string.h> + +#include "BLI_mempool.h" +#include "BLI_utildefines.h" +#include "BLI_vector.hh" + +#include "DNA_outliner_types.h" + +#include "BKE_outliner_treehash.hh" + +#include "MEM_guardedalloc.h" + +namespace blender::bke::outliner::treehash { + +/* -------------------------------------------------------------------- */ +/** \name #TseGroup + * \{ */ + +class TseGroup { + public: + blender::Vector<TreeStoreElem *> elems; + /* Index of last used #TreeStoreElem item, to speed up search for another one. */ + int lastused = 0; + /* Counter used to reduce the amount of 'rests' of `lastused` index, otherwise search for unused + * item is exponential and becomes critically slow when there are a lot of items in the group. */ + int lastused_reset_count = -1; + + public: + void add_element(TreeStoreElem &elem); + void remove_element(TreeStoreElem &elem); +}; + +/* Only allow reset of #TseGroup.lastused counter to 0 once every 1k search. */ +#define TSEGROUP_LASTUSED_RESET_VALUE 10000 + +void TseGroup::add_element(TreeStoreElem &elem) +{ + const int64_t idx = elems.append_and_get_index(&elem); + lastused = idx; +} + +void TseGroup::remove_element(TreeStoreElem &elem) +{ + const int64_t idx = elems.first_index_of(&elem); + elems.remove(idx); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #TreeStoreElemKey + * \{ */ + +TreeStoreElemKey::TreeStoreElemKey(const TreeStoreElem &elem) + : id(elem.id), type(elem.type), nr(elem.nr) +{ +} + +TreeStoreElemKey::TreeStoreElemKey(ID *id, short type, short nr) : id(id), type(type), nr(nr) +{ +} + +uint64_t TreeStoreElemKey::hash() const +{ + return get_default_hash_3(id, type, nr); +} + +bool operator==(const TreeStoreElemKey &a, const TreeStoreElemKey &b) +{ + return (a.id == b.id) && (a.type == b.type) && (a.nr == b.nr); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #TreeHash + * \{ */ + +TreeHash::~TreeHash() = default; + +std::unique_ptr<TreeHash> TreeHash::create_from_treestore(BLI_mempool &treestore) +{ + /* Can't use `make_unique()` here because of private constructor. */ + std::unique_ptr<TreeHash> tree_hash{new TreeHash()}; + tree_hash->fill_treehash(treestore); + + return tree_hash; +} + +void TreeHash::fill_treehash(BLI_mempool &treestore) +{ + TreeStoreElem *tselem; + BLI_mempool_iter iter; + BLI_mempool_iternew(&treestore, &iter); + + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + add_element(*tselem); + } +} + +void TreeHash::clear_used() +{ + for (auto &group : elem_groups_.values()) { + group->lastused = 0; + group->lastused_reset_count = 0; + } +} + +void TreeHash::rebuild_from_treestore(BLI_mempool &treestore) +{ + elem_groups_.clear(); + fill_treehash(treestore); +} + +void TreeHash::add_element(TreeStoreElem &elem) +{ + std::unique_ptr<TseGroup> &group = elem_groups_.lookup_or_add_cb( + TreeStoreElemKey(elem), []() { return std::make_unique<TseGroup>(); }); + group->add_element(elem); +} + +void TreeHash::remove_element(TreeStoreElem &elem) +{ + TseGroup *group = lookup_group(elem); + BLI_assert(group != nullptr); + + if (group->elems.size() <= 1) { + /* One element -> remove group completely. */ + elem_groups_.remove(TreeStoreElemKey(elem)); + } + else { + group->remove_element(elem); + } +} + +TseGroup *TreeHash::lookup_group(const TreeStoreElemKey &key) const +{ + auto *group = elem_groups_.lookup_ptr(key); + if (group) { + return group->get(); + } + return nullptr; +} + +TseGroup *TreeHash::lookup_group(const TreeStoreElem &key_elem) const +{ + return lookup_group(TreeStoreElemKey(key_elem)); +} + +TseGroup *TreeHash::lookup_group(const short type, const short nr, ID *id) const +{ + TreeStoreElemKey key(id, type, nr); + if (type == TSE_SOME_ID) { + key.nr = 0; /* we're picky! :) */ + } + return lookup_group(key); +} + +TreeStoreElem *TreeHash::lookup_unused(const short type, const short nr, ID *id) const +{ + TseGroup *group = lookup_group(type, nr, id); + if (!group) { + return nullptr; + } + + /* Find unused element, with optimization to start from previously + * found element assuming we do repeated lookups. */ + const int size = group->elems.size(); + int offset = group->lastused; + + for (int i = 0; i < size; i++, offset++) { + /* Once at the end of the array of items, in most cases it just means that all items are + * used, so only check the whole array once every TSEGROUP_LASTUSED_RESET_VALUE times. */ + if (offset >= size) { + if (LIKELY(group->lastused_reset_count <= TSEGROUP_LASTUSED_RESET_VALUE)) { + group->lastused_reset_count++; + group->lastused = group->elems.size() - 1; + break; + } + group->lastused_reset_count = 0; + offset = 0; + } + + if (!group->elems[offset]->used) { + group->lastused = offset; + return group->elems[offset]; + } + } + return nullptr; +} + +TreeStoreElem *TreeHash::lookup_any(const short type, const short nr, ID *id) const +{ + const TseGroup *group = lookup_group(type, nr, id); + return group ? group->elems[0] : nullptr; +} + +/** \} */ + +} // namespace blender::bke::outliner::treehash diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.cc index 9b0d15ac702..4c3da5eabc4 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.cc @@ -5,8 +5,8 @@ * \ingroup bke */ -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -30,6 +30,7 @@ #include "BLT_translation.h" #include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_brush.h" #include "BKE_ccg.h" #include "BKE_colortools.h" @@ -95,13 +96,10 @@ static void palette_blend_write(BlendWriter *writer, ID *id, const void *id_addr { Palette *palette = (Palette *)id; - PaletteColor *color; BLO_write_id_struct(writer, Palette, id_address, &palette->id); BKE_id_blend_write(writer, &palette->id); - for (color = palette->colors.first; color; color = color->next) { - BLO_write_struct(writer, PaletteColor, color); - } + BLO_write_struct_list(writer, PaletteColor, &palette->colors); } static void palette_blend_read_data(BlendDataReader *reader, ID *id) @@ -116,38 +114,38 @@ static void palette_undo_preserve(BlendLibReader *UNUSED(reader), ID *id_new, ID /* NOTE: We do not care about potential internal references to self here, Palette has none. */ /* NOTE: We do not swap IDProperties, as dealing with potential ID pointers in those would be * fairly delicate. */ - BKE_lib_id_swap(NULL, id_new, id_old); + BKE_lib_id_swap(nullptr, id_new, id_old); SWAP(IDProperty *, id_new->properties, id_old->properties); } IDTypeInfo IDType_ID_PAL = { - .id_code = ID_PAL, - .id_filter = FILTER_ID_PAL, - .main_listbase_index = INDEX_ID_PAL, - .struct_size = sizeof(Palette), - .name = "Palette", - .name_plural = "palettes", - .translation_context = BLT_I18NCONTEXT_ID_PALETTE, - .flags = IDTYPE_FLAGS_NO_ANIMDATA, - .asset_type_info = NULL, - - .init_data = palette_init_data, - .copy_data = palette_copy_data, - .free_data = palette_free_data, - .make_local = NULL, - .foreach_id = NULL, - .foreach_cache = NULL, - .foreach_path = NULL, - .owner_get = NULL, - - .blend_write = palette_blend_write, - .blend_read_data = palette_blend_read_data, - .blend_read_lib = NULL, - .blend_read_expand = NULL, - - .blend_read_undo_preserve = palette_undo_preserve, - - .lib_override_apply_post = NULL, + /* id_code */ ID_PAL, + /* id_filter */ FILTER_ID_PAL, + /* main_listbase_index */ INDEX_ID_PAL, + /* struct_size */ sizeof(Palette), + /* name */ "Palette", + /* name_plural */ "palettes", + /* translation_context */ BLT_I18NCONTEXT_ID_PALETTE, + /* flags */ IDTYPE_FLAGS_NO_ANIMDATA, + /* asset_type_info */ nullptr, + + /* init_data */ palette_init_data, + /* copy_data */ palette_copy_data, + /* free_data */ palette_free_data, + /* make_local */ nullptr, + /* foreach_id */ nullptr, + /* foreach_cache */ nullptr, + /* foreach_path */ nullptr, + /* owner_get */ nullptr, + + /* blend_write */ palette_blend_write, + /* blend_read_data */ palette_blend_read_data, + /* blend_read_lib */ nullptr, + /* blend_read_expand */ nullptr, + + /* blend_read_undo_preserve */ palette_undo_preserve, + + /* lib_override_apply_post */ nullptr, }; static void paint_curve_copy_data(Main *UNUSED(bmain), @@ -159,7 +157,8 @@ static void paint_curve_copy_data(Main *UNUSED(bmain), const PaintCurve *paint_curve_src = (const PaintCurve *)id_src; if (paint_curve_src->tot_points != 0) { - paint_curve_dst->points = MEM_dupallocN(paint_curve_src->points); + paint_curve_dst->points = static_cast<PaintCurvePoint *>( + MEM_dupallocN(paint_curve_src->points)); } } @@ -188,41 +187,41 @@ static void paint_curve_blend_read_data(BlendDataReader *reader, ID *id) } IDTypeInfo IDType_ID_PC = { - .id_code = ID_PC, - .id_filter = FILTER_ID_PC, - .main_listbase_index = INDEX_ID_PC, - .struct_size = sizeof(PaintCurve), - .name = "PaintCurve", - .name_plural = "paint_curves", - .translation_context = BLT_I18NCONTEXT_ID_PAINTCURVE, - .flags = IDTYPE_FLAGS_NO_ANIMDATA, - .asset_type_info = NULL, - - .init_data = NULL, - .copy_data = paint_curve_copy_data, - .free_data = paint_curve_free_data, - .make_local = NULL, - .foreach_id = NULL, - .foreach_cache = NULL, - .foreach_path = NULL, - .owner_get = NULL, - - .blend_write = paint_curve_blend_write, - .blend_read_data = paint_curve_blend_read_data, - .blend_read_lib = NULL, - .blend_read_expand = NULL, - - .blend_read_undo_preserve = NULL, - - .lib_override_apply_post = NULL, + /* id_code */ ID_PC, + /* id_filter */ FILTER_ID_PC, + /* main_listbase_index */ INDEX_ID_PC, + /* struct_size */ sizeof(PaintCurve), + /* name */ "PaintCurve", + /* name_plural */ "paint_curves", + /* translation_context */ BLT_I18NCONTEXT_ID_PAINTCURVE, + /* flags */ IDTYPE_FLAGS_NO_ANIMDATA, + /* asset_type_info */ nullptr, + + /* init_data */ nullptr, + /* copy_data */ paint_curve_copy_data, + /* free_data */ paint_curve_free_data, + /* make_local */ nullptr, + /* foreach_id */ nullptr, + /* foreach_cache */ nullptr, + /* foreach_path */ nullptr, + /* owner_get */ nullptr, + + /* blend_write */ paint_curve_blend_write, + /* blend_read_data */ paint_curve_blend_read_data, + /* blend_read_lib */ nullptr, + /* blend_read_expand */ nullptr, + + /* blend_read_undo_preserve */ nullptr, + + /* lib_override_apply_post */ nullptr, }; -const char PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; -const char PAINT_CURSOR_VERTEX_PAINT[3] = {255, 255, 255}; -const char PAINT_CURSOR_WEIGHT_PAINT[3] = {200, 200, 255}; -const char PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255}; +const uchar PAINT_CURSOR_SCULPT[3] = {255, 100, 100}; +const uchar PAINT_CURSOR_VERTEX_PAINT[3] = {255, 255, 255}; +const uchar PAINT_CURSOR_WEIGHT_PAINT[3] = {200, 200, 255}; +const uchar PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255}; -static ePaintOverlayControlFlags overlay_flags = 0; +static ePaintOverlayControlFlags overlay_flags = (ePaintOverlayControlFlags)0; void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const Tex *tex) { @@ -247,7 +246,7 @@ void BKE_paint_invalidate_overlay_tex(Scene *scene, ViewLayer *view_layer, const void BKE_paint_invalidate_cursor_overlay(Scene *scene, ViewLayer *view_layer, CurveMapping *curve) { Paint *p = BKE_paint_get_active(scene, view_layer); - if (p == NULL) { + if (p == nullptr) { return; } @@ -294,10 +293,10 @@ void BKE_paint_reset_overlay_invalid(ePaintOverlayControlFlags flag) bool BKE_paint_ensure_from_paintmode(Scene *sce, ePaintMode mode) { ToolSettings *ts = sce->toolsettings; - Paint **paint_ptr = NULL; + Paint **paint_ptr = nullptr; /* Some paint modes don't store paint settings as pointer, for these this can be set and * referenced by paint_ptr. */ - Paint *paint_tmp = NULL; + Paint *paint_tmp = nullptr; switch (mode) { case PAINT_MODE_SCULPT: @@ -370,13 +369,13 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, ePaintMode mode) case PAINT_MODE_SCULPT_CURVES: return &ts->curves_sculpt->paint; case PAINT_MODE_INVALID: - return NULL; + return nullptr; default: return &ts->imapaint.paint; } } - return NULL; + return nullptr; } const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode) @@ -406,7 +405,7 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(ePaintMode mode) case PAINT_MODE_INVALID: break; } - return NULL; + return nullptr; } const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode) @@ -438,7 +437,7 @@ const char *BKE_paint_get_tool_prop_id_from_paintmode(ePaintMode mode) } /* Invalid paint mode. */ - return NULL; + return nullptr; } Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) @@ -467,7 +466,7 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) case OB_MODE_SCULPT_CURVES: return &ts->curves_sculpt->paint; case OB_MODE_EDIT: - return ts->uvsculpt ? &ts->uvsculpt->paint : NULL; + return ts->uvsculpt ? &ts->uvsculpt->paint : nullptr; default: break; } @@ -477,7 +476,7 @@ Paint *BKE_paint_get_active(Scene *sce, ViewLayer *view_layer) return &ts->imapaint.paint; } - return NULL; + return nullptr; } Paint *BKE_paint_get_active_from_context(const bContext *C) @@ -488,13 +487,13 @@ Paint *BKE_paint_get_active_from_context(const bContext *C) if (sce && view_layer) { ToolSettings *ts = sce->toolsettings; - Object *obact = NULL; + Object *obact = nullptr; if (view_layer->basact && view_layer->basact->object) { obact = view_layer->basact->object; } - if ((sima = CTX_wm_space_image(C)) != NULL) { + if ((sima = CTX_wm_space_image(C)) != nullptr) { if (obact && obact->mode == OB_MODE_EDIT) { if (sima->mode == SI_MODE_PAINT) { return &ts->imapaint.paint; @@ -512,7 +511,7 @@ Paint *BKE_paint_get_active_from_context(const bContext *C) } } - return NULL; + return nullptr; } ePaintMode BKE_paintmode_get_active_from_context(const bContext *C) @@ -522,13 +521,13 @@ ePaintMode BKE_paintmode_get_active_from_context(const bContext *C) SpaceImage *sima; if (sce && view_layer) { - Object *obact = NULL; + Object *obact = nullptr; if (view_layer->basact && view_layer->basact->object) { obact = view_layer->basact->object; } - if ((sima = CTX_wm_space_image(C)) != NULL) { + if ((sima = CTX_wm_space_image(C)) != nullptr) { if (obact && obact->mode == OB_MODE_EDIT) { if (sima->mode == SI_MODE_PAINT) { return PAINT_MODE_TEXTURE_2D; @@ -568,7 +567,7 @@ ePaintMode BKE_paintmode_get_active_from_context(const bContext *C) return PAINT_MODE_INVALID; } -ePaintMode BKE_paintmode_get_from_tool(const struct bToolRef *tref) +ePaintMode BKE_paintmode_get_from_tool(const bToolRef *tref) { if (tref->space_type == SPACE_VIEW3D) { switch (tref->mode) { @@ -611,7 +610,7 @@ Brush *BKE_paint_brush(Paint *p) const Brush *BKE_paint_brush_for_read(const Paint *p) { - return p ? p->brush : NULL; + return p ? p->brush : nullptr; } void BKE_paint_brush_set(Paint *p, Brush *br) @@ -704,16 +703,13 @@ uint BKE_paint_get_brush_tool_offset_from_paintmode(const ePaintMode mode) PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) { - PaintCurve *pc; - - pc = BKE_id_new(bmain, ID_PC, name); - + PaintCurve *pc = static_cast<PaintCurve *>(BKE_id_new(bmain, ID_PC, name)); return pc; } Palette *BKE_paint_palette(Paint *p) { - return p ? p->palette : NULL; + return p ? p->palette : nullptr; } void BKE_paint_palette_set(Paint *p, Palette *palette) @@ -763,18 +759,18 @@ void BKE_palette_clear(Palette *palette) Palette *BKE_palette_add(Main *bmain, const char *name) { - Palette *palette = BKE_id_new(bmain, ID_PAL, name); + Palette *palette = static_cast<Palette *>(BKE_id_new(bmain, ID_PAL, name)); return palette; } PaletteColor *BKE_palette_color_add(Palette *palette) { - PaletteColor *color = MEM_callocN(sizeof(*color), "Palette Color"); + PaletteColor *color = MEM_cnew<PaletteColor>(__func__); BLI_addtail(&palette->colors, color); return color; } -bool BKE_palette_is_empty(const struct Palette *palette) +bool BKE_palette_is_empty(const Palette *palette) { return BLI_listbase_is_empty(&palette->colors); } @@ -782,7 +778,8 @@ bool BKE_palette_is_empty(const struct Palette *palette) /* helper function to sort using qsort */ static int palettecolor_compare_hsv(const void *a1, const void *a2) { - const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + const tPaletteColorHSV *ps1 = static_cast<const tPaletteColorHSV *>(a1); + const tPaletteColorHSV *ps2 = static_cast<const tPaletteColorHSV *>(a2); /* Hue */ if (ps1->h > ps2->h) { @@ -814,7 +811,8 @@ static int palettecolor_compare_hsv(const void *a1, const void *a2) /* helper function to sort using qsort */ static int palettecolor_compare_svh(const void *a1, const void *a2) { - const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + const tPaletteColorHSV *ps1 = static_cast<const tPaletteColorHSV *>(a1); + const tPaletteColorHSV *ps2 = static_cast<const tPaletteColorHSV *>(a2); /* Saturation. */ if (ps1->s > ps2->s) { @@ -845,7 +843,8 @@ static int palettecolor_compare_svh(const void *a1, const void *a2) static int palettecolor_compare_vhs(const void *a1, const void *a2) { - const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + const tPaletteColorHSV *ps1 = static_cast<const tPaletteColorHSV *>(a1); + const tPaletteColorHSV *ps2 = static_cast<const tPaletteColorHSV *>(a2); /* Value. */ if (1.0f - ps1->v > 1.0f - ps2->v) { @@ -876,7 +875,8 @@ static int palettecolor_compare_vhs(const void *a1, const void *a2) static int palettecolor_compare_luminance(const void *a1, const void *a2) { - const tPaletteColorHSV *ps1 = a1, *ps2 = a2; + const tPaletteColorHSV *ps1 = static_cast<const tPaletteColorHSV *>(a1); + const tPaletteColorHSV *ps2 = static_cast<const tPaletteColorHSV *>(a2); float lumi1 = (ps1->rgb[0] + ps1->rgb[1] + ps1->rgb[2]) / 3.0f; float lumi2 = (ps2->rgb[0] + ps2->rgb[1] + ps2->rgb[2]) / 3.0f; @@ -917,14 +917,15 @@ void BKE_palette_sort_luminance(tPaletteColorHSV *color_array, const int totcol) bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, const bool linear) { - tPaletteColorHSV *color_array = NULL; - tPaletteColorHSV *col_elm = NULL; + tPaletteColorHSV *color_array = nullptr; + tPaletteColorHSV *col_elm = nullptr; bool done = false; const int totpal = BLI_ghash_len(color_table); if (totpal > 0) { - color_array = MEM_calloc_arrayN(totpal, sizeof(tPaletteColorHSV), __func__); + color_array = static_cast<tPaletteColorHSV *>( + MEM_calloc_arrayN(totpal, sizeof(tPaletteColorHSV), __func__)); /* Put all colors in an array. */ GHashIterator gh_iter; int t = 0; @@ -979,14 +980,14 @@ bool BKE_palette_from_hash(Main *bmain, GHash *color_table, const char *name, co bool BKE_paint_select_face_test(Object *ob) { - return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) && + return ((ob != nullptr) && (ob->type == OB_MESH) && (ob->data != nullptr) && (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))); } bool BKE_paint_select_vert_test(Object *ob) { - return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) && + return ((ob != nullptr) && (ob->type == OB_MESH) && (ob->data != nullptr) && (((Mesh *)ob->data)->editflag & ME_EDIT_PAINT_VERT_SEL) && (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT)); } @@ -998,14 +999,14 @@ bool BKE_paint_select_elem_test(Object *ob) bool BKE_paint_always_hide_test(Object *ob) { - return ((ob != NULL) && (ob->type == OB_MESH) && (ob->data != NULL) && + return ((ob != nullptr) && (ob->type == OB_MESH) && (ob->data != nullptr) && (ob->mode & OB_MODE_WEIGHT_PAINT || ob->mode & OB_MODE_VERTEX_PAINT)); } void BKE_paint_cavity_curve_preset(Paint *p, int preset) { - CurveMapping *cumap = NULL; - CurveMap *cuma = NULL; + CurveMapping *cumap = nullptr; + CurveMap *cuma = nullptr; if (!p->cavity_curve) { p->cavity_curve = BKE_curvemapping_add(1, 0, 0, 1, 1); @@ -1035,13 +1036,13 @@ eObjectMode BKE_paint_object_mode_from_paintmode(ePaintMode mode) return OB_MODE_EDIT; case PAINT_MODE_INVALID: default: - return 0; + return OB_MODE_OBJECT; } } -bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) +bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint) { - Paint *paint = NULL; + Paint *paint = nullptr; if (*r_paint) { /* Tool offset should never be 0 for initialized paint settings, so it's a reliable way to * check if already initialized. */ @@ -1053,7 +1054,7 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) } else { BLI_assert(ELEM(*r_paint, - /* Cast is annoying, but prevent NULL-pointer access. */ + /* Cast is annoying, but prevent nullptr-pointer access. */ (Paint *)ts->gp_paint, (Paint *)ts->gp_vertexpaint, (Paint *)ts->gp_sculptpaint, @@ -1065,7 +1066,7 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) (Paint *)ts->curves_sculpt, (Paint *)&ts->imapaint)); #ifdef DEBUG - struct Paint paint_test = **r_paint; + Paint paint_test = **r_paint; BKE_paint_runtime_init(ts, *r_paint); /* Swap so debug doesn't hide errors when release fails. */ SWAP(Paint, **r_paint, paint_test); @@ -1077,11 +1078,11 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) } if (((VPaint **)r_paint == &ts->vpaint) || ((VPaint **)r_paint == &ts->wpaint)) { - VPaint *data = MEM_callocN(sizeof(*data), __func__); + VPaint *data = MEM_cnew<VPaint>(__func__); paint = &data->paint; } else if ((Sculpt **)r_paint == &ts->sculpt) { - Sculpt *data = MEM_callocN(sizeof(*data), __func__); + Sculpt *data = MEM_cnew<Sculpt>(__func__); paint = &data->paint; /* Turn on X plane mirror symmetry by default */ @@ -1091,27 +1092,27 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE; } else if ((GpPaint **)r_paint == &ts->gp_paint) { - GpPaint *data = MEM_callocN(sizeof(*data), __func__); + GpPaint *data = MEM_cnew<GpPaint>(__func__); paint = &data->paint; } else if ((GpVertexPaint **)r_paint == &ts->gp_vertexpaint) { - GpVertexPaint *data = MEM_callocN(sizeof(*data), __func__); + GpVertexPaint *data = MEM_cnew<GpVertexPaint>(__func__); paint = &data->paint; } else if ((GpSculptPaint **)r_paint == &ts->gp_sculptpaint) { - GpSculptPaint *data = MEM_callocN(sizeof(*data), __func__); + GpSculptPaint *data = MEM_cnew<GpSculptPaint>(__func__); paint = &data->paint; } else if ((GpWeightPaint **)r_paint == &ts->gp_weightpaint) { - GpWeightPaint *data = MEM_callocN(sizeof(*data), __func__); + GpWeightPaint *data = MEM_cnew<GpWeightPaint>(__func__); paint = &data->paint; } else if ((UvSculpt **)r_paint == &ts->uvsculpt) { - UvSculpt *data = MEM_callocN(sizeof(*data), __func__); + UvSculpt *data = MEM_cnew<UvSculpt>(__func__); paint = &data->paint; } else if ((CurvesSculpt **)r_paint == &ts->curves_sculpt) { - CurvesSculpt *data = MEM_callocN(sizeof(*data), __func__); + CurvesSculpt *data = MEM_cnew<CurvesSculpt>(__func__); paint = &data->paint; } else if (*r_paint == &ts->imapaint.paint) { @@ -1127,7 +1128,7 @@ bool BKE_paint_ensure(ToolSettings *ts, struct Paint **r_paint) return false; } -void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3]) +void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const uchar col[3]) { UnifiedPaintSettings *ups = &sce->toolsettings->unified_paint_settings; Paint *paint = BKE_paint_get_active_from_paintmode(sce, mode); @@ -1137,7 +1138,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3]) /* If there's no brush, create one */ if (PAINT_MODE_HAS_BRUSH(mode)) { Brush *brush = BKE_paint_brush(paint); - if (brush == NULL) { + if (brush == nullptr) { eObjectMode ob_mode = BKE_paint_object_mode_from_paintmode(mode); brush = BKE_brush_first_search(bmain, ob_mode); if (!brush) { @@ -1148,7 +1149,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const char col[3]) } } - memcpy(paint->paint_cursor_col, col, 3); + copy_v3_v3_uchar(paint->paint_cursor_col, col); paint->paint_cursor_col[3] = 128; ups->last_stroke_valid = false; zero_v3(ups->average_stroke_accum); @@ -1168,12 +1169,12 @@ void BKE_paint_copy(Paint *src, Paint *tar, const int flag) { tar->brush = src->brush; tar->cavity_curve = BKE_curvemapping_copy(src->cavity_curve); - tar->tool_slots = MEM_dupallocN(src->tool_slots); + tar->tool_slots = static_cast<PaintToolSlot *>(MEM_dupallocN(src->tool_slots)); if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus((ID *)tar->brush); id_us_plus((ID *)tar->palette); - if (src->tool_slots != NULL) { + if (src->tool_slots != nullptr) { for (int i = 0; i < tar->tool_slots_len; i++) { id_us_plus((ID *)tar->tool_slots[i].brush); } @@ -1221,7 +1222,7 @@ void BKE_paint_blend_read_data(BlendDataReader *reader, const Scene *scene, Pain const size_t expected_size = sizeof(PaintToolSlot) * p->tool_slots_len; if (p->tool_slots && MEM_allocN_len(p->tool_slots) < expected_size) { MEM_freeN(p->tool_slots); - p->tool_slots = MEM_callocN(expected_size, "PaintToolSlot"); + p->tool_slots = static_cast<PaintToolSlot *>(MEM_callocN(expected_size, "PaintToolSlot")); } BKE_paint_runtime_init(scene->toolsettings, p); @@ -1232,22 +1233,24 @@ void BKE_paint_blend_read_lib(BlendLibReader *reader, Scene *sce, Paint *p) if (p) { BLO_read_id_address(reader, sce->id.lib, &p->brush); for (int i = 0; i < p->tool_slots_len; i++) { - if (p->tool_slots[i].brush != NULL) { + if (p->tool_slots[i].brush != nullptr) { BLO_read_id_address(reader, sce->id.lib, &p->tool_slots[i].brush); } } BLO_read_id_address(reader, sce->id.lib, &p->palette); - p->paint_cursor = NULL; + p->paint_cursor = nullptr; BKE_paint_runtime_init(sce->toolsettings, p); } } -bool paint_is_face_hidden(const MLoopTri *lt, const MVert *mvert, const MLoop *mloop) +bool paint_is_face_hidden(const MLoopTri *lt, const bool *hide_vert, const MLoop *mloop) { - return ((mvert[mloop[lt->tri[0]].v].flag & ME_HIDE) || - (mvert[mloop[lt->tri[1]].v].flag & ME_HIDE) || - (mvert[mloop[lt->tri[2]].v].flag & ME_HIDE)); + if (!hide_vert) { + return false; + } + return ((hide_vert[mloop[lt->tri[0]].v]) || (hide_vert[mloop[lt->tri[1]].v]) || + (hide_vert[mloop[lt->tri[2]].v])); } bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int y) @@ -1346,9 +1349,9 @@ void BKE_sculptsession_free_deformMats(SculptSession *ss) MEM_SAFE_FREE(ss->deform_imats); } -void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss) +void BKE_sculptsession_free_vwpaint_data(SculptSession *ss) { - struct SculptVertexPaintGeomMap *gmap = NULL; + SculptVertexPaintGeomMap *gmap = nullptr; if (ss->mode_type == OB_MODE_VERTEX_PAINT) { gmap = &ss->mode.vpaint.gmap; } @@ -1359,7 +1362,7 @@ void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss) if (ss->mode.wpaint.dvert_prev) { BKE_defvert_array_free_elems(ss->mode.wpaint.dvert_prev, ss->totvert); MEM_freeN(ss->mode.wpaint.dvert_prev); - ss->mode.wpaint.dvert_prev = NULL; + ss->mode.wpaint.dvert_prev = nullptr; } } else { @@ -1388,12 +1391,9 @@ static void sculptsession_bm_to_me_update_data_only(Object *ob, bool reorder) if (reorder) { BM_log_mesh_elems_reorder(ss->bm, ss->bm_log); } - BM_mesh_bm_to_me(NULL, - ss->bm, - ob->data, - (&(struct BMeshToMeshParams){ - .calc_object_remap = false, - })); + BMeshToMeshParams params{}; + params.calc_object_remap = false; + BM_mesh_bm_to_me(nullptr, ss->bm, static_cast<Mesh *>(ob->data), ¶ms); } } } @@ -1419,7 +1419,7 @@ static void sculptsession_free_pbvh(Object *object) if (ss->pbvh) { BKE_pbvh_free(ss->pbvh); - ss->pbvh = NULL; + ss->pbvh = nullptr; } MEM_SAFE_FREE(ss->pmap); @@ -1433,10 +1433,10 @@ static void sculptsession_free_pbvh(Object *object) MEM_SAFE_FREE(ss->persistent_base); - MEM_SAFE_FREE(ss->preview_vert_index_list); - ss->preview_vert_index_count = 0; + MEM_SAFE_FREE(ss->preview_vert_list); + ss->preview_vert_count = 0; - MEM_SAFE_FREE(ss->preview_vert_index_list); + MEM_SAFE_FREE(ss->preview_vert_list); MEM_SAFE_FREE(ss->vertex_info.connected_component); MEM_SAFE_FREE(ss->vertex_info.boundary); @@ -1521,7 +1521,7 @@ void BKE_sculptsession_free(Object *ob) MEM_freeN(ss); - ob->sculpt = NULL; + ob->sculpt = nullptr; } } @@ -1533,18 +1533,18 @@ MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob) if (ob->sculpt && ob->sculpt->bm) { /* can't combine multires and dynamic topology */ - return NULL; + return nullptr; } if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) { /* multires can't work without displacement layer */ - return NULL; + return nullptr; } /* Weight paint operates on original vertices, and needs to treat multires as regular modifier * to make it so that PBVH vertices are at the multires surface. */ if ((ob->mode & OB_MODE_SCULPT) == 0) { - return NULL; + return nullptr; } for (md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); md; md = md->next) { @@ -1559,11 +1559,11 @@ MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob) return mmd; } - return NULL; + return nullptr; } } - return NULL; + return nullptr; } /* Checks if there are any supported deformation modifiers active */ @@ -1586,7 +1586,7 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) /* exception for shape keys because we can edit those */ for (; md; md = md->next) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type)); if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { continue; } @@ -1616,7 +1616,7 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob) */ static void sculpt_update_object(Depsgraph *depsgraph, Object *ob, - Mesh *me_eval, + Object *ob_eval, bool need_pmap, bool need_mask, bool is_paint_tool) @@ -1625,9 +1625,12 @@ static void sculpt_update_object(Depsgraph *depsgraph, Sculpt *sd = scene->toolsettings->sculpt; SculptSession *ss = ob->sculpt; const Mesh *me = BKE_object_get_original_mesh(ob); + Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0; + BLI_assert(me_eval != nullptr); + ss->depsgraph = depsgraph; ss->deform_modifiers_active = sculpt_modifiers_active(scene, sd, ob); @@ -1639,7 +1642,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->scene = scene; if (need_mask) { - if (mmd == NULL) { + if (mmd == nullptr) { BLI_assert(CustomData_has_layer(&me->vdata, CD_PAINT_MASK)); } else { @@ -1647,7 +1650,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, } } - ss->shapekey_active = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL; + ss->shapekey_active = (mmd == nullptr) ? BKE_keyblock_from_object(ob) : nullptr; /* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path, * so no extra checks is needed here. */ @@ -1673,40 +1676,40 @@ static void sculpt_update_object(Depsgraph *depsgraph, ss->mpoly = me->mpoly; ss->mloop = me->mloop; ss->multires.active = false; - ss->multires.modifier = NULL; + ss->multires.modifier = nullptr; ss->multires.level = 0; - ss->vmask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); + ss->vmask = static_cast<float *>(CustomData_get_layer(&me->vdata, CD_PAINT_MASK)); CustomDataLayer *layer; eAttrDomain domain; if (BKE_pbvh_get_color_layer(me, &layer, &domain)) { if (layer->type == CD_PROP_COLOR) { - ss->vcol = layer->data; + ss->vcol = static_cast<MPropCol *>(layer->data); } else { - ss->mcol = layer->data; + ss->mcol = static_cast<MLoopCol *>(layer->data); } ss->vcol_domain = domain; - ss->vcol_type = layer->type; + ss->vcol_type = static_cast<eCustomDataType>(layer->type); } else { - ss->vcol = NULL; - ss->mcol = NULL; + ss->vcol = nullptr; + ss->mcol = nullptr; - ss->vcol_type = -1; - ss->vcol_domain = ATTR_DOMAIN_NUM; + ss->vcol_type = (eCustomDataType)-1; + ss->vcol_domain = ATTR_DOMAIN_POINT; } } /* Sculpt Face Sets. */ if (use_face_sets) { BLI_assert(CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS)); - ss->face_sets = CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS); + ss->face_sets = static_cast<int *>(CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS)); } else { - ss->face_sets = NULL; + ss->face_sets = nullptr; } ss->subdiv_ccg = me_eval->runtime.subdiv_ccg; @@ -1733,14 +1736,33 @@ static void sculpt_update_object(Depsgraph *depsgraph, pbvh_show_face_sets_set(ss->pbvh, ss->show_face_sets); if (ss->deform_modifiers_active) { - if (!ss->orig_cos) { + /* Painting doesn't need crazyspace, use already evaluated mesh coordinates. */ + if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) { + Mesh *me_eval_deform = ob_eval->runtime.mesh_deform_eval; + + /* If the fully evaluated mesh has the same topology as the deform-only version, use it. + * This matters because 'deform eval' is very restrictive and excludes even modifiers that + * simply recompute vertex weights. */ + if (me_eval_deform->mpoly == me_eval->mpoly && me_eval_deform->mloop == me_eval->mloop && + me_eval_deform->totvert == me_eval->totvert) { + me_eval_deform = me_eval; + } + + BKE_sculptsession_free_deformMats(ss); + + BLI_assert(me_eval_deform->totvert == me->totvert); + + ss->deform_cos = BKE_mesh_vert_coords_alloc(me_eval_deform, NULL); + BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos, me->totvert); + } + else if (!ss->orig_cos) { int a; BKE_sculptsession_free_deformMats(ss); ss->orig_cos = (ss->shapekey_active) ? BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active) : - BKE_mesh_vert_coords_alloc(me, NULL); + BKE_mesh_vert_coords_alloc(me, nullptr); BKE_crazyspace_build_sculpt(depsgraph, scene, ob, &ss->deform_imats, &ss->deform_cos); BKE_pbvh_vert_coords_apply(ss->pbvh, ss->deform_cos, me->totvert); @@ -1754,14 +1776,14 @@ static void sculpt_update_object(Depsgraph *depsgraph, BKE_sculptsession_free_deformMats(ss); } - if (ss->shapekey_active != NULL && ss->deform_cos == NULL) { + if (ss->shapekey_active != nullptr && ss->deform_cos == nullptr) { ss->deform_cos = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); } /* if pbvh is deformed, key block is already applied to it */ if (ss->shapekey_active) { bool pbvh_deformed = BKE_pbvh_is_deformed(ss->pbvh); - if (!pbvh_deformed || ss->deform_cos == NULL) { + if (!pbvh_deformed || ss->deform_cos == nullptr) { float(*vertCos)[3] = BKE_keyblock_convert_to_vertcos(ob, ss->shapekey_active); if (vertCos) { @@ -1769,7 +1791,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, /* apply shape keys coordinates to PBVH */ BKE_pbvh_vert_coords_apply(ss->pbvh, vertCos, me->totvert); } - if (ss->deform_cos == NULL) { + if (ss->deform_cos == nullptr) { ss->deform_cos = vertCos; } if (vertCos != ss->deform_cos) { @@ -1788,7 +1810,7 @@ static void sculpt_update_object(Depsgraph *depsgraph, */ if (U.experimental.use_sculpt_texture_paint && ss->pbvh) { char *paint_canvas_key = BKE_paint_canvas_key_get(&scene->toolsettings->paint_mode, ob); - if (ss->last_paint_canvas_key == NULL || + if (ss->last_paint_canvas_key == nullptr || !STREQ(paint_canvas_key, ss->last_paint_canvas_key)) { MEM_SAFE_FREE(ss->last_paint_canvas_key); ss->last_paint_canvas_key = paint_canvas_key; @@ -1813,8 +1835,8 @@ static void sculpt_face_sets_ensure(Mesh *mesh) return; } - int *new_face_sets = CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, mesh->totpoly); + int *new_face_sets = static_cast<int *>(CustomData_add_layer( + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ @@ -1845,7 +1867,7 @@ void BKE_sculpt_update_object_before_eval(const Scene *scene, Object *ob_eval) PBVHNode **nodes; int n, totnode; - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + BKE_pbvh_search_gather(ss->pbvh, nullptr, nullptr, &nodes, &totnode); for (n = 0; n < totnode; n++) { BKE_pbvh_node_mark_update(nodes[n]); @@ -1871,13 +1893,11 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval) /* Update after mesh evaluation in the dependency graph, to rebuild PBVH or * other data when modifiers change the mesh. */ Object *ob_orig = DEG_get_original_object(ob_eval); - Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); - BLI_assert(me_eval != NULL); - sculpt_update_object(depsgraph, ob_orig, me_eval, false, false, false); + sculpt_update_object(depsgraph, ob_orig, ob_eval, false, false, false); } -void BKE_sculpt_color_layer_create_if_needed(struct Object *object) +void BKE_sculpt_color_layer_create_if_needed(Object *object) { Mesh *orig_me = BKE_object_get_original_mesh(object); @@ -1897,7 +1917,7 @@ void BKE_sculpt_color_layer_create_if_needed(struct Object *object) return; } - CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_DEFAULT, NULL, orig_me->totvert); + CustomData_add_layer(&orig_me->vdata, CD_PROP_COLOR, CD_CONSTRUCT, nullptr, orig_me->totvert); CustomDataLayer *layer = orig_me->vdata.layers + CustomData_get_layer_index(&orig_me->vdata, CD_PROP_COLOR); @@ -1917,19 +1937,17 @@ void BKE_sculpt_update_object_for_edit( BLI_assert(ob_orig == DEG_get_original_object(ob_orig)); Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig); - Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); - BLI_assert(me_eval != NULL); - sculpt_update_object(depsgraph, ob_orig, me_eval, need_pmap, need_mask, is_paint_tool); + sculpt_update_object(depsgraph, ob_orig, ob_eval, need_pmap, need_mask, is_paint_tool); } int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) { - const float *paint_mask; - Mesh *me = ob->data; + Mesh *me = static_cast<Mesh *>(ob->data); int ret = 0; - paint_mask = CustomData_get_layer(&me->vdata, CD_PAINT_MASK); + const float *paint_mask = static_cast<const float *>( + CustomData_get_layer(&me->vdata, CD_PAINT_MASK)); /* if multires is active, create a grid paint mask layer if there * isn't one already */ @@ -1940,13 +1958,15 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) int gridarea = gridsize * gridsize; int i, j; - gmask = CustomData_add_layer(&me->ldata, CD_GRID_PAINT_MASK, CD_CALLOC, NULL, me->totloop); + gmask = static_cast<GridPaintMask *>(CustomData_add_layer( + &me->ldata, CD_GRID_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totloop)); for (i = 0; i < me->totloop; i++) { GridPaintMask *gpm = &gmask[i]; gpm->level = level; - gpm->data = MEM_callocN(sizeof(float) * gridarea, "GridPaintMask.data"); + gpm->data = static_cast<float *>( + MEM_callocN(sizeof(float) * gridarea, "GridPaintMask.data")); } /* if vertices already have mask, copy into multires data */ @@ -1982,14 +2002,14 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd) /* create vertex paint mask layer if there isn't one already */ if (!paint_mask) { - CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_CALLOC, NULL, me->totvert); + CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totvert); ret |= SCULPT_MASK_LAYER_CALC_VERT; } return ret; } -void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene) +void BKE_sculpt_toolsettings_data_ensure(Scene *scene) { BKE_paint_ensure(scene->toolsettings, (Paint **)&scene->toolsettings->sculpt); @@ -2027,7 +2047,7 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc deformed |= object->sculpt->deform_modifiers_active; if (for_construction) { - deformed |= object->sculpt->shapekey_active != NULL; + deformed |= object->sculpt->shapekey_active != nullptr; } else { /* As in case with modifiers, we can't synchronize deformation made against @@ -2049,15 +2069,16 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) { /* Make everything visible. */ - int *current_face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + int *current_face_sets = static_cast<int *>( + CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); for (int i = 0; i < mesh->totpoly; i++) { current_face_sets[i] = abs(current_face_sets[i]); } } else { initialize_new_face_sets = true; - int *new_face_sets = CustomData_add_layer( - &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CALLOC, NULL, mesh->totpoly); + int *new_face_sets = static_cast<int *>(CustomData_add_layer( + &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)); /* Initialize the new Face Set data-layer with a default valid visible ID and set the default * color to render it white. */ @@ -2067,10 +2088,12 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) mesh->face_sets_color_default = face_sets_default_visible_id; } - int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + int *face_sets = static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); + const bool *hide_poly = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, ".hide_poly"); for (int i = 0; i < mesh->totpoly; i++) { - if (!(mesh->mpoly[i].flag & ME_HIDE)) { + if (!(hide_poly && hide_poly[i])) { continue; } @@ -2090,22 +2113,31 @@ void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh) void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh) { - const int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + using namespace blender::bke; + const int *face_sets = static_cast<const int *>( + CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); if (!face_sets) { return; } - for (int i = 0; i < mesh->totpoly; i++) { - const bool is_face_set_visible = face_sets[i] >= 0; - SET_FLAG_FROM_TEST(mesh->mpoly[i].flag, !is_face_set_visible, ME_HIDE); + MutableAttributeAccessor attributes = mesh_attributes_for_write(*mesh); + SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_poly", ATTR_DOMAIN_FACE); + if (!hide_poly) { + return; + } + for (const int i : hide_poly.span.index_range()) { + hide_poly.span[i] = face_sets[i] < 0; } + hide_poly.finish(); BKE_mesh_flush_hidden_from_polys(mesh); } void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg) { - const int *face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + const int *face_sets = static_cast<const int *>( + CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); if (!face_sets) { return; } @@ -2134,7 +2166,7 @@ void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv } } -void BKE_sculpt_sync_face_set_visibility(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg) +void BKE_sculpt_sync_face_set_visibility(Mesh *mesh, SubdivCCG *subdiv_ccg) { BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh); BKE_sculpt_sync_face_sets_visibility_to_base_mesh(mesh); @@ -2150,9 +2182,10 @@ void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object) /* Copy the current mesh visibility to the Face Sets. */ BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh); - if (object->sculpt != NULL) { + if (object->sculpt != nullptr) { /* If a sculpt session is active, ensure we have its face-set data properly up-to-date. */ - object->sculpt->face_sets = CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS); + object->sculpt->face_sets = static_cast<int *>( + CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)); /* NOTE: In theory we could add that on the fly when required by sculpt code. * But this then requires proper update of depsgraph etc. For now we play safe, optimization is @@ -2201,11 +2234,12 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool PBVH *pbvh = BKE_pbvh_new(); BKE_pbvh_respect_hide_set(pbvh, respect_hide); - MLoopTri *looptri = MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__); + MLoopTri *looptri = static_cast<MLoopTri *>( + MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__)); BKE_mesh_recalc_looptri(me->mloop, me->mpoly, me->mvert, me->totloop, me->totpoly, looptri); - BKE_sculpt_sync_face_set_visibility(me, NULL); + BKE_sculpt_sync_face_set_visibility(me, nullptr); BKE_pbvh_build_mesh(pbvh, me, @@ -2223,7 +2257,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool pbvh_show_face_sets_set(pbvh, ob->sculpt->show_face_sets); const bool is_deformed = check_sculpt_object_deformed(ob, true); - if (is_deformed && me_eval_deform != NULL) { + if (is_deformed && me_eval_deform != nullptr) { int totvert; float(*v_cos)[3] = BKE_mesh_vert_coords_alloc(me_eval_deform, &totvert); BKE_pbvh_vert_coords_apply(pbvh, v_cos, totvert); @@ -2257,21 +2291,21 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) { - if (ob == NULL || ob->sculpt == NULL) { - return NULL; + if (ob == nullptr || ob->sculpt == nullptr) { + return nullptr; } const bool respect_hide = true; PBVH *pbvh = ob->sculpt->pbvh; - if (pbvh != NULL) { + if (pbvh != nullptr) { /* NOTE: It is possible that grids were re-allocated due to modifier * stack. Need to update those pointers. */ if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); - Mesh *mesh_eval = object_eval->data; + Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data); SubdivCCG *subdiv_ccg = mesh_eval->runtime.subdiv_ccg; - if (subdiv_ccg != NULL) { + if (subdiv_ccg != nullptr) { BKE_sculpt_bvh_update_from_ccg(pbvh, subdiv_ccg); } } @@ -2282,14 +2316,14 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob) return pbvh; } - if (ob->sculpt->bm != NULL) { + if (ob->sculpt->bm != nullptr) { /* Sculpting on a BMesh (dynamic-topology) gets a special PBVH. */ pbvh = build_pbvh_for_dynamic_topology(ob); } else { Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); - Mesh *mesh_eval = object_eval->data; - if (mesh_eval->runtime.subdiv_ccg != NULL) { + Mesh *mesh_eval = static_cast<Mesh *>(object_eval->data); + if (mesh_eval->runtime.subdiv_ccg != nullptr) { pbvh = build_pbvh_from_ccg(ob, mesh_eval->runtime.subdiv_ccg, respect_hide); } else if (ob->type == OB_MESH) { @@ -2316,7 +2350,7 @@ void BKE_sculpt_bvh_update_from_ccg(PBVH *pbvh, SubdivCCG *subdiv_ccg) bool BKE_sculptsession_use_pbvh_draw(const Object *ob, const View3D *UNUSED(v3d)) { SculptSession *ss = ob->sculpt; - if (ss == NULL || ss->pbvh == NULL || ss->mode_type != OB_MODE_SCULPT) { + if (ss == nullptr || ss->pbvh == nullptr || ss->mode_type != OB_MODE_SCULPT) { return false; } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index c5344997733..9ccd6562649 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3494,7 +3494,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_re * initial tangent, but taking that in to account will allow * the possibility of flipping again. -jahka */ - mat3_to_quat_is_ok(cache[p]->rot, rotmat); + mat3_to_quat_legacy(cache[p]->rot, rotmat); } psys->totcached = totpart; @@ -3684,7 +3684,7 @@ static void psys_cache_edit_paths_iter(void *__restrict iter_data_v, * initial tangent, but taking that in to account will allow * the possibility of flipping again. -jahka */ - mat3_to_quat_is_ok(cache[iter]->rot, rotmat); + mat3_to_quat_legacy(cache[iter]->rot, rotmat); } } @@ -5413,8 +5413,8 @@ void BKE_particle_system_blend_read_lib(BlendLibReader *reader, BLO_read_id_address(reader, id->lib, &psys->target_ob); if (psys->clmd) { - /* XXX(campbell): from reading existing code this seems correct but intended usage of - * pointcache /w cloth should be added in 'ParticleSystem'. */ + /* XXX(@campbellbarton): from reading existing code this seems correct but intended usage + * of pointcache /w cloth should be added in 'ParticleSystem'. */ psys->clmd->point_cache = psys->pointcache; psys->clmd->ptcaches.first = psys->clmd->ptcaches.last = NULL; BLO_read_id_address(reader, id->lib, &psys->clmd->coll_parms->group); diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index 524ee31229b..a890812cfc4 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -158,10 +158,8 @@ static void do_kink_spiral(ParticleThreadContext *ctx, int start_index = 0, end_index = 0; float kink_base[3]; - if (ptex) { - kink_amp *= ptex->kink_amp; - kink_freq *= ptex->kink_freq; - } + kink_amp *= ptex->kink_amp; + kink_freq *= ptex->kink_freq; cut_time = (totkeys - 1) * ptex->length; zero_v3(spiral_start); @@ -405,7 +403,7 @@ void do_kink(ParticleKey *state, float obmat[4][4], int smooth_start) { - float kink[3] = {1.0f, 0.0f, 0.0f}, par_vec[3], q1[4] = {1.0f, 0.0f, 0.0f, 0.0f}; + float kink[3] = {1.0f, 0.0f, 0.0f}, par_vec[3]; float t, dt = 1.0f, result[3]; if (ELEM(type, PART_KINK_NO, PART_KINK_SPIRAL)) { @@ -455,6 +453,7 @@ void do_kink(ParticleKey *state, switch (type) { case PART_KINK_CURL: { float curl_offset[3]; + float q1[4] = {1.0f, 0.0f, 0.0f, 0.0f}; /* rotate kink vector around strand tangent */ mul_v3_v3fl(curl_offset, kink, amplitude); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 4a8f029beee..254cea0bd8b 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -837,7 +837,7 @@ void psys_get_birth_coords( cross_v3_v3v3(mat[1], mat[2], mat[0]); /* apply rotation */ - mat3_to_quat_is_ok(q, mat); + mat3_to_quat_legacy(q, mat); copy_qt_qt(state->rot, q); } else { @@ -969,7 +969,7 @@ void psys_get_birth_coords( float tmat[3][3]; /* NOTE: utan_local is not taken from 'utan', we calculate from rot_vec/vtan. */ - /* NOTE(campbell): it looks like rotation phase may be applied twice + /* NOTE(@campbellbarton): it looks like rotation phase may be applied twice * (once with vtan, again below) however this isn't the case. */ float *rot_vec_local = tmat[0]; float *vtan_local = tmat[1]; @@ -3322,7 +3322,7 @@ static void hair_create_input_mesh(ParticleSimulationData *sim, mesh = *r_mesh; if (!mesh) { *r_mesh = mesh = BKE_mesh_new_nomain(totpoint, totedge, 0, 0, 0); - CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_CALLOC, NULL, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, mesh->totvert); BKE_mesh_update_customdata_pointers(mesh, false); } mvert = mesh->mvert; diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 8c1f19f0909..1c6274ef35e 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -145,9 +145,14 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node) // BB_expand(&node->vb, co); //} -static bool face_materials_match(const MPoly *f1, const MPoly *f2) +static bool face_materials_match(const PBVH *pbvh, const int a, const int b) { - return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr)); + if (pbvh->material_indices) { + if (pbvh->material_indices[a] != pbvh->material_indices[b]) { + return false; + } + } + return (pbvh->mpoly[a].flag & ME_SMOOTH) == (pbvh->mpoly[b].flag & ME_SMOOTH); } static bool grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2) @@ -180,30 +185,23 @@ static int partition_indices(int *prim_indices, int lo, int hi, int axis, float /* Returns the index of the first element on the right of the partition */ static int partition_indices_material(PBVH *pbvh, int lo, int hi) { - const MPoly *mpoly = pbvh->mpoly; const MLoopTri *looptri = pbvh->looptri; const DMFlagMat *flagmats = pbvh->grid_flag_mats; const int *indices = pbvh->prim_indices; - const void *first; int i = lo, j = hi; - if (pbvh->looptri) { - first = &mpoly[looptri[pbvh->prim_indices[lo]].poly]; - } - else { - first = &flagmats[pbvh->prim_indices[lo]]; - } - for (;;) { if (pbvh->looptri) { - for (; face_materials_match(first, &mpoly[looptri[indices[i]].poly]); i++) { + const int first = looptri[pbvh->prim_indices[lo]].poly; + for (; face_materials_match(pbvh, first, looptri[indices[i]].poly); i++) { /* pass */ } - for (; !face_materials_match(first, &mpoly[looptri[indices[j]].poly]); j--) { + for (; !face_materials_match(pbvh, first, looptri[indices[j]].poly); j--) { /* pass */ } } else { + const DMFlagMat *first = &flagmats[pbvh->prim_indices[lo]]; for (; grid_materials_match(first, &flagmats[indices[i]]); i++) { /* pass */ } @@ -287,7 +285,7 @@ static void build_mesh_leaf_node(PBVH *pbvh, PBVHNode *node) } if (has_visible == false) { - if (!paint_is_face_hidden(lt, pbvh->verts, pbvh->mloop)) { + if (!paint_is_face_hidden(lt, pbvh->hide_vert, pbvh->mloop)) { has_visible = true; } } @@ -424,12 +422,9 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count) if (pbvh->looptri) { const MLoopTri *first = &pbvh->looptri[pbvh->prim_indices[offset]]; - const MPoly *mp = &pbvh->mpoly[first->poly]; - for (int i = offset + count - 1; i > offset; i--) { int prim = pbvh->prim_indices[i]; - const MPoly *mp_other = &pbvh->mpoly[pbvh->looptri[prim].poly]; - if (!face_materials_match(mp, mp_other)) { + if (!face_materials_match(pbvh, first->poly, pbvh->looptri[prim].poly)) { return true; } } @@ -555,13 +550,16 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, BB cb; pbvh->mesh = mesh; - pbvh->type = PBVH_FACES; + pbvh->header.type = PBVH_FACES; pbvh->mpoly = mpoly; + pbvh->material_indices = (const int *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_INT32, "material_index"); pbvh->mloop = mloop; pbvh->looptri = looptri; pbvh->verts = verts; BKE_mesh_vertex_normals_ensure(mesh); pbvh->vert_normals = BKE_mesh_vertex_normals_for_write(mesh); + pbvh->hide_vert = (bool *)CustomData_get_layer_named(&mesh->vdata, CD_PROP_BOOL, ".hide_vert"); pbvh->vert_bitmap = MEM_calloc_arrayN(totvert, sizeof(bool), "bvh->vert_bitmap"); pbvh->totvert = totvert; pbvh->leaf_limit = LEAF_LIMIT; @@ -615,7 +613,7 @@ void BKE_pbvh_build_grids(PBVH *pbvh, { const int gridsize = key->grid_size; - pbvh->type = PBVH_GRIDS; + pbvh->header.type = PBVH_GRIDS; pbvh->grids = grids; pbvh->gridfaces = gridfaces; pbvh->grid_flag_mats = flagmats; @@ -1274,7 +1272,7 @@ bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDo if (!layer || !ELEM(layer->type, CD_PROP_COLOR, CD_PROP_BYTE_COLOR)) { *r_layer = NULL; - *r_attr = ATTR_DOMAIN_NUM; + *r_attr = ATTR_DOMAIN_POINT; return false; } @@ -1282,7 +1280,7 @@ bool BKE_pbvh_get_color_layer(const Mesh *me, CustomDataLayer **r_layer, eAttrDo if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { *r_layer = NULL; - *r_attr = ATTR_DOMAIN_NUM; + *r_attr = ATTR_DOMAIN_POINT; return false; } @@ -1303,19 +1301,8 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, PBVH *pbvh = data->pbvh; PBVHNode *node = data->nodes[n]; - CustomData *vdata, *ldata; - - if (!pbvh->bm) { - vdata = pbvh->vdata; - ldata = pbvh->ldata; - } - else { - vdata = &pbvh->bm->vdata; - ldata = &pbvh->bm->ldata; - } - if (node->flag & PBVH_RebuildDrawBuffers) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: { bool smooth = node->totprim > 0 ? pbvh->grid_flag_mats[node->prim_indices[0]].flag & ME_SMOOTH : @@ -1326,14 +1313,11 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, } case PBVH_FACES: node->draw_buffers = GPU_pbvh_mesh_buffers_build( - pbvh->mpoly, - pbvh->mloop, + pbvh->mesh, pbvh->looptri, - pbvh->verts, - node->prim_indices, CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS), - node->totprim, - pbvh->mesh); + node->prim_indices, + node->totprim); break; case PBVH_BMESH: node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags & @@ -1343,8 +1327,10 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, } if (node->flag & PBVH_UpdateDrawBuffers) { + node->debug_draw_gen++; + const int update_flags = pbvh_get_buffers_update_flags(pbvh); - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: GPU_pbvh_grid_buffers_update(pbvh->vbo_id, node->draw_buffers, @@ -1360,11 +1346,12 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, update_flags); break; case PBVH_FACES: { + /* Pass vertices separately because they may be not be the same as the mesh's vertices, + * and pass normals separately because they are managed by the PBVH. */ GPU_pbvh_mesh_buffers_update(pbvh->vbo_id, node->draw_buffers, + pbvh->mesh, pbvh->verts, - vdata, - ldata, CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK), CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS), pbvh->face_sets_color_seed, @@ -1376,7 +1363,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata, case PBVH_BMESH: GPU_pbvh_bmesh_buffers_update(pbvh->vbo_id, node->draw_buffers, - pbvh->bm, + pbvh->header.bm, node->bm_faces, node->bm_unique_verts, node->bm_other_verts, @@ -1405,15 +1392,15 @@ static void pbvh_check_draw_layout(PBVH *pbvh) pbvh->vbo_id = GPU_pbvh_make_format(); } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_BMESH: - if (!pbvh->bm) { + if (!pbvh->header.bm) { /* BMesh hasn't been created yet */ return; } - vdata = &pbvh->bm->vdata; - ldata = &pbvh->bm->ldata; + vdata = &pbvh->header.bm->vdata; + ldata = &pbvh->header.bm->ldata; break; case PBVH_FACES: vdata = pbvh->vdata; @@ -1431,7 +1418,7 @@ static void pbvh_check_draw_layout(PBVH *pbvh) * (there's no guarantee there isn't another EEVEE viewport which would * free the draw buffers and corrupt the draw cache). */ - if (GPU_pbvh_attribute_names_update(pbvh->type, pbvh->vbo_id, vdata, ldata, false)) { + if (GPU_pbvh_attribute_names_update(pbvh->header.type, pbvh->vbo_id, vdata, ldata, false)) { /* attribute layout changed; force rebuild */ for (int i = 0; i < pbvh->totnode; i++) { PBVHNode *node = pbvh->nodes + i; @@ -1451,14 +1438,14 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, pbvh->vbo_id = GPU_pbvh_make_format(); } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_BMESH: - if (!pbvh->bm) { + if (!pbvh->header.bm) { /* BMesh hasn't been created yet */ return; } - vdata = &pbvh->bm->vdata; + vdata = &pbvh->header.bm->vdata; break; case PBVH_FACES: vdata = pbvh->vdata; @@ -1469,7 +1456,7 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, } UNUSED_VARS(vdata); - if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->type, PBVH_GRIDS, PBVH_BMESH)) { + if ((update_flag & PBVH_RebuildDrawBuffers) || ELEM(pbvh->header.type, PBVH_GRIDS, PBVH_BMESH)) { /* Free buffers uses OpenGL, so not in parallel. */ for (int n = 0; n < totnode; n++) { PBVHNode *node = nodes[n]; @@ -1477,11 +1464,11 @@ static void pbvh_update_draw_buffers(PBVH *pbvh, PBVHNode **nodes, int totnode, pbvh_free_draw_buffers(pbvh, node); } else if ((node->flag & PBVH_UpdateDrawBuffers) && node->draw_buffers) { - if (pbvh->type == PBVH_GRIDS) { + if (pbvh->header.type == PBVH_GRIDS) { GPU_pbvh_grid_buffers_update_free( node->draw_buffers, pbvh->grid_flag_mats, node->prim_indices); } - else if (pbvh->type == PBVH_BMESH) { + else if (pbvh->header.type == PBVH_BMESH) { GPU_pbvh_bmesh_buffers_update_free(node->draw_buffers); } } @@ -1602,9 +1589,12 @@ static void pbvh_faces_node_visibility_update(PBVH *pbvh, PBVHNode *node) BKE_pbvh_node_num_verts(pbvh, node, NULL, &totvert); BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert); + if (pbvh->hide_vert == NULL) { + BKE_pbvh_node_fully_hidden_set(node, false); + return; + } for (i = 0; i < totvert; i++) { - MVert *v = &mvert[vert_indices[i]]; - if (!(v->flag & ME_HIDE)) { + if (!(pbvh->hide_vert[vert_indices[i]])) { BKE_pbvh_node_fully_hidden_set(node, false); return; } @@ -1795,15 +1785,10 @@ void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int /***************************** PBVH Access ***********************************/ -PBVHType BKE_pbvh_type(const PBVH *pbvh) -{ - return pbvh->type; -} - bool BKE_pbvh_has_faces(const PBVH *pbvh) { - if (pbvh->type == PBVH_BMESH) { - return (pbvh->bm->totface != 0); + if (pbvh->header.type == PBVH_BMESH) { + return (pbvh->header.bm->totface != 0); } return (pbvh->totprim != 0); @@ -1824,46 +1809,40 @@ void BKE_pbvh_bounding_box(const PBVH *pbvh, float min[3], float max[3]) BLI_bitmap **BKE_pbvh_grid_hidden(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->grid_hidden; } const CCGKey *BKE_pbvh_get_grid_key(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return &pbvh->gridkey; } struct CCGElem **BKE_pbvh_get_grids(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->grids; } BLI_bitmap **BKE_pbvh_get_grid_visibility(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->grid_hidden; } int BKE_pbvh_get_grid_num_vertices(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->totgrid * pbvh->gridkey.grid_area; } int BKE_pbvh_get_grid_num_faces(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_GRIDS); + BLI_assert(pbvh->header.type == PBVH_GRIDS); return pbvh->totgrid * (pbvh->gridkey.grid_size - 1) * (pbvh->gridkey.grid_size - 1); } -BMesh *BKE_pbvh_get_bmesh(PBVH *pbvh) -{ - BLI_assert(pbvh->type == PBVH_BMESH); - return pbvh->bm; -} - /***************************** Node Access ***********************************/ void BKE_pbvh_node_mark_update(PBVHNode *node) @@ -1964,10 +1943,10 @@ bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node) return (node->flag & PBVH_Leaf) && (node->flag & PBVH_FullyUnmasked); } -void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, int index) +void BKE_pbvh_vert_tag_update_normal(PBVH *pbvh, PBVHVertRef vertex) { - BLI_assert(pbvh->type == PBVH_FACES); - pbvh->vert_bitmap[index] = true; + BLI_assert(pbvh->header.type == PBVH_FACES); + pbvh->vert_bitmap[vertex.i] = true; } void BKE_pbvh_node_get_loops(PBVH *pbvh, @@ -2004,7 +1983,7 @@ void BKE_pbvh_node_num_verts(PBVH *pbvh, PBVHNode *node, int *r_uniquevert, int { int tot; - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: tot = node->totprim * pbvh->gridkey.grid_area; if (r_totvert) { @@ -2042,7 +2021,7 @@ void BKE_pbvh_node_get_grids(PBVH *pbvh, int *r_gridsize, CCGElem ***r_griddata) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: if (r_grid_indices) { *r_grid_indices = node->prim_indices; @@ -2125,7 +2104,7 @@ void BKE_pbvh_node_get_bm_orco_data(PBVHNode *node, bool BKE_pbvh_node_has_vert_with_normal_update_tag(PBVH *pbvh, PBVHNode *node) { - BLI_assert(pbvh->type == PBVH_FACES); + BLI_assert(pbvh->header.type == PBVH_FACES); const int *verts = node->vert_indices; const int totvert = node->uniq_verts + node->face_verts; @@ -2299,7 +2278,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, int *r_active_face_index, float *r_face_normal) { @@ -2314,7 +2293,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, const MLoopTri *lt = &pbvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; - if (pbvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) { + if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_vert, mloop)) { continue; } @@ -2339,7 +2318,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, normal_tri_v3(r_face_normal, co[0], co[1], co[2]); } - if (r_active_vertex_index) { + if (r_active_vertex) { float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { @@ -2349,7 +2328,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh, if (j == 0 || len_squared_v3v3(location, co[j]) < len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, co[j]); - *r_active_vertex_index = mloop[lt->tri[j]].v; + r_active_vertex->i = mloop[lt->tri[j]].v; *r_active_face_index = lt->poly; } } @@ -2367,7 +2346,7 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, int *r_active_grid_index, float *r_face_normal) { @@ -2419,7 +2398,7 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh, normal_quad_v3(r_face_normal, co[0], co[1], co[2], co[3]); } - if (r_active_vertex_index) { + if (r_active_vertex) { float location[3] = {0.0}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); @@ -2434,8 +2413,8 @@ static bool pbvh_grids_node_raycast(PBVH *pbvh, len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, co[j]); - *r_active_vertex_index = gridkey->grid_area * grid_index + - (y + y_it[j]) * gridkey->grid_size + (x + x_it[j]); + r_active_vertex->i = gridkey->grid_area * grid_index + + (y + y_it[j]) * gridkey->grid_size + (x + x_it[j]); } } } @@ -2462,7 +2441,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, const float ray_normal[3], struct IsectRayPrecalc *isect_precalc, float *depth, - int *active_vertex_index, + PBVHVertRef *active_vertex, int *active_face_grid_index, float *face_normal) { @@ -2472,7 +2451,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, return false; } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_FACES: hit |= pbvh_faces_node_raycast(pbvh, node, @@ -2481,7 +2460,7 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, ray_normal, isect_precalc, depth, - active_vertex_index, + active_vertex, active_face_grid_index, face_normal); break; @@ -2493,19 +2472,19 @@ bool BKE_pbvh_node_raycast(PBVH *pbvh, ray_normal, isect_precalc, depth, - active_vertex_index, + active_vertex, active_face_grid_index, face_normal); break; case PBVH_BMESH: - BM_mesh_elem_index_ensure(pbvh->bm, BM_VERT); + BM_mesh_elem_index_ensure(pbvh->header.bm, BM_VERT); hit = pbvh_bmesh_node_raycast(node, ray_start, ray_normal, isect_precalc, depth, use_origco, - active_vertex_index, + active_vertex, face_normal); break; } @@ -2623,7 +2602,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh, const MLoopTri *lt = &pbvh->looptri[faces[i]]; const int *face_verts = node->face_vert_indices[i]; - if (pbvh->respect_hide && paint_is_face_hidden(lt, vert, mloop)) { + if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_vert, mloop)) { continue; } @@ -2729,7 +2708,7 @@ bool BKE_pbvh_node_find_nearest_to_ray(PBVH *pbvh, return false; } - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_FACES: hit |= pbvh_faces_node_nearest_to_ray( pbvh, node, origco, ray_start, ray_normal, depth, dist_sq); @@ -2820,13 +2799,13 @@ void BKE_pbvh_update_normals(PBVH *pbvh, struct SubdivCCG *subdiv_ccg) pbvh, update_search_cb, POINTER_FROM_INT(PBVH_UpdateNormals), &nodes, &totnode); if (totnode > 0) { - if (pbvh->type == PBVH_BMESH) { + if (pbvh->header.type == PBVH_BMESH) { pbvh_bmesh_normals_update(nodes, totnode); } - else if (pbvh->type == PBVH_FACES) { + else if (pbvh->header.type == PBVH_FACES) { pbvh_faces_update_normals(pbvh, nodes, totnode); } - else if (pbvh->type == PBVH_GRIDS) { + else if (pbvh->header.type == PBVH_GRIDS) { struct CCGFace **faces; int num_faces; BKE_pbvh_get_grid_updates(pbvh, true, (void ***)&faces, &num_faces); @@ -2917,15 +2896,18 @@ void BKE_pbvh_draw_cb(PBVH *pbvh, MEM_SAFE_FREE(nodes); } -void BKE_pbvh_draw_debug_cb( - PBVH *pbvh, - void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag), - void *user_data) +void BKE_pbvh_draw_debug_cb(PBVH *pbvh, + void (*draw_fn)(PBVHNode *node, + void *user_data, + const float bmin[3], + const float bmax[3], + PBVHNodeFlags flag), + void *user_data) { for (int a = 0; a < pbvh->totnode; a++) { PBVHNode *node = &pbvh->nodes[a]; - draw_fn(user_data, node->vb.bmin, node->vb.bmax, node->flag); + draw_fn(node, user_data, node->vb.bmin, node->vb.bmax, node->flag); } } @@ -2991,7 +2973,7 @@ void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int /* no need for float comparison here (memory is exactly equal or not) */ if (memcmp(mvert->co, vertCos[a], sizeof(float[3])) != 0) { copy_v3_v3(mvert->co, vertCos[a]); - BKE_pbvh_vert_tag_update_normal(pbvh, a); + BKE_pbvh_vert_tag_update_normal(pbvh, BKE_pbvh_make_vref(a)); } } @@ -3108,6 +3090,7 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi->no = NULL; vi->fno = NULL; vi->mvert = NULL; + vi->vertex.i = 0LL; vi->respect_hide = pbvh->respect_hide; if (pbvh->respect_hide == false) { @@ -3134,10 +3117,10 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m vi->vert_indices = vert_indices; vi->mverts = verts; - if (pbvh->type == PBVH_BMESH) { + if (pbvh->header.type == PBVH_BMESH) { BLI_gsetIterator_init(&vi->bm_unique_verts, node->bm_unique_verts); BLI_gsetIterator_init(&vi->bm_other_verts, node->bm_other_verts); - vi->bm_vdata = &pbvh->bm->vdata; + vi->bm_vdata = &pbvh->header.bm->vdata; vi->cd_vert_mask_offset = CustomData_get_offset(vi->bm_vdata, CD_PAINT_MASK); } @@ -3147,8 +3130,9 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m } vi->mask = NULL; - if (pbvh->type == PBVH_FACES) { + if (pbvh->header.type == PBVH_FACES) { vi->vert_normals = pbvh->vert_normals; + vi->hide_vert = pbvh->hide_vert; vi->vmask = CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK); } @@ -3156,13 +3140,14 @@ void pbvh_vertex_iter_init(PBVH *pbvh, PBVHNode *node, PBVHVertexIter *vi, int m bool pbvh_has_mask(const PBVH *pbvh) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: return (pbvh->gridkey.has_mask != 0); case PBVH_FACES: return (pbvh->vdata && CustomData_get_layer(pbvh->vdata, CD_PAINT_MASK)); case PBVH_BMESH: - return (pbvh->bm && (CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK) != -1)); + return (pbvh->header.bm && + (CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK) != -1)); } return false; @@ -3170,7 +3155,7 @@ bool pbvh_has_mask(const PBVH *pbvh) bool pbvh_has_face_sets(PBVH *pbvh) { - switch (pbvh->type) { + switch (pbvh->header.type) { case PBVH_GRIDS: return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS)); case PBVH_FACES: @@ -3218,16 +3203,37 @@ void BKE_pbvh_parallel_range_settings(TaskParallelSettings *settings, MVert *BKE_pbvh_get_verts(const PBVH *pbvh) { - BLI_assert(pbvh->type == PBVH_FACES); + BLI_assert(pbvh->header.type == PBVH_FACES); return pbvh->verts; } const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3] { - BLI_assert(pbvh->type == PBVH_FACES); + BLI_assert(pbvh->header.type == PBVH_FACES); return pbvh->vert_normals; } +const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh) +{ + BLI_assert(pbvh->header.type == PBVH_FACES); + return pbvh->hide_vert; +} + +bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh) +{ + BLI_assert(pbvh->header.type == PBVH_FACES); + if (pbvh->hide_vert) { + return pbvh->hide_vert; + } + pbvh->hide_vert = CustomData_get_layer_named(&pbvh->mesh->vdata, CD_PROP_BOOL, ".hide_vert"); + if (pbvh->hide_vert) { + return pbvh->hide_vert; + } + pbvh->hide_vert = (bool *)CustomData_add_layer_named( + &pbvh->mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, pbvh->mesh->totvert, ".hide_vert"); + return pbvh->hide_vert; +} + void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, SubdivCCG *subdiv_ccg) { pbvh->subdiv_ccg = subdiv_ccg; @@ -3242,6 +3248,7 @@ void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide) { pbvh->respect_hide = respect_hide; } + bool BKE_pbvh_is_drawing(const PBVH *pbvh) { return pbvh->is_drawing; @@ -3325,3 +3332,8 @@ void BKE_pbvh_ensure_node_loops(PBVH *pbvh) MEM_SAFE_FREE(visit); } + +int BKE_pbvh_debug_draw_gen_get(PBVHNode *node) +{ + return node->debug_draw_gen; +} diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index dec93826b9b..70aeb10f087 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -86,10 +86,12 @@ template<> void from_float(const float src[4], MPropCol &dst) } template<typename T> -static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4]) +static void pbvh_vertex_color_get(const PBVH &pbvh, PBVHVertRef vertex, float r_color[4]) { + int index = vertex.i; + if (pbvh.color_domain == ATTR_DOMAIN_CORNER) { - const MeshElemMap &melem = pbvh.pmap[vertex]; + const MeshElemMap &melem = pbvh.pmap[index]; int count = 0; zero_v4(r_color); @@ -99,7 +101,7 @@ static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4] Span<MLoop> loops{pbvh.mloop + mp.loopstart, mp.totloop}; for (const int i_loop : IndexRange(mp.totloop)) { - if (loops[i_loop].v == vertex) { + if (loops[i_loop].v == index) { float temp[4]; to_float(colors[i_loop], temp); @@ -114,15 +116,17 @@ static void pbvh_vertex_color_get(const PBVH &pbvh, int vertex, float r_color[4] } } else { - to_float(static_cast<T *>(pbvh.color_layer->data)[vertex], r_color); + to_float(static_cast<T *>(pbvh.color_layer->data)[index], r_color); } } template<typename T> -static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4]) +static void pbvh_vertex_color_set(PBVH &pbvh, PBVHVertRef vertex, const float color[4]) { + int index = vertex.i; + if (pbvh.color_domain == ATTR_DOMAIN_CORNER) { - const MeshElemMap &melem = pbvh.pmap[vertex]; + const MeshElemMap &melem = pbvh.pmap[index]; for (const int i_poly : Span(melem.indices, melem.count)) { const MPoly &mp = pbvh.mpoly[i_poly]; @@ -130,21 +134,21 @@ static void pbvh_vertex_color_set(PBVH &pbvh, int vertex, const float color[4]) Span<MLoop> loops{pbvh.mloop + mp.loopstart, mp.totloop}; for (const int i_loop : IndexRange(mp.totloop)) { - if (loops[i_loop].v == vertex) { + if (loops[i_loop].v == index) { from_float(color, colors[i_loop]); } } } } else { - from_float(color, static_cast<T *>(pbvh.color_layer->data)[vertex]); + from_float(color, static_cast<T *>(pbvh.color_layer->data)[index]); } } } // namespace blender::bke extern "C" { -void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]) +void BKE_pbvh_vertex_color_get(const PBVH *pbvh, PBVHVertRef vertex, float r_color[4]) { blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); @@ -152,7 +156,7 @@ void BKE_pbvh_vertex_color_get(const PBVH *pbvh, int vertex, float r_color[4]) }); } -void BKE_pbvh_vertex_color_set(PBVH *pbvh, int vertex, const float color[4]) +void BKE_pbvh_vertex_color_set(PBVH *pbvh, PBVHVertRef vertex, const float color[4]) { blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); @@ -202,7 +206,7 @@ void BKE_pbvh_store_colors_vertex(PBVH *pbvh, blender::bke::to_static_color_type(eCustomDataType(pbvh->color_layer->type), [&](auto dummy) { using T = decltype(dummy); for (const int i : IndexRange(indices_num)) { - blender::bke::pbvh_vertex_color_get<T>(*pbvh, indices[i], r_colors[i]); + blender::bke::pbvh_vertex_color_get<T>(*pbvh, BKE_pbvh_make_vref(indices[i]), r_colors[i]); } }); } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 112fd01c699..c4993684100 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -400,7 +400,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *pbvh, int node_index) BM_elem_index_set(f, i); /* set_dirty! */ } /* Likely this is already dirty. */ - pbvh->bm->elem_index_dirty |= BM_FACE; + pbvh->header.bm->elem_index_dirty |= BM_FACE; pbvh_bmesh_node_split(pbvh, bbc_array, node_index); @@ -484,8 +484,8 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *pbvh, BLI_assert((pbvh->totnode == 1 || node_index) && node_index <= pbvh->totnode); /* avoid initializing customdata because its quite involved */ - BMVert *v = BM_vert_create(pbvh->bm, co, NULL, BM_CREATE_SKIP_CD); - CustomData_bmesh_set_default(&pbvh->bm->vdata, &v->head.data); + BMVert *v = BM_vert_create(pbvh->header.bm, co, NULL, BM_CREATE_SKIP_CD); + CustomData_bmesh_set_default(&pbvh->header.bm->vdata, &v->head.data); /* This value is logged below */ copy_v3_v3(v->no, no); @@ -512,7 +512,7 @@ static BMFace *pbvh_bmesh_face_create( /* ensure we never add existing face */ BLI_assert(!BM_face_exists(v_tri, 3)); - BMFace *f = BM_face_create(pbvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); + BMFace *f = BM_face_create(pbvh->header.bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); f->head.hflag = f_example->head.hflag; BLI_gset_insert(node->bm_faces, f); @@ -1185,22 +1185,22 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, v_tri[0] = v1; v_tri[1] = v_new; v_tri[2] = v_opp; - bm_edges_from_tri(pbvh->bm, v_tri, e_tri); + bm_edges_from_tri(pbvh->header.bm, v_tri, e_tri); f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj); long_edge_queue_face_add(eq_ctx, f_new); v_tri[0] = v_new; v_tri[1] = v2; /* v_tri[2] = v_opp; */ /* unchanged */ - e_tri[0] = BM_edge_create(pbvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); + e_tri[0] = BM_edge_create(pbvh->header.bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); e_tri[2] = e_tri[1]; /* switched */ - e_tri[1] = BM_edge_create(pbvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); + e_tri[1] = BM_edge_create(pbvh->header.bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); f_new = pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f_adj); long_edge_queue_face_add(eq_ctx, f_new); /* Delete original */ pbvh_bmesh_face_remove(pbvh, f_adj); - BM_face_kill(pbvh->bm, f_adj); + BM_face_kill(pbvh->header.bm, f_adj); /* Ensure new vertex is in the node */ if (!BLI_gset_haskey(pbvh->nodes[ni].bm_unique_verts, v_new)) { @@ -1217,7 +1217,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, } } - BM_edge_kill(pbvh->bm, e); + BM_edge_kill(pbvh->header.bm, e); } static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, @@ -1303,12 +1303,12 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, BMFace *f_adj = l_adj->f; pbvh_bmesh_face_remove(pbvh, f_adj); - BM_face_kill(pbvh->bm, f_adj); + BM_face_kill(pbvh->header.bm, f_adj); } /* Kill the edge */ BLI_assert(BM_edge_is_wire(e)); - BM_edge_kill(pbvh->bm, e); + BM_edge_kill(pbvh->header.bm, e); /* For all remaining faces of v_del, create a new face that is the * same except it uses v_conn instead of v_del */ @@ -1355,7 +1355,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, BMEdge *e_tri[3]; PBVHNode *n = pbvh_bmesh_node_from_face(pbvh, f); int ni = n - pbvh->nodes; - bm_edges_from_tri(pbvh->bm, v_tri, e_tri); + bm_edges_from_tri(pbvh->header.bm, v_tri, e_tri); pbvh_bmesh_face_create(pbvh, ni, v_tri, e_tri, f); /* Ensure that v_conn is in the new face's node */ @@ -1388,13 +1388,13 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, /* Remove the face */ pbvh_bmesh_face_remove(pbvh, f_del); - BM_face_kill(pbvh->bm, f_del); + BM_face_kill(pbvh->header.bm, f_del); /* Check if any of the face's edges are now unused by any * face, if so delete them */ for (int j = 0; j < 3; j++) { if (BM_edge_is_wire(e_tri[j])) { - BM_edge_kill(pbvh->bm, e_tri[j]); + BM_edge_kill(pbvh->header.bm, e_tri[j]); } } @@ -1410,7 +1410,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, v_conn = NULL; } BLI_ghash_insert(deleted_verts, v_tri[j], NULL); - BM_vert_kill(pbvh->bm, v_tri[j]); + BM_vert_kill(pbvh->header.bm, v_tri[j]); } } } @@ -1437,7 +1437,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh, BM_log_vert_removed(pbvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset); /* v_conn == NULL is OK */ BLI_ghash_insert(deleted_verts, v_del, v_conn); - BM_vert_kill(pbvh->bm, v_del); + BM_vert_kill(pbvh->header.bm, v_del); } static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx, @@ -1501,7 +1501,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, struct IsectRayPrecalc *isect_precalc, float *depth, bool use_original, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, float *r_face_normal) { bool hit = false; @@ -1538,14 +1538,14 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, normal_tri_v3(r_face_normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co); } - if (r_active_vertex_index) { + if (r_active_vertex) { float location[3] = {0.0f}; madd_v3_v3v3fl(location, ray_start, ray_normal, *depth); for (int j = 0; j < 3; j++) { if (len_squared_v3v3(location, v_tri[j]->co) < len_squared_v3v3(location, nearest_vertex_co)) { copy_v3_v3(nearest_vertex_co, v_tri[j]->co); - *r_active_vertex_index = BM_elem_index_get(v_tri[j]); + r_active_vertex->i = (intptr_t)v_tri[j]; } } } @@ -1872,11 +1872,11 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh, { pbvh->cd_vert_node_offset = cd_vert_node_offset; pbvh->cd_face_node_offset = cd_face_node_offset; - pbvh->bm = bm; + pbvh->header.bm = bm; BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75); - pbvh->type = PBVH_BMESH; + pbvh->header.type = PBVH_BMESH; pbvh->bm_log = log; /* TODO: choose leaf limit better */ @@ -1951,7 +1951,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, /* 2 is enough for edge faces - manifold edge */ BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2); BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32); - const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK); + const int cd_vert_mask_offset = CustomData_get_offset(&pbvh->header.bm->vdata, CD_PAINT_MASK); const int cd_vert_node_offset = pbvh->cd_vert_node_offset; const int cd_face_node_offset = pbvh->cd_face_node_offset; @@ -1967,7 +1967,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, EdgeQueueContext eq_ctx = { &q, queue_pool, - pbvh->bm, + pbvh->header.bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, @@ -1986,7 +1986,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh, EdgeQueueContext eq_ctx = { &q, queue_pool, - pbvh->bm, + pbvh->header.bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, @@ -2126,13 +2126,13 @@ static void pbvh_bmesh_print(PBVH *pbvh) BMIter iter; BMFace *f; - BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(f), pbvh_bmesh_node_index_from_face(pbvh, f)); } fprintf(stderr, "bm_vert_to_node:\n"); BMVert *v; - BM_ITER_MESH (v, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), pbvh_bmesh_node_index_from_vert(pbvh, v)); } @@ -2171,21 +2171,21 @@ static void print_flag_factors(int flag) static void pbvh_bmesh_verify(PBVH *pbvh) { /* build list of faces & verts to lookup */ - GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totface); + GSet *faces_all = BLI_gset_ptr_new_ex(__func__, pbvh->header.bm->totface); BMIter iter; { BMFace *f; - BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { BLI_assert(BM_ELEM_CD_GET_INT(f, pbvh->cd_face_node_offset) != DYNTOPO_NODE_NONE); BLI_gset_insert(faces_all, f); } } - GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->bm->totvert); + GSet *verts_all = BLI_gset_ptr_new_ex(__func__, pbvh->header.bm->totvert); { BMVert *v; - BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { BLI_gset_insert(verts_all, v); } @@ -2207,7 +2207,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) { BMFace *f; - BM_ITER_MESH (f, &iter, pbvh->bm, BM_FACES_OF_MESH) { + BM_ITER_MESH (f, &iter, pbvh->header.bm, BM_FACES_OF_MESH) { BMIter bm_iter; BMVert *v; PBVHNode *n = pbvh_bmesh_node_lookup(pbvh, f); @@ -2240,7 +2240,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) /* Check verts */ { BMVert *v; - BM_ITER_MESH (v, &iter, pbvh->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (v, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { /* vertex isn't tracked */ if (BM_ELEM_CD_GET_INT(v, pbvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { continue; @@ -2286,7 +2286,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) # if 0 /* check that every vert belongs somewhere */ /* Slow */ - BM_ITER_MESH (vi, &iter, pbvh->bm, BM_VERTS_OF_MESH) { + BM_ITER_MESH (vi, &iter, pbvh->header.bm, BM_VERTS_OF_MESH) { bool has_unique = false; for (int i = 0; i < pbvh->totnode; i++) { PBVHNode *n = &pbvh->nodes[i]; @@ -2299,7 +2299,7 @@ static void pbvh_bmesh_verify(PBVH *pbvh) } /* If totvert differs from number of verts inside the hash. hash-totvert is checked above. */ - BLI_assert(vert_count == pbvh->bm->totvert); + BLI_assert(vert_count == pbvh->header.bm->totvert); # endif /* Check that node elements are recorded in the top level */ diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index a4ac2744a73..b848327b7a9 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -123,6 +123,11 @@ struct PBVHNode { /* Used to store the brush color during a stroke and composite it over the original color */ PBVHColorBufferNode color_buffer; PBVHPixelsNode pixels; + + /* Used to flash colors of updated node bounding boxes in + * debug draw mode (when G.debug_value / bpy.app.debug_value is 889). + */ + int debug_draw_gen; }; typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1 } PBVHFlags; @@ -130,7 +135,7 @@ typedef enum { PBVH_DYNTOPO_SMOOTH_SHADING = 1 } PBVHFlags; typedef struct PBVHBMeshLog PBVHBMeshLog; struct PBVH { - PBVHType type; + struct PBVHPublic header; PBVHFlags flags; PBVHNode *nodes; @@ -144,12 +149,15 @@ struct PBVH { int leaf_limit; /* Mesh data */ - const struct Mesh *mesh; + struct Mesh *mesh; /* NOTE: Normals are not `const` because they can be updated for drawing by sculpt code. */ float (*vert_normals)[3]; + bool *hide_vert; struct MVert *verts; const struct MPoly *mpoly; + /** Material indices. Only valid for polygon meshes. */ + const int *material_indices; const struct MLoop *mloop; const struct MLoopTri *looptri; CustomData *vdata; @@ -183,7 +191,6 @@ struct PBVH { bool respect_hide; /* Dynamic topology */ - BMesh *bm; float bm_max_edge_len; float bm_min_edge_len; int cd_vert_node_offset; @@ -265,7 +272,7 @@ bool pbvh_bmesh_node_raycast(PBVHNode *node, struct IsectRayPrecalc *isect_precalc, float *dist, bool use_original, - int *r_active_vertex_index, + PBVHVertRef *r_active_vertex, float *r_face_normal); bool pbvh_bmesh_node_nearest_to_ray(PBVHNode *node, const float ray_start[3], diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 5d8025dce8a..ce04d781980 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1304,7 +1304,7 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext) #define MAX_PTCACHE_PATH FILE_MAX #define MAX_PTCACHE_FILE (FILE_MAX * 2) -static int ptcache_path(PTCacheID *pid, char *filename) +static int ptcache_path(PTCacheID *pid, char *dirname) { const char *blendfile_path = BKE_main_blendfile_path_from_global(); Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL; @@ -1314,13 +1314,13 @@ static int ptcache_path(PTCacheID *pid, char *filename) size_t i; if (pid->cache->flag & PTCACHE_EXTERNAL) { - strcpy(filename, pid->cache->path); + strcpy(dirname, pid->cache->path); - if (BLI_path_is_rel(filename)) { - BLI_path_abs(filename, blendfilename); + if (BLI_path_is_rel(dirname)) { + BLI_path_abs(dirname, blendfilename); } - return BLI_path_slash_ensure(filename); /* new strlen() */ + return BLI_path_slash_ensure(dirname); /* new strlen() */ } if ((blendfile_path[0] != '\0') || lib) { char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */ @@ -1334,28 +1334,28 @@ static int ptcache_path(PTCacheID *pid, char *filename) } /* Add blend file name to pointcache dir. */ - BLI_snprintf(filename, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file); + BLI_snprintf(dirname, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file); - BLI_path_abs(filename, blendfilename); - return BLI_path_slash_ensure(filename); /* new strlen() */ + BLI_path_abs(dirname, blendfilename); + return BLI_path_slash_ensure(dirname); /* new strlen() */ } /* use the temp path. this is weak but better than not using point cache at all */ /* temporary directory is assumed to exist and ALWAYS has a trailing slash */ - BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session()); + BLI_snprintf(dirname, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session()); - return BLI_path_slash_ensure(filename); /* new strlen() */ + return BLI_path_slash_ensure(dirname); /* new strlen() */ } -static size_t ptcache_filename_ext_append(PTCacheID *pid, - char *filename, - const size_t filename_len, +static size_t ptcache_filepath_ext_append(PTCacheID *pid, + char *filepath, + const size_t filepath_len, const bool use_frame_number, const int cfra) { - size_t len = filename_len; + size_t len = filepath_len; char *filename_ext; - filename_ext = filename + filename_len; + filename_ext = filepath + filepath_len; *filename_ext = '\0'; /* PointCaches are inserted in object's list on demand, we need a valid index now. */ @@ -1399,14 +1399,14 @@ static size_t ptcache_filename_ext_append(PTCacheID *pid, return len; } -static int ptcache_filename( - PTCacheID *pid, char *filename, int cfra, const bool do_path, const bool do_ext) +static int ptcache_filepath( + PTCacheID *pid, char *filepath, int cfra, const bool do_path, const bool do_ext) { int len = 0; char *idname; char *newname; - filename[0] = '\0'; - newname = filename; + filepath[0] = '\0'; + newname = filepath; if ((pid->cache->flag & PTCACHE_EXTERNAL) == 0) { const char *blendfile_path = BKE_main_blendfile_path_from_global(); @@ -1417,7 +1417,7 @@ static int ptcache_filename( /* start with temp dir */ if (do_path) { - len = ptcache_path(pid, filename); + len = ptcache_path(pid, filepath); newname += len; } if (pid->cache->name[0] == '\0' && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) { @@ -1437,7 +1437,7 @@ static int ptcache_filename( } if (do_ext) { - len += ptcache_filename_ext_append(pid, filename, (size_t)len, true, cfra); + len += ptcache_filepath_ext_append(pid, filepath, (size_t)len, true, cfra); } return len; /* make sure the above string is always 16 chars */ @@ -1465,7 +1465,7 @@ static PTCacheFile *ptcache_file_open(PTCacheID *pid, int mode, int cfra) } } - ptcache_filename(pid, filepath, cfra, true, true); + ptcache_filepath(pid, filepath, cfra, true, true); if (mode == PTCACHE_FILE_READ) { fp = BLI_fopen(filepath, "rb"); @@ -2596,7 +2596,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) DIR *dir; struct dirent *de; char path[MAX_PTCACHE_PATH]; - char filename[MAX_PTCACHE_FILE]; + char filepath[MAX_PTCACHE_FILE]; char path_full[MAX_PTCACHE_FILE]; char ext[MAX_PTCACHE_PATH]; @@ -2631,20 +2631,20 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) return; } - len = ptcache_filename(pid, filename, cfra, false, false); /* no path */ + len = ptcache_filepath(pid, filepath, cfra, false, false); /* no path */ /* append underscore terminator to ensure we don't match similar names * from objects whose names start with the same prefix */ - if (len < sizeof(filename) - 2) { - BLI_strncpy(filename + len, "_", sizeof(filename) - 2 - len); + if (len < sizeof(filepath) - 2) { + BLI_strncpy(filepath + len, "_", sizeof(filepath) - 2 - len); len += 1; } - ptcache_filename_ext_append(pid, ext, 0, false, 0); + ptcache_filepath_ext_append(pid, ext, 0, false, 0); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* Do we have the right extension? */ - if (STREQLEN(filename, de->d_name, len)) { /* Do we have the right prefix. */ + if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */ if (mode == PTCACHE_CLEAR_ALL) { pid->cache->last_exact = MIN2(pid->cache->startframe, 0); BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name); @@ -2713,8 +2713,8 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra) case PTCACHE_CLEAR_FRAME: if (pid->cache->flag & PTCACHE_DISK_CACHE) { if (BKE_ptcache_id_exist(pid, cfra)) { - ptcache_filename(pid, filename, cfra, true, true); /* no path */ - BLI_delete(filename, false, false); + ptcache_filepath(pid, filepath, cfra, true, true); /* no path */ + BLI_delete(filepath, false, false); } } else { @@ -2752,11 +2752,11 @@ bool BKE_ptcache_id_exist(PTCacheID *pid, int cfra) } if (pid->cache->flag & PTCACHE_DISK_CACHE) { - char filename[MAX_PTCACHE_FILE]; + char filepath[MAX_PTCACHE_FILE]; - ptcache_filename(pid, filename, cfra, true, true); + ptcache_filepath(pid, filepath, cfra, true, true); - return BLI_exists(filename); + return BLI_exists(filepath); } PTCacheMem *pm = pid->cache->mem_cache.first; @@ -2824,24 +2824,24 @@ void BKE_ptcache_id_time( DIR *dir; struct dirent *de; char path[MAX_PTCACHE_PATH]; - char filename[MAX_PTCACHE_FILE]; + char filepath[MAX_PTCACHE_FILE]; char ext[MAX_PTCACHE_PATH]; unsigned int len; /* store the length of the string */ ptcache_path(pid, path); - len = ptcache_filename(pid, filename, (int)cfra, 0, 0); /* no path */ + len = ptcache_filepath(pid, filepath, (int)cfra, 0, 0); /* no path */ dir = opendir(path); if (dir == NULL) { return; } - ptcache_filename_ext_append(pid, ext, 0, false, 0); + ptcache_filepath_ext_append(pid, ext, 0, false, 0); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* Do we have the right extension? */ - if (STREQLEN(filename, de->d_name, len)) { /* Do we have the right prefix. */ + if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */ /* read the number of the file */ const int frame = ptcache_frame_from_filename(de->d_name, ext); @@ -3494,7 +3494,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c DIR *dir; struct dirent *de; char path[MAX_PTCACHE_PATH]; - char old_filename[MAX_PTCACHE_FILE]; + char old_filepath[MAX_PTCACHE_FILE]; char new_path_full[MAX_PTCACHE_FILE]; char old_path_full[MAX_PTCACHE_FILE]; char ext[MAX_PTCACHE_PATH]; @@ -3510,7 +3510,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c /* get "from" filename */ BLI_strncpy(pid->cache->name, name_src, sizeof(pid->cache->name)); - len = ptcache_filename(pid, old_filename, 0, false, false); /* no path */ + len = ptcache_filepath(pid, old_filepath, 0, false, false); /* no path */ ptcache_path(pid, path); dir = opendir(path); @@ -3519,20 +3519,20 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c return; } - ptcache_filename_ext_append(pid, ext, 0, false, 0); + ptcache_filepath_ext_append(pid, ext, 0, false, 0); /* put new name into cache */ BLI_strncpy(pid->cache->name, name_dst, sizeof(pid->cache->name)); while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* Do we have the right extension? */ - if (STREQLEN(old_filename, de->d_name, len)) { /* Do we have the right prefix. */ + if (STREQLEN(old_filepath, de->d_name, len)) { /* Do we have the right prefix. */ /* read the number of the file */ const int frame = ptcache_frame_from_filename(de->d_name, ext); if (frame != -1) { BLI_join_dirfile(old_path_full, sizeof(old_path_full), path, de->d_name); - ptcache_filename(pid, new_path_full, frame, true, true); + ptcache_filepath(pid, new_path_full, frame, true, true); BLI_rename(old_path_full, new_path_full); } } @@ -3556,7 +3556,7 @@ void BKE_ptcache_load_external(PTCacheID *pid) DIR *dir; struct dirent *de; char path[MAX_PTCACHE_PATH]; - char filename[MAX_PTCACHE_FILE]; + char filepath[MAX_PTCACHE_FILE]; char ext[MAX_PTCACHE_PATH]; if (!cache) { @@ -3565,7 +3565,7 @@ void BKE_ptcache_load_external(PTCacheID *pid) ptcache_path(pid, path); - len = ptcache_filename(pid, filename, 1, false, false); /* no path */ + len = ptcache_filepath(pid, filepath, 1, false, false); /* no path */ dir = opendir(path); if (dir == NULL) { @@ -3583,7 +3583,7 @@ void BKE_ptcache_load_external(PTCacheID *pid) while ((de = readdir(dir)) != NULL) { if (strstr(de->d_name, ext)) { /* Do we have the right extension? */ - if (STREQLEN(filename, de->d_name, len)) { /* Do we have the right prefix. */ + if (STREQLEN(filepath, de->d_name, len)) { /* Do we have the right prefix. */ /* read the number of the file */ const int frame = ptcache_frame_from_filename(de->d_name, ext); diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 426ad797cef..14ca3f58db9 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -64,7 +64,7 @@ static void pointcloud_init_data(ID *id) CustomData_reset(&pointcloud->pdata); CustomData_add_layer_named(&pointcloud->pdata, CD_PROP_FLOAT3, - CD_CALLOC, + CD_SET_DEFAULT, nullptr, pointcloud->totpoint, POINTCLOUD_ATTR_POSITION); @@ -228,13 +228,6 @@ void *BKE_pointcloud_add_default(Main *bmain, const char *name) PointCloud *pointcloud = static_cast<PointCloud *>(BKE_libblock_alloc(bmain, ID_PT, name, 0)); pointcloud_init_data(&pointcloud->id); - - CustomData_add_layer_named(&pointcloud->pdata, - CD_PROP_FLOAT, - CD_CALLOC, - nullptr, - pointcloud->totpoint, - POINTCLOUD_ATTR_RADIUS); pointcloud_random(pointcloud); return pointcloud; @@ -251,7 +244,7 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) CustomData_add_layer_named(&pointcloud->pdata, CD_PROP_FLOAT, - CD_CALLOC, + CD_SET_DEFAULT, nullptr, pointcloud->totpoint, POINTCLOUD_ATTR_RADIUS); @@ -325,22 +318,6 @@ bool BKE_pointcloud_customdata_required(const PointCloud *UNUSED(pointcloud), co /* Dependency Graph */ -PointCloud *BKE_pointcloud_new_for_eval(const PointCloud *pointcloud_src, int totpoint) -{ - PointCloud *pointcloud_dst = static_cast<PointCloud *>(BKE_id_new_nomain(ID_PT, nullptr)); - CustomData_free(&pointcloud_dst->pdata, pointcloud_dst->totpoint); - - STRNCPY(pointcloud_dst->id.name, pointcloud_src->id.name); - pointcloud_dst->mat = static_cast<Material **>(MEM_dupallocN(pointcloud_src->mat)); - pointcloud_dst->totcol = pointcloud_src->totcol; - - pointcloud_dst->totpoint = totpoint; - CustomData_copy( - &pointcloud_src->pdata, &pointcloud_dst->pdata, CD_MASK_ALL, CD_CALLOC, totpoint); - - return pointcloud_dst; -} - PointCloud *BKE_pointcloud_copy_for_eval(struct PointCloud *pointcloud_src, bool reference) { int flags = LIB_ID_COPY_LOCALIZE; diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index aaa6baac1ff..0445db5aed0 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -2501,7 +2501,7 @@ static bool check_rendered_viewport_visible(Main *bmain) return false; } -/* TODO(campbell): shouldn't we be able to use 'DEG_get_view_layer' here? +/* TODO(@campbellbarton): shouldn't we be able to use 'DEG_get_view_layer' here? * Currently this is nullptr on load, so don't. */ static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_layer) { @@ -2591,7 +2591,7 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on // DEG_debug_graph_relations_validate(depsgraph, bmain, scene); /* Flush editing data if needed. */ prepare_mesh_for_viewport_render(bmain, view_layer); - /* Update all objects: drivers, matrices, #DispList, etc. flags set + /* Update all objects: drivers, matrices, etc. flags set * by depsgraph or manual, no layer check here, gets correct flushed. */ DEG_evaluate_on_refresh(depsgraph); /* Update sound system. */ @@ -2666,7 +2666,7 @@ void BKE_scene_graph_update_for_newframe_ex(Depsgraph *depsgraph, const bool cle BKE_image_editors_update_frame(bmain, scene->r.cfra); BKE_sound_set_cfra(scene->r.cfra); DEG_graph_relations_update(depsgraph); - /* Update all objects: drivers, matrices, #DispList, etc. flags set + /* Update all objects: drivers, matrices, etc. flags set * by depsgraph or manual, no layer check here, gets correct flushed. * * NOTE: Only update for new frame on first iteration. Second iteration is for ensuring user diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index c16e5ce5655..f1eba64e401 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -148,7 +148,6 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_OUTLINER: { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - BKE_LIB_FOREACHID_PROCESS_ID(data, space_outliner->search_tse.id, IDWALK_CB_NOP); if (space_outliner->treestore != NULL) { TreeStoreElem *tselem; BLI_mempool_iter iter; @@ -1124,40 +1123,50 @@ static void write_uilist(BlendWriter *writer, uiList *ui_list) } } -static void write_space_outliner(BlendWriter *writer, SpaceOutliner *space_outliner) +static void write_space_outliner(BlendWriter *writer, const SpaceOutliner *space_outliner) { BLI_mempool *ts = space_outliner->treestore; if (ts) { - SpaceOutliner space_outliner_flat = *space_outliner; - - int elems = BLI_mempool_len(ts); + const int elems = BLI_mempool_len(ts); /* linearize mempool to array */ TreeStoreElem *data = elems ? BLI_mempool_as_arrayN(ts, "TreeStoreElem") : NULL; if (data) { - /* In this block we use the memory location of the treestore - * but _not_ its data, the addresses in this case are UUID's, - * since we can't rely on malloc giving us different values each time. + BLO_write_struct(writer, SpaceOutliner, space_outliner); + + /* To store #TreeStore (instead of the mempool), two unique memory addresses are needed, + * which can be used to identify the data on read: + * 1) One for the #TreeStore data itself. + * 2) One for the array of #TreeStoreElem's inside #TreeStore (#TreeStore.data). + * + * For 1) we just use the mempool's address (#SpaceOutliner::treestore). + * For 2) we don't have such a direct choice. We can't just use the array's address from + * above, since that may not be unique over all Outliners. So instead use an address relative + * to 1). */ - TreeStore ts_flat = {0}; + /* TODO the mempool could be moved to #SpaceOutliner_Runtime so that #SpaceOutliner could + * hold the #TreeStore directly. */ - /* we know the treestore is at least as big as a pointer, - * so offsetting works to give us a UUID. */ + /* Address relative to the tree-store, as noted above. */ void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *)); + /* There should be plenty of memory addresses within the mempool data that we can point into, + * just double-check we don't potentially end up with a memory address that another DNA + * struct might use. Assumes BLI_mempool uses the guarded allocator. */ + BLI_assert(MEM_allocN_len(ts) >= sizeof(void *) * 2); + TreeStore ts_flat = {0}; ts_flat.usedelem = elems; ts_flat.totelem = elems; ts_flat.data = data_addr; - BLO_write_struct(writer, SpaceOutliner, space_outliner); - BLO_write_struct_at_address(writer, TreeStore, ts, &ts_flat); BLO_write_struct_array_at_address(writer, TreeStoreElem, elems, data_addr, data); MEM_freeN(data); } else { + SpaceOutliner space_outliner_flat = *space_outliner; space_outliner_flat.treestore = NULL; BLO_write_struct_at_address(writer, SpaceOutliner, space_outliner, &space_outliner_flat); } @@ -1873,7 +1882,6 @@ void BKE_screen_area_blend_read_lib(BlendLibReader *reader, ID *parent_id, ScrAr } case SPACE_OUTLINER: { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - BLO_read_id_address(reader, NULL, &space_outliner->search_tse.id); if (space_outliner->treestore) { TreeStoreElem *tselem; diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c index 51ebd232978..745bd2a97e6 100644 --- a/source/blender/blenkernel/intern/shader_fx.c +++ b/source/blender/blenkernel/intern/shader_fx.c @@ -70,7 +70,8 @@ ShaderFxData *BKE_shaderfx_new(int type) fx->type = type; fx->mode = eShaderFxMode_Realtime | eShaderFxMode_Render; fx->flag = eShaderFxFlag_OverrideLibrary_Local; - fx->ui_expand_flag = 1; /* Expand only the parent panel by default. */ + /* Expand only the parent panel by default. */ + fx->ui_expand_flag = UI_PANEL_DATA_EXPAND_ROOT; if (fxi->flags & eShaderFxTypeFlag_EnableInEditmode) { fx->mode |= eShaderFxMode_Editmode; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index f459b5a82ac..bb0e7a4dd6b 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -756,7 +756,7 @@ void BKE_sound_remove_scene_sound(Scene *scene, void *handle) AUD_Sequence_remove(scene->sound_scene, handle); } -void BKE_sound_mute_scene_sound(void *handle, char mute) +void BKE_sound_mute_scene_sound(void *handle, bool mute) { AUD_SequenceEntry_setMuted(handle, mute); } @@ -1346,7 +1346,7 @@ void *BKE_sound_add_scene_sound_defaults(Scene *UNUSED(scene), Sequence *UNUSED( void BKE_sound_remove_scene_sound(Scene *UNUSED(scene), void *UNUSED(handle)) { } -void BKE_sound_mute_scene_sound(void *UNUSED(handle), char UNUSED(mute)) +void BKE_sound_mute_scene_sound(void *UNUSED(handle), bool UNUSED(mute)) { } void BKE_sound_move_scene_sound(const Scene *UNUSED(scene), diff --git a/source/blender/blenkernel/intern/subdiv_ccg_material.c b/source/blender/blenkernel/intern/subdiv_ccg_material.c index cf49db15b7b..9095a628418 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg_material.c +++ b/source/blender/blenkernel/intern/subdiv_ccg_material.c @@ -5,6 +5,7 @@ * \ingroup bke */ +#include "BKE_customdata.h" #include "BKE_subdiv_ccg.h" #include "MEM_guardedalloc.h" @@ -14,6 +15,7 @@ typedef struct CCGMaterialFromMeshData { const Mesh *mesh; + const int *material_indices; } CCGMaterialFromMeshData; static DMFlagMat subdiv_ccg_material_flags_eval( @@ -26,7 +28,7 @@ static DMFlagMat subdiv_ccg_material_flags_eval( const MPoly *poly = &mpoly[coarse_face_index]; DMFlagMat material_flags; material_flags.flag = poly->flag; - material_flags.mat_nr = poly->mat_nr; + material_flags.mat_nr = data->material_indices ? data->material_indices[coarse_face_index] : 0; return material_flags; } @@ -42,6 +44,8 @@ void BKE_subdiv_ccg_material_flags_init_from_mesh( CCGMaterialFromMeshData *data = MEM_mallocN(sizeof(CCGMaterialFromMeshData), "ccg material eval"); data->mesh = mesh; + data->material_indices = (const int *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_INT32, "material_index"); material_flags_evaluator->eval_material_flags = subdiv_ccg_material_flags_eval; material_flags_evaluator->free = subdiv_ccg_material_flags_free; material_flags_evaluator->user_data = data; diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c index 12a5f00a68b..9c6d507d42c 100644 --- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c @@ -205,7 +205,15 @@ static void precalc_uv_layer(const OpenSubdiv_Converter *converter, const int la mesh->totloop, sizeof(int), "loop uv vertex index"); } UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create( - mpoly, mloop, mloopuv, num_poly, num_vert, limit, false, true); + mpoly, + (const bool *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, ".hide_poly"), + mloop, + mloopuv, + num_poly, + num_vert, + limit, + false, + true); /* NOTE: First UV vertex is supposed to be always marked as separate. */ storage->num_uv_coordinates = -1; for (int vertex_index = 0; vertex_index < num_vert; vertex_index++) { diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.cc index 433bad34479..da22ee6fd47 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -11,7 +11,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BLI_alloca.h" +#include "BLI_array.hh" #include "BLI_bitmap.h" #include "BLI_math_vector.h" @@ -29,7 +29,7 @@ /** \name Subdivision Context * \{ */ -typedef struct SubdivMeshContext { +struct SubdivMeshContext { const SubdivToMeshSettings *settings; const Mesh *coarse_mesh; Subdiv *subdiv; @@ -48,15 +48,15 @@ typedef struct SubdivMeshContext { /* Per-subdivided vertex counter of averaged values. */ int *accumulated_counters; bool have_displacement; -} SubdivMeshContext; +}; static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx) { Mesh *subdiv_mesh = ctx->subdiv_mesh; ctx->num_uv_layers = CustomData_number_of_layers(&subdiv_mesh->ldata, CD_MLOOPUV); for (int layer_index = 0; layer_index < ctx->num_uv_layers; layer_index++) { - ctx->uv_layers[layer_index] = CustomData_get_layer_n( - &subdiv_mesh->ldata, CD_MLOOPUV, layer_index); + ctx->uv_layers[layer_index] = static_cast<MLoopUV *>( + CustomData_get_layer_n(&subdiv_mesh->ldata, CD_MLOOPUV, layer_index)); } } @@ -64,15 +64,20 @@ static void subdiv_mesh_ctx_cache_custom_data_layers(SubdivMeshContext *ctx) { Mesh *subdiv_mesh = ctx->subdiv_mesh; /* Pointers to original indices layers. */ - ctx->vert_origindex = CustomData_get_layer(&subdiv_mesh->vdata, CD_ORIGINDEX); - ctx->edge_origindex = CustomData_get_layer(&subdiv_mesh->edata, CD_ORIGINDEX); - ctx->loop_origindex = CustomData_get_layer(&subdiv_mesh->ldata, CD_ORIGINDEX); - ctx->poly_origindex = CustomData_get_layer(&subdiv_mesh->pdata, CD_ORIGINDEX); + ctx->vert_origindex = static_cast<int *>( + CustomData_get_layer(&subdiv_mesh->vdata, CD_ORIGINDEX)); + ctx->edge_origindex = static_cast<int *>( + CustomData_get_layer(&subdiv_mesh->edata, CD_ORIGINDEX)); + ctx->loop_origindex = static_cast<int *>( + CustomData_get_layer(&subdiv_mesh->ldata, CD_ORIGINDEX)); + ctx->poly_origindex = static_cast<int *>( + CustomData_get_layer(&subdiv_mesh->pdata, CD_ORIGINDEX)); /* UV layers interpolation. */ subdiv_mesh_ctx_cache_uv_layers(ctx); /* Orco interpolation. */ - ctx->orco = CustomData_get_layer(&subdiv_mesh->vdata, CD_ORCO); - ctx->cloth_orco = CustomData_get_layer(&subdiv_mesh->vdata, CD_CLOTH_ORCO); + ctx->orco = static_cast<float(*)[3]>(CustomData_get_layer(&subdiv_mesh->vdata, CD_ORCO)); + ctx->cloth_orco = static_cast<float(*)[3]>( + CustomData_get_layer(&subdiv_mesh->vdata, CD_CLOTH_ORCO)); } static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vertices) @@ -80,8 +85,8 @@ static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vert if (!ctx->have_displacement) { return; } - ctx->accumulated_counters = MEM_calloc_arrayN( - num_vertices, sizeof(*ctx->accumulated_counters), "subdiv accumulated counters"); + ctx->accumulated_counters = static_cast<int *>( + MEM_calloc_arrayN(num_vertices, sizeof(*ctx->accumulated_counters), __func__)); } static void subdiv_mesh_context_free(SubdivMeshContext *ctx) @@ -95,7 +100,7 @@ static void subdiv_mesh_context_free(SubdivMeshContext *ctx) /** \name Loop custom data copy helpers * \{ */ -typedef struct LoopsOfPtex { +struct LoopsOfPtex { /* First loop of the ptex, starts at ptex (0, 0) and goes in u direction. */ const MLoop *first_loop; /* Last loop of the ptex, starts at ptex (0, 0) and goes in v direction. */ @@ -103,7 +108,7 @@ typedef struct LoopsOfPtex { /* For quad coarse faces only. */ const MLoop *second_loop; const MLoop *third_loop; -} LoopsOfPtex; +}; static void loops_of_ptex_get(const SubdivMeshContext *ctx, LoopsOfPtex *loops_of_ptex, @@ -126,8 +131,8 @@ static void loops_of_ptex_get(const SubdivMeshContext *ctx, loops_of_ptex->third_loop = loops_of_ptex->first_loop + 2; } else { - loops_of_ptex->second_loop = NULL; - loops_of_ptex->third_loop = NULL; + loops_of_ptex->second_loop = nullptr; + loops_of_ptex->third_loop = nullptr; } } @@ -140,7 +145,7 @@ static void loops_of_ptex_get(const SubdivMeshContext *ctx, /* TODO(sergey): Somehow de-duplicate with loops storage, without too much * exception cases all over the code. */ -typedef struct VerticesForInterpolation { +struct VerticesForInterpolation { /* This field points to a vertex data which is to be used for interpolation. * The idea is to avoid unnecessary allocations for regular faces, where * we can simply use corner vertices. */ @@ -159,7 +164,7 @@ typedef struct VerticesForInterpolation { /* Indices within vertex_data to interpolate for. The indices are aligned * with uv coordinates in a similar way as indices in loop_data_storage. */ int vertex_indices[4]; -} VerticesForInterpolation; +}; static void vertex_interpolation_init(const SubdivMeshContext *ctx, VerticesForInterpolation *vertex_interpolation, @@ -181,7 +186,7 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx, CustomData_copy(&ctx->coarse_mesh->vdata, &vertex_interpolation->vertex_data_storage, CD_MASK_EVERYTHING.vmask, - CD_CALLOC, + CD_SET_DEFAULT, 4); /* Initialize indices. */ vertex_interpolation->vertex_indices[0] = 0; @@ -192,17 +197,17 @@ static void vertex_interpolation_init(const SubdivMeshContext *ctx, /* Interpolate center of poly right away, it stays unchanged for all * ptex faces. */ const float weight = 1.0f / (float)coarse_poly->totloop; - float *weights = BLI_array_alloca(weights, coarse_poly->totloop); - int *indices = BLI_array_alloca(indices, coarse_poly->totloop); + blender::Array<float, 32> weights(coarse_poly->totloop); + blender::Array<int, 32> indices(coarse_poly->totloop); for (int i = 0; i < coarse_poly->totloop; i++) { weights[i] = weight; indices[i] = coarse_mloop[coarse_poly->loopstart + i].v; } CustomData_interp(&coarse_mesh->vdata, &vertex_interpolation->vertex_data_storage, - indices, - weights, - NULL, + indices.data(), + weights.data(), + nullptr, coarse_poly->totloop, 2); } @@ -237,26 +242,27 @@ static void vertex_interpolation_from_corner(const SubdivMeshContext *ctx, const int first_loop_index = loops_of_ptex.first_loop - coarse_mloop; const int last_loop_index = loops_of_ptex.last_loop - coarse_mloop; const int first_indices[2] = { - coarse_mloop[first_loop_index].v, - coarse_mloop[coarse_poly->loopstart + - (first_loop_index - coarse_poly->loopstart + 1) % coarse_poly->totloop] - .v}; + static_cast<int>(coarse_mloop[first_loop_index].v), + static_cast<int>( + coarse_mloop[coarse_poly->loopstart + + (first_loop_index - coarse_poly->loopstart + 1) % coarse_poly->totloop] + .v)}; const int last_indices[2] = { - coarse_mloop[first_loop_index].v, - coarse_mloop[last_loop_index].v, + static_cast<int>(coarse_mloop[first_loop_index].v), + static_cast<int>(coarse_mloop[last_loop_index].v), }; CustomData_interp(vertex_data, &vertex_interpolation->vertex_data_storage, first_indices, weights, - NULL, + nullptr, 2, 1); CustomData_interp(vertex_data, &vertex_interpolation->vertex_data_storage, last_indices, weights, - NULL, + nullptr, 2, 3); } @@ -275,7 +281,7 @@ static void vertex_interpolation_end(VerticesForInterpolation *vertex_interpolat /** \name Loop custom data interpolation helpers * \{ */ -typedef struct LoopsForInterpolation { +struct LoopsForInterpolation { /* This field points to a loop data which is to be used for interpolation. * The idea is to avoid unnecessary allocations for regular faces, where * we can simply interpolate corner vertices. */ @@ -291,10 +297,10 @@ typedef struct LoopsForInterpolation { * Is allocated for non-regular faces (triangles and n-gons). */ CustomData loop_data_storage; bool loop_data_storage_allocated; - /* Infices within loop_data to interpolate for. The indices are aligned with + /* Indices within loop_data to interpolate for. The indices are aligned with * uv coordinates in a similar way as indices in loop_data_storage. */ int loop_indices[4]; -} LoopsForInterpolation; +}; static void loop_interpolation_init(const SubdivMeshContext *ctx, LoopsForInterpolation *loop_interpolation, @@ -315,7 +321,7 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx, CustomData_copy(&ctx->coarse_mesh->ldata, &loop_interpolation->loop_data_storage, CD_MASK_EVERYTHING.lmask, - CD_CALLOC, + CD_SET_DEFAULT, 4); /* Initialize indices. */ loop_interpolation->loop_indices[0] = 0; @@ -326,17 +332,17 @@ static void loop_interpolation_init(const SubdivMeshContext *ctx, /* Interpolate center of poly right away, it stays unchanged for all * ptex faces. */ const float weight = 1.0f / (float)coarse_poly->totloop; - float *weights = BLI_array_alloca(weights, coarse_poly->totloop); - int *indices = BLI_array_alloca(indices, coarse_poly->totloop); + blender::Array<float, 32> weights(coarse_poly->totloop); + blender::Array<int, 32> indices(coarse_poly->totloop); for (int i = 0; i < coarse_poly->totloop; i++) { weights[i] = weight; indices[i] = coarse_poly->loopstart + i; } CustomData_interp(&coarse_mesh->ldata, &loop_interpolation->loop_data_storage, - indices, - weights, - NULL, + indices.data(), + weights.data(), + nullptr, coarse_poly->totloop, 2); } @@ -372,13 +378,13 @@ static void loop_interpolation_from_corner(const SubdivMeshContext *ctx, (first_loop_index - base_loop_index + 1) % coarse_poly->totloop; const int first_indices[2] = {first_loop_index, second_loop_index}; const int last_indices[2] = { - loops_of_ptex.last_loop - coarse_mloop, - loops_of_ptex.first_loop - coarse_mloop, + static_cast<int>(loops_of_ptex.last_loop - coarse_mloop), + static_cast<int>(loops_of_ptex.first_loop - coarse_mloop), }; CustomData_interp( - loop_data, &loop_interpolation->loop_data_storage, first_indices, weights, NULL, 2, 1); + loop_data, &loop_interpolation->loop_data_storage, first_indices, weights, nullptr, 2, 1); CustomData_interp( - loop_data, &loop_interpolation->loop_data_storage, last_indices, weights, NULL, 2, 3); + loop_data, &loop_interpolation->loop_data_storage, last_indices, weights, nullptr, 2, 3); } } @@ -395,7 +401,7 @@ static void loop_interpolation_end(LoopsForInterpolation *loop_interpolation) /** \name TLS * \{ */ -typedef struct SubdivMeshTLS { +struct SubdivMeshTLS { bool vertex_interpolation_initialized; VerticesForInterpolation vertex_interpolation; const MPoly *vertex_interpolation_coarse_poly; @@ -405,11 +411,11 @@ typedef struct SubdivMeshTLS { LoopsForInterpolation loop_interpolation; const MPoly *loop_interpolation_coarse_poly; int loop_interpolation_coarse_corner; -} SubdivMeshTLS; +}; static void subdiv_mesh_tls_free(void *tls_v) { - SubdivMeshTLS *tls = tls_v; + SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v); if (tls->vertex_interpolation_initialized) { vertex_interpolation_end(&tls->vertex_interpolation); } @@ -492,7 +498,7 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex CustomData_MeshMasks mask = CD_MASK_EVERYTHING; mask.lmask &= ~CD_MASK_MULTIRES_GRIDS; - SubdivMeshContext *subdiv_context = foreach_context->user_data; + SubdivMeshContext *subdiv_context = static_cast<SubdivMeshContext *>(foreach_context->user_data); subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template_ex( subdiv_context->coarse_mesh, num_vertices, num_edges, 0, num_loops, num_polygons, mask); subdiv_mesh_ctx_cache_custom_data_layers(subdiv_context); @@ -533,10 +539,10 @@ static void subdiv_vertex_data_interpolate(const SubdivMeshContext *ctx, &ctx->subdiv_mesh->vdata, vertex_interpolation->vertex_indices, weights, - NULL, + nullptr, 4, subdiv_vertex_index); - if (ctx->vert_origindex != NULL) { + if (ctx->vert_origindex != nullptr) { ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; } } @@ -564,7 +570,7 @@ static void evaluate_vertex_and_apply_displacement_copy(const SubdivMeshContext add_v3_v3(subdiv_vert->co, D); /* Evaluate undeformed texture coordinate. */ subdiv_vertex_orco_evaluate(ctx, ptex_face_index, u, v, subdiv_vertex_index); - /* Remove facedot flag. This can happen if there is more than one subsurf modifier. */ + /* Remove face-dot flag. This can happen if there is more than one subsurf modifier. */ BLI_BITMAP_DISABLE(ctx->subdiv_mesh->runtime.subsurf_face_dot_tags, subdiv_vertex_index); } @@ -602,7 +608,7 @@ static void subdiv_mesh_vertex_displacement_every_corner_or_edge( const float v, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); Mesh *subdiv_mesh = ctx->subdiv_mesh; MVert *subdiv_mvert = subdiv_mesh->mvert; MVert *subdiv_vert = &subdiv_mvert[subdiv_vertex_index]; @@ -649,7 +655,7 @@ static void subdiv_mesh_vertex_corner(const SubdivForeachContext *foreach_contex const int subdiv_vertex_index) { BLI_assert(coarse_vertex_index != ORIGINDEX_NONE); - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); const Mesh *coarse_mesh = ctx->coarse_mesh; const MVert *coarse_mvert = coarse_mesh->mvert; Mesh *subdiv_mesh = ctx->subdiv_mesh; @@ -698,8 +704,8 @@ static void subdiv_mesh_vertex_edge(const SubdivForeachContext *foreach_context, const int coarse_corner, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; - SubdivMeshTLS *tls = tls_v; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); + SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v); const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; @@ -746,8 +752,8 @@ static void subdiv_mesh_vertex_inner(const SubdivForeachContext *foreach_context const int coarse_corner, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; - SubdivMeshTLS *tls = tls_v; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); + SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v); Subdiv *subdiv = ctx->subdiv; const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; @@ -773,14 +779,14 @@ static void subdiv_copy_edge_data(SubdivMeshContext *ctx, const MEdge *coarse_edge) { const int subdiv_edge_index = subdiv_edge - ctx->subdiv_mesh->medge; - if (coarse_edge == NULL) { + if (coarse_edge == nullptr) { subdiv_edge->crease = 0; subdiv_edge->bweight = 0; subdiv_edge->flag = 0; if (!ctx->settings->use_optimal_display) { subdiv_edge->flag |= ME_EDGERENDER; } - if (ctx->edge_origindex != NULL) { + if (ctx->edge_origindex != nullptr) { ctx->edge_origindex[subdiv_edge_index] = ORIGINDEX_NONE; } return; @@ -799,11 +805,11 @@ static void subdiv_mesh_edge(const SubdivForeachContext *foreach_context, const int subdiv_v1, const int subdiv_v2) { - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); Mesh *subdiv_mesh = ctx->subdiv_mesh; MEdge *subdiv_medge = subdiv_mesh->medge; MEdge *subdiv_edge = &subdiv_medge[subdiv_edge_index]; - const MEdge *coarse_edge = NULL; + const MEdge *coarse_edge = nullptr; if (coarse_edge_index != ORIGINDEX_NONE) { const Mesh *coarse_mesh = ctx->coarse_mesh; const MEdge *coarse_medge = coarse_mesh->medge; @@ -832,7 +838,7 @@ static void subdiv_interpolate_loop_data(const SubdivMeshContext *ctx, &ctx->subdiv_mesh->ldata, loop_interpolation->loop_indices, weights, - NULL, + nullptr, 4, subdiv_loop_index); /* TODO(sergey): Set ORIGINDEX. */ @@ -895,8 +901,8 @@ static void subdiv_mesh_loop(const SubdivForeachContext *foreach_context, const int subdiv_vertex_index, const int subdiv_edge_index) { - SubdivMeshContext *ctx = foreach_context->user_data; - SubdivMeshTLS *tls = tls_v; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); + SubdivMeshTLS *tls = static_cast<SubdivMeshTLS *>(tls_v); const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; @@ -934,7 +940,7 @@ static void subdiv_mesh_poly(const SubdivForeachContext *foreach_context, const int num_loops) { BLI_assert(coarse_poly_index != ORIGINDEX_NONE); - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); const Mesh *coarse_mesh = ctx->coarse_mesh; const MPoly *coarse_mpoly = coarse_mesh->mpoly; const MPoly *coarse_poly = &coarse_mpoly[coarse_poly_index]; @@ -957,7 +963,7 @@ static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context const int coarse_vertex_index, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); const Mesh *coarse_mesh = ctx->coarse_mesh; const MVert *coarse_mvert = coarse_mesh->mvert; const MVert *coarse_vertex = &coarse_mvert[coarse_vertex_index]; @@ -975,8 +981,8 @@ static void find_edge_neighbors(const Mesh *coarse_mesh, const MEdge *neighbors[2]) { const MEdge *coarse_medge = coarse_mesh->medge; - neighbors[0] = NULL; - neighbors[1] = NULL; + neighbors[0] = nullptr; + neighbors[1] = nullptr; int neighbor_counters[2] = {0, 0}; for (int edge_index = 0; edge_index < coarse_mesh->totedge; edge_index++) { const MEdge *current_edge = &coarse_medge[edge_index]; @@ -996,10 +1002,10 @@ static void find_edge_neighbors(const Mesh *coarse_mesh, * sharp. This is also how topology factory treats vertices of a surface * which are adjacent to a loose edge. */ if (neighbor_counters[0] > 1) { - neighbors[0] = NULL; + neighbors[0] = nullptr; } if (neighbor_counters[1] > 1) { - neighbors[1] = NULL; + neighbors[1] = nullptr; } } @@ -1013,7 +1019,7 @@ static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh, copy_v3_v3(points_r[1], coarse_mvert[coarse_edge->v1].co); copy_v3_v3(points_r[2], coarse_mvert[coarse_edge->v2].co); /* Start point, duplicate from edge start if no neighbor. */ - if (neighbors[0] != NULL) { + if (neighbors[0] != nullptr) { if (neighbors[0]->v1 == coarse_edge->v1) { copy_v3_v3(points_r[0], coarse_mvert[neighbors[0]->v2].co); } @@ -1026,7 +1032,7 @@ static void points_for_loose_edges_interpolation_get(const Mesh *coarse_mesh, add_v3_v3(points_r[0], points_r[1]); } /* End point, duplicate from edge end if no neighbor. */ - if (neighbors[1] != NULL) { + if (neighbors[1] != nullptr) { if (neighbors[1]->v1 == coarse_edge->v2) { copy_v3_v3(points_r[3], coarse_mvert[neighbors[1]->v2].co); } @@ -1075,26 +1081,27 @@ static void subdiv_mesh_vertex_of_loose_edge_interpolate(SubdivMeshContext *ctx, BLI_assert(u > 0.0f); BLI_assert(u < 1.0f); const float interpolation_weights[2] = {1.0f - u, u}; - const int coarse_vertex_indices[2] = {coarse_edge->v1, coarse_edge->v2}; + const int coarse_vertex_indices[2] = {static_cast<int>(coarse_edge->v1), + static_cast<int>(coarse_edge->v2)}; CustomData_interp(&coarse_mesh->vdata, &subdiv_mesh->vdata, coarse_vertex_indices, interpolation_weights, - NULL, + nullptr, 2, subdiv_vertex_index); - if (ctx->vert_origindex != NULL) { + if (ctx->vert_origindex != nullptr) { ctx->vert_origindex[subdiv_vertex_index] = ORIGINDEX_NONE; } } -static void subdiv_mesh_vertex_of_loose_edge(const struct SubdivForeachContext *foreach_context, +static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach_context, void *UNUSED(tls), const int coarse_edge_index, const float u, const int subdiv_vertex_index) { - SubdivMeshContext *ctx = foreach_context->user_data; + SubdivMeshContext *ctx = static_cast<SubdivMeshContext *>(foreach_context->user_data); const Mesh *coarse_mesh = ctx->coarse_mesh; const MEdge *coarse_edge = &coarse_mesh->medge[coarse_edge_index]; Mesh *subdiv_mesh = ctx->subdiv_mesh; @@ -1158,7 +1165,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, /* Make sure evaluator is up to date with possible new topology, and that * it is refined for the new positions of coarse vertices. */ if (!BKE_subdiv_eval_begin_from_mesh( - subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) { + subdiv, coarse_mesh, nullptr, SUBDIV_EVALUATOR_TYPE_CPU, nullptr)) { /* This could happen in two situations: * - OpenSubdiv is disabled. * - Something totally bad happened, and OpenSubdiv rejected our @@ -1166,7 +1173,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, * In either way, we can't safely continue. */ if (coarse_mesh->totpoly) { BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); - return NULL; + return nullptr; } } /* Initialize subdivision mesh creation context. */ @@ -1174,7 +1181,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, subdiv_context.settings = settings; subdiv_context.coarse_mesh = coarse_mesh; subdiv_context.subdiv = subdiv; - subdiv_context.have_displacement = (subdiv->displacement_evaluator != NULL); + subdiv_context.have_displacement = (subdiv->displacement_evaluator != nullptr); /* Multi-threaded traversal/evaluation. */ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH_GEOMETRY); SubdivForeachContext foreach_context; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index efabb4f039a..52df555090f 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -284,7 +284,8 @@ static int ss_sync_from_uv(CCGSubSurf *ss, * UV map in really simple cases with mirror + subsurf, see second part of T44530. * Also, initially intention is to treat merged vertices from mirror modifier as seams. * This fixes a very old regression (2.49 was correct here) */ - vmap = BKE_mesh_uv_vert_map_create(mpoly, mloop, mloopuv, totface, totvert, limit, false, true); + vmap = BKE_mesh_uv_vert_map_create( + mpoly, NULL, mloop, mloopuv, totface, totvert, limit, false, true); if (!vmap) { return 0; } @@ -1133,14 +1134,12 @@ static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mpoly) CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); int flag = (faceFlags) ? faceFlags[index].flag : ME_SMOOTH; - int mat_nr = (faceFlags) ? faceFlags[index].mat_nr : 0; for (S = 0; S < numVerts; S++) { for (y = 0; y < gridSize - 1; y++) { for (x = 0; x < gridSize - 1; x++) { MPoly *mp = &mpoly[i]; - mp->mat_nr = mat_nr; mp->flag = flag; mp->loopstart = k; mp->totloop = 4; @@ -1247,7 +1246,7 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type) BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE); origindex = CustomData_add_layer( - &dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numVertData); + &dm->vertData, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, dm->numVertData); totorig = ccgSubSurf_getNumVerts(ss); totnone = dm->numVertData - totorig; @@ -1286,7 +1285,7 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type) } origindex = CustomData_add_layer( - &dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numEdgeData); + &dm->edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, dm->numEdgeData); totedge = ccgSubSurf_getNumEdges(ss); totorig = totedge * (edgeSize - 1); @@ -1329,7 +1328,7 @@ static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type) } origindex = CustomData_add_layer( - &dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, dm->numPolyData); + &dm->polyData, CD_ORIGINDEX, CD_SET_DEFAULT, NULL, dm->numPolyData); totface = ccgSubSurf_getNumFaces(ss); @@ -1606,6 +1605,8 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, medge = dm->getEdgeArray(dm); const MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); + const int *material_indices = CustomData_get_layer_named( + &dm->polyData, CD_MPOLY, "material_index"); const int *base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX); int *vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX); @@ -1634,7 +1635,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, ccgdm->faceMap[index].startFace = faceNum; faceFlags->flag = mpoly ? mpoly[origIndex].flag : 0; - faceFlags->mat_nr = mpoly ? mpoly[origIndex].mat_nr : 0; + faceFlags->mat_nr = material_indices ? material_indices[origIndex] : 0; faceFlags++; /* set the face base vert */ diff --git a/source/blender/blenkernel/intern/tracking_detect.c b/source/blender/blenkernel/intern/tracking_detect.c index 51ffce4a3e3..540f880905d 100644 --- a/source/blender/blenkernel/intern/tracking_detect.c +++ b/source/blender/blenkernel/intern/tracking_detect.c @@ -81,7 +81,6 @@ static void detect_retrieve_libmv_features(MovieTracking *tracking, a = libmv_countFeatures(features); while (a--) { - MovieTrackingTrack *track; double x, y, size, score; bool ok = true; float xu, yu; @@ -99,7 +98,8 @@ static void detect_retrieve_libmv_features(MovieTracking *tracking, } if (ok) { - track = BKE_tracking_track_add(tracking, tracksbase, xu, yu, framenr, width, height); + MovieTrackingTrack *track = BKE_tracking_track_add( + tracking, tracksbase, xu, yu, framenr, width, height); track->flag |= SELECT; track->pat_flag |= SELECT; track->search_flag |= SELECT; diff --git a/source/blender/blenkernel/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc index 0b5d6ad7b10..a01f5d19088 100644 --- a/source/blender/blenkernel/intern/type_conversions.cc +++ b/source/blender/blenkernel/intern/type_conversions.cc @@ -367,20 +367,38 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, functions->convert_single_to_uninitialized(from_value, to_value); } +static void call_convert_to_uninitialized_fn(const GVArray &from, + const fn::MultiFunction &fn, + const IndexMask mask, + GMutableSpan to) +{ + fn::MFParamsBuilder params{fn, from.size()}; + params.add_readonly_single_input(from); + params.add_uninitialized_single_output(to); + fn::MFContextBuilder context; + fn.call_auto(mask, params, context); +} + +static void call_convert_to_uninitialized_fn(const GVArray &from, + const fn::MultiFunction &fn, + GMutableSpan to) +{ + call_convert_to_uninitialized_fn(from, fn, IndexMask(from.size()), to); +} + void DataTypeConversions::convert_to_initialized_n(GSpan from_span, GMutableSpan to_span) const { const CPPType &from_type = from_span.type(); const CPPType &to_type = to_span.type(); + BLI_assert(from_span.size() == to_span.size()); BLI_assert(this->is_convertible(from_type, to_type)); + const fn::MultiFunction *fn = this->get_conversion_multi_function( MFDataType::ForSingle(from_type), MFDataType::ForSingle(to_type)); - fn::MFParamsBuilder params{*fn, from_span.size()}; - params.add_readonly_single_input(from_span); + to_type.destruct_n(to_span.data(), to_span.size()); - params.add_uninitialized_single_output(to_span); - fn::MFContextBuilder context; - fn->call_auto(IndexRange(from_span.size()), params, context); + call_convert_to_uninitialized_fn(GVArray::ForSpan(from_span), *fn, to_span); } class GVArray_For_ConvertedGVArray : public GVArrayImpl { @@ -414,6 +432,20 @@ class GVArray_For_ConvertedGVArray : public GVArrayImpl { old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); from_type_.destruct(buffer); } + + void materialize(const IndexMask mask, void *dst) const override + { + type_->destruct_n(dst, mask.min_array_size()); + this->materialize_to_uninitialized(mask, dst); + } + + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override + { + call_convert_to_uninitialized_fn(varray_, + *old_to_new_conversions_.multi_function, + mask, + {this->type(), dst, mask.min_array_size()}); + } }; class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArrayImpl { @@ -458,6 +490,20 @@ class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArrayImpl { new_to_old_conversions_.convert_single_to_uninitialized(value, buffer); varray_.set_by_relocate(index, buffer); } + + void materialize(const IndexMask mask, void *dst) const override + { + type_->destruct_n(dst, mask.min_array_size()); + this->materialize_to_uninitialized(mask, dst); + } + + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override + { + call_convert_to_uninitialized_fn(varray_, + *old_to_new_conversions_.multi_function, + mask, + {this->type(), dst, mask.min_array_size()}); + } }; GVArray DataTypeConversions::try_convert(GVArray varray, const CPPType &to_type) const @@ -495,9 +541,8 @@ fn::GField DataTypeConversions::try_convert(fn::GField field, const CPPType &to_ if (!this->is_convertible(from_type, to_type)) { return {}; } - const fn::MultiFunction &fn = - *bke::get_implicit_type_conversions().get_conversion_multi_function( - fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type)); + const fn::MultiFunction &fn = *this->get_conversion_multi_function( + fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type)); return {std::make_shared<fn::FieldOperation>(fn, Vector<fn::GField>{std::move(field)})}; } diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c index b31632f0234..f7ea4c81fbf 100644 --- a/source/blender/blenkernel/intern/unit.c +++ b/source/blender/blenkernel/intern/unit.c @@ -845,8 +845,8 @@ static bool unit_distribute_negatives(char *str, const int len_max) bool changed = false; char *remaining_str = str; - int remaining_str_len = len_max; while ((remaining_str = find_next_negative(str, remaining_str)) != NULL) { + int remaining_str_len; /* Exit early in the unlikely situation that we've run out of length to add the parentheses. */ remaining_str_len = len_max - (int)(remaining_str - str); if (remaining_str_len <= 2) { @@ -1025,6 +1025,16 @@ static bool unit_find(const char *str, const bUnitDef *unit) return false; } +static const bUnitDef *unit_find_in_collection(const bUnitCollection *usys, const char *str) +{ + for (const bUnitDef *unit = usys->units; unit->name; unit++) { + if (unit_find(str, unit)) { + return unit; + } + } + return NULL; +} + /** * Try to find a default unit from current or previous string. * This allows us to handle cases like 2 + 2mm, people would expect to get 4mm, not 2.002m! @@ -1035,25 +1045,15 @@ static const bUnitDef *unit_detect_from_str(const bUnitCollection *usys, const char *str, const char *str_prev) { - const bUnitDef *unit = NULL; - /* See which units the new value has. */ - for (unit = usys->units; unit->name; unit++) { - if (unit_find(str, unit)) { - break; - } - } + const bUnitDef *unit = unit_find_in_collection(usys, str); /* Else, try to infer the default unit from the previous string. */ - if (str_prev && (unit == NULL || unit->name == NULL)) { + if (str_prev && (unit == NULL)) { /* See which units the original value had. */ - for (unit = usys->units; unit->name; unit++) { - if (unit_find(str_prev, unit)) { - break; - } - } + unit = unit_find_in_collection(usys, str_prev); } /* Else, fall back to default unit. */ - if (unit == NULL || unit->name == NULL) { + if (unit == NULL) { unit = unit_default(usys); } @@ -1067,11 +1067,8 @@ bool BKE_unit_string_contains_unit(const char *str, int type) if (!is_valid_unit_collection(usys)) { continue; } - - for (int i = 0; i < usys->length; i++) { - if (unit_find(str, usys->units + i)) { - return true; - } + if (unit_find_in_collection(usys, str)) { + return true; } } return false; @@ -1155,13 +1152,12 @@ bool BKE_unit_replace_string( */ { char *str_found = str; - const char *ch = str; while ((str_found = strchr(str_found, SEP_CHR))) { bool op_found = false; /* Any operators after this? */ - for (ch = str_found + 1; *ch != '\0'; ch++) { + for (const char *ch = str_found + 1; *ch != '\0'; ch++) { if (ELEM(*ch, ' ', '\t')) { continue; } diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.c index 0265dd037b1..88e7db1fe6c 100644 --- a/source/blender/blenkernel/intern/workspace.c +++ b/source/blender/blenkernel/intern/workspace.c @@ -456,12 +456,12 @@ WorkSpaceLayout *BKE_workspace_layout_iter_circular(const WorkSpace *workspace, WorkSpaceLayout *iter_layout; if (iter_backward) { - LISTBASE_CIRCULAR_BACKWARD_BEGIN (&workspace->layouts, iter_layout, start) { + LISTBASE_CIRCULAR_BACKWARD_BEGIN (WorkSpaceLayout *, &workspace->layouts, iter_layout, start) { if (!callback(iter_layout, arg)) { return iter_layout; } } - LISTBASE_CIRCULAR_BACKWARD_END(&workspace->layouts, iter_layout, start); + LISTBASE_CIRCULAR_BACKWARD_END(WorkSpaceLayout *, &workspace->layouts, iter_layout, start); } else { LISTBASE_CIRCULAR_FORWARD_BEGIN (&workspace->layouts, iter_layout, start) { diff --git a/source/blender/blenkernel/nla_private.h b/source/blender/blenkernel/nla_private.h index 41d1eef733c..c6fbdcc542c 100644 --- a/source/blender/blenkernel/nla_private.h +++ b/source/blender/blenkernel/nla_private.h @@ -128,7 +128,7 @@ typedef struct NlaEvalData { int num_channels; NlaEvalSnapshot base_snapshot; - /* Evaluation result shapshot. */ + /* Evaluation result snapshot. */ NlaEvalSnapshot eval_snapshot; } NlaEvalData; |