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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Eagar <joeedh@gmail.com>2022-09-24 23:38:38 +0300
committerJoseph Eagar <joeedh@gmail.com>2022-09-24 23:38:38 +0300
commit6637ad543241211bd49a02bcc83f03eef4f19584 (patch)
treea54ccdbde87f1cf5926d073cf1f36062c2917047 /source/blender/blenkernel
parent6482e092d06ee1ab862f9e98ddccbe8c23fb2bb0 (diff)
parent2ff5d42cd3b41cc1412d4a896d8f9e8d2977686f (diff)
Merge branch 'master' into temp-pbvh-vbos
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h3
-rw-r--r--source/blender/blenkernel/BKE_attribute.hh49
-rw-r--r--source/blender/blenkernel/BKE_attribute_math.hh122
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h4
-rw-r--r--source/blender/blenkernel/BKE_curves.hh23
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh20
-rw-r--r--source/blender/blenkernel/BKE_customdata.h7
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h2
-rw-r--r--source/blender/blenkernel/BKE_geometry_set.hh49
-rw-r--r--source/blender/blenkernel/BKE_global.h2
-rw-r--r--source/blender/blenkernel/BKE_idprop.h2
-rw-r--r--source/blender/blenkernel/BKE_idprop.hh6
-rw-r--r--source/blender/blenkernel/BKE_key.h2
-rw-r--r--source/blender/blenkernel/BKE_lib_id.h32
-rw-r--r--source/blender/blenkernel/BKE_lib_remap.h8
-rw-r--r--source/blender/blenkernel/BKE_main.h6
-rw-r--r--source/blender/blenkernel/BKE_mball.h2
-rw-r--r--source/blender/blenkernel/BKE_mesh.h17
-rw-r--r--source/blender/blenkernel/BKE_mesh_legacy_convert.h28
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h1
-rw-r--r--source/blender/blenkernel/BKE_nla.h2
-rw-r--r--source/blender/blenkernel/BKE_node.h14
-rw-r--r--source/blender/blenkernel/BKE_node_runtime.hh20
-rw-r--r--source/blender/blenkernel/BKE_paint.h165
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h4
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h2
-rw-r--r--source/blender/blenkernel/BKE_screen.h2
-rw-r--r--source/blender/blenkernel/BKE_spline.hh688
-rw-r--r--source/blender/blenkernel/BKE_subdiv.h1
-rw-r--r--source/blender/blenkernel/CMakeLists.txt11
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc4
-rw-r--r--source/blender/blenkernel/intern/action.c2
-rw-r--r--source/blender/blenkernel/intern/anim_data.c14
-rw-r--r--source/blender/blenkernel/intern/appdir.c2
-rw-r--r--source/blender/blenkernel/intern/armature.c2
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc14
-rw-r--r--source/blender/blenkernel/intern/attribute_access_intern.hh40
-rw-r--r--source/blender/blenkernel/intern/brush.cc1
-rw-r--r--source/blender/blenkernel/intern/camera.c6
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c1
-rw-r--r--source/blender/blenkernel/intern/constraint.c9
-rw-r--r--source/blender/blenkernel/intern/curve.cc4
-rw-r--r--source/blender/blenkernel/intern/curve_catmull_rom.cc14
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc587
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc5
-rw-r--r--source/blender/blenkernel/intern/curves_utils.cc15
-rw-r--r--source/blender/blenkernel/intern/customdata.cc37
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c60
-rw-r--r--source/blender/blenkernel/intern/displist.cc2
-rw-r--r--source/blender/blenkernel/intern/fluid.c105
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curve.cc1464
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc55
-rw-r--r--source/blender/blenkernel/intern/geometry_component_mesh.cc30
-rw-r--r--source/blender/blenkernel/intern/gpencil_modifier.c2
-rw-r--r--source/blender/blenkernel/intern/idprop_create.cc2
-rw-r--r--source/blender/blenkernel/intern/image.cc15
-rw-r--r--source/blender/blenkernel/intern/image_gen.c2
-rw-r--r--source/blender/blenkernel/intern/ipo.c4
-rw-r--r--source/blender/blenkernel/intern/lib_id.c8
-rw-r--r--source/blender/blenkernel/intern/lib_id_delete.c4
-rw-r--r--source/blender/blenkernel/intern/lib_override.cc6
-rw-r--r--source/blender/blenkernel/intern/lib_remap.c2
-rw-r--r--source/blender/blenkernel/intern/mask.c2
-rw-r--r--source/blender/blenkernel/intern/mball_tessellate.c1
-rw-r--r--source/blender/blenkernel/intern/mesh.cc37
-rw-r--r--source/blender/blenkernel/intern/mesh_boolean_convert.cc13
-rw-r--r--source/blender/blenkernel/intern/mesh_calc_edges.cc27
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc2
-rw-r--r--source/blender/blenkernel/intern/mesh_debug.cc13
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.cc127
-rw-r--r--source/blender/blenkernel/intern/mesh_legacy_convert.cc165
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.cc (renamed from source/blender/blenkernel/intern/mesh_mapping.c)110
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc35
-rw-r--r--source/blender/blenkernel/intern/mesh_runtime.cc34
-rw-r--r--source/blender/blenkernel/intern/mesh_sample.cc21
-rw-r--r--source/blender/blenkernel/intern/multires.c2
-rw-r--r--source/blender/blenkernel/intern/multires_reshape.h2
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_smooth.c16
-rw-r--r--source/blender/blenkernel/intern/multires_reshape_util.c3
-rw-r--r--source/blender/blenkernel/intern/nla.c5
-rw-r--r--source/blender/blenkernel/intern/node.cc44
-rw-r--r--source/blender/blenkernel/intern/node_runtime.cc48
-rw-r--r--source/blender/blenkernel/intern/node_tree_update.cc17
-rw-r--r--source/blender/blenkernel/intern/object.cc64
-rw-r--r--source/blender/blenkernel/intern/object_deform.c8
-rw-r--r--source/blender/blenkernel/intern/object_dupli.cc9
-rw-r--r--source/blender/blenkernel/intern/paint.cc646
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c2
-rw-r--r--source/blender/blenkernel/intern/pbvh.c7
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c12
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c2
-rw-r--r--source/blender/blenkernel/intern/scene.cc6
-rw-r--r--source/blender/blenkernel/intern/screen.c4
-rw-r--r--source/blender/blenkernel/intern/sound.c11
-rw-r--r--source/blender/blenkernel/intern/spline_base.cc526
-rw-r--r--source/blender/blenkernel/intern/spline_bezier.cc646
-rw-r--r--source/blender/blenkernel/intern/spline_nurbs.cc395
-rw-r--r--source/blender/blenkernel/intern/spline_poly.cc97
-rw-r--r--source/blender/blenkernel/intern/subdiv_converter_mesh.c9
-rw-r--r--source/blender/blenkernel/intern/subdiv_mesh.cc8
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c7
-rw-r--r--source/blender/blenkernel/intern/vfont.c2
-rw-r--r--source/blender/blenkernel/intern/workspace.cc (renamed from source/blender/blenkernel/intern/workspace.c)146
103 files changed, 1953 insertions, 5190 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index da1e45ababd..cb9c4256e33 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -104,9 +104,6 @@ struct DerivedMesh {
int num_alloc;
} looptris;
- /* use for converting to BMesh which doesn't store bevel weight and edge crease by default */
- char cd_flag;
-
short tangent_mask; /* which tangent layers are calculated */
/** Loop tessellation cache (WARNING! Only call inside threading-protected code!) */
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
index fbdacee139c..7b13b8a2b09 100644
--- a/source/blender/blenkernel/BKE_attribute.hh
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -16,6 +16,10 @@
struct Mesh;
struct PointCloud;
+namespace blender::fn {
+class MultiFunction;
+class GField;
+} // namespace blender::fn
namespace blender::bke {
@@ -163,6 +167,27 @@ template<typename T> struct AttributeReader {
};
/**
+ * A utility to make sure attribute values are valid, for attributes like "material_index" which
+ * can only be positive, or attributes that represent enum options. This is usually only necessary
+ * when writing attributes from an untrusted/arbitrary user input.
+ */
+struct AttributeValidator {
+ /**
+ * Single input, single output function that corrects attribute values if necessary.
+ */
+ const fn::MultiFunction *function;
+
+ operator bool() const
+ {
+ return this->function != nullptr;
+ }
+ /**
+ * Return a field that creates corrected attribute values.
+ */
+ fn::GField validate_field_if_necessary(const fn::GField &field) const;
+};
+
+/**
* 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.
@@ -239,7 +264,9 @@ template<typename T> struct SpanAttributeWriter {
*/
void finish()
{
- this->span.save();
+ if (this->span.varray()) {
+ this->span.save();
+ }
if (this->tag_modified_fn) {
this->tag_modified_fn();
}
@@ -314,7 +341,9 @@ struct GSpanAttributeWriter {
void finish()
{
- this->span.save();
+ if (this->span.varray()) {
+ this->span.save();
+ }
if (this->tag_modified_fn) {
this->tag_modified_fn();
}
@@ -343,7 +372,7 @@ struct AttributeAccessorFunctions {
eAttrDomain to_domain);
bool (*for_all)(const void *owner,
FunctionRef<bool(const AttributeIDRef &, const AttributeMetaData &)> fn);
-
+ AttributeValidator (*lookup_validator)(const void *owner, const AttributeIDRef &attribute_id);
GAttributeWriter (*lookup_for_write)(void *owner, const AttributeIDRef &attribute_id);
bool (*remove)(void *owner, const AttributeIDRef &attribute_id);
bool (*add)(void *owner,
@@ -498,6 +527,14 @@ class AttributeAccessor {
}
/**
+ * Same as the generic version above, but should be used when the type is known at compile time.
+ */
+ AttributeValidator lookup_validator(const AttributeIDRef &attribute_id) const
+ {
+ return fn_->lookup_validator(owner_, attribute_id);
+ }
+
+ /**
* Interpolate data from one domain to another.
*/
GVArray adapt_domain(const GVArray &varray,
@@ -659,6 +696,8 @@ class MutableAttributeAccessor : public AttributeAccessor {
* The "only" in the name indicates that the caller should not read existing values from the
* span. If the attribute is not stored as span internally, the existing values won't be copied
* over to the span.
+ *
+ * For trivial types, the values in a newly created attribute will not be initialized.
*/
GSpanAttributeWriter lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id,
const eAttrDomain domain,
@@ -671,7 +710,9 @@ class MutableAttributeAccessor : public AttributeAccessor {
SpanAttributeWriter<T> lookup_or_add_for_write_only_span(const AttributeIDRef &attribute_id,
const eAttrDomain domain)
{
- AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>(attribute_id, domain);
+ AttributeWriter<T> attribute = this->lookup_or_add_for_write<T>(
+ attribute_id, domain, AttributeInitConstruct());
+
if (attribute) {
return SpanAttributeWriter<T>{std::move(attribute), false};
}
diff --git a/source/blender/blenkernel/BKE_attribute_math.hh b/source/blender/blenkernel/BKE_attribute_math.hh
index 770937688d7..abd8b33b260 100644
--- a/source/blender/blenkernel/BKE_attribute_math.hh
+++ b/source/blender/blenkernel/BKE_attribute_math.hh
@@ -46,6 +46,58 @@ inline void convert_to_static_type(const eCustomDataType data_type, const Func &
}
/* -------------------------------------------------------------------- */
+/** \name Mix two values of the same type.
+ *
+ * This is just basic linear interpolation.
+ * \{ */
+
+template<typename T> T mix2(float factor, const T &a, const T &b);
+
+template<> inline bool mix2(const float factor, const bool &a, const bool &b)
+{
+ return ((1.0f - factor) * a + factor * b) >= 0.5f;
+}
+
+template<> inline int8_t mix2(const float factor, const int8_t &a, const int8_t &b)
+{
+ return static_cast<int8_t>(std::round((1.0f - factor) * a + factor * b));
+}
+
+template<> inline int mix2(const float factor, const int &a, const int &b)
+{
+ return static_cast<int>(std::round((1.0f - factor) * a + factor * b));
+}
+
+template<> inline float mix2(const float factor, const float &a, const float &b)
+{
+ return (1.0f - factor) * a + factor * b;
+}
+
+template<> inline float2 mix2(const float factor, const float2 &a, const float2 &b)
+{
+ return math::interpolate(a, b, factor);
+}
+
+template<> inline float3 mix2(const float factor, const float3 &a, const float3 &b)
+{
+ return math::interpolate(a, b, factor);
+}
+
+template<>
+inline ColorGeometry4f mix2(const float factor, const ColorGeometry4f &a, const ColorGeometry4f &b)
+{
+ return math::interpolate(a, b, factor);
+}
+
+template<>
+inline ColorGeometry4b mix2(const float factor, const ColorGeometry4b &a, const ColorGeometry4b &b)
+{
+ return math::interpolate(a, b, factor);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Mix three values of the same type.
*
* This is typically used to interpolate values within a triangle.
@@ -117,53 +169,85 @@ inline ColorGeometry4b mix3(const float3 &weights,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Mix two values of the same type.
+/** \name Mix four values of the same type.
*
- * This is just basic linear interpolation.
* \{ */
-template<typename T> T mix2(float factor, const T &a, const T &b);
+template<typename T>
+T mix4(const float4 &weights, const T &v0, const T &v1, const T &v2, const T &v3);
-template<> inline bool mix2(const float factor, const bool &a, const bool &b)
+template<>
+inline int8_t mix4(
+ const float4 &weights, const int8_t &v0, const int8_t &v1, const int8_t &v2, const int8_t &v3)
{
- return ((1.0f - factor) * a + factor * b) >= 0.5f;
+ return static_cast<int8_t>(
+ std::round(weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3));
}
-template<> inline int8_t mix2(const float factor, const int8_t &a, const int8_t &b)
+template<>
+inline bool mix4(
+ const float4 &weights, const bool &v0, const bool &v1, const bool &v2, const bool &v3)
{
- return static_cast<int8_t>(std::round((1.0f - factor) * a + factor * b));
+ return (weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3) >= 0.5f;
}
-template<> inline int mix2(const float factor, const int &a, const int &b)
+template<>
+inline int mix4(const float4 &weights, const int &v0, const int &v1, const int &v2, const int &v3)
{
- return static_cast<int>(std::round((1.0f - factor) * a + factor * b));
+ return static_cast<int>(
+ std::round(weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3));
}
-template<> inline float mix2(const float factor, const float &a, const float &b)
+template<>
+inline float mix4(
+ const float4 &weights, const float &v0, const float &v1, const float &v2, const float &v3)
{
- return (1.0f - factor) * a + factor * b;
+ return weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3;
}
-template<> inline float2 mix2(const float factor, const float2 &a, const float2 &b)
+template<>
+inline float2 mix4(
+ const float4 &weights, const float2 &v0, const float2 &v1, const float2 &v2, const float2 &v3)
{
- return math::interpolate(a, b, factor);
+ return weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3;
}
-template<> inline float3 mix2(const float factor, const float3 &a, const float3 &b)
+template<>
+inline float3 mix4(
+ const float4 &weights, const float3 &v0, const float3 &v1, const float3 &v2, const float3 &v3)
{
- return math::interpolate(a, b, factor);
+ return weights.x * v0 + weights.y * v1 + weights.z * v2 + weights.w * v3;
}
template<>
-inline ColorGeometry4f mix2(const float factor, const ColorGeometry4f &a, const ColorGeometry4f &b)
+inline ColorGeometry4f mix4(const float4 &weights,
+ const ColorGeometry4f &v0,
+ const ColorGeometry4f &v1,
+ const ColorGeometry4f &v2,
+ const ColorGeometry4f &v3)
{
- return math::interpolate(a, b, factor);
+ ColorGeometry4f result;
+ interp_v4_v4v4v4v4(result, v0, v1, v2, v3, weights);
+ return result;
}
template<>
-inline ColorGeometry4b mix2(const float factor, const ColorGeometry4b &a, const ColorGeometry4b &b)
+inline ColorGeometry4b mix4(const float4 &weights,
+ const ColorGeometry4b &v0,
+ const ColorGeometry4b &v1,
+ const ColorGeometry4b &v2,
+ const ColorGeometry4b &v3)
{
- return math::interpolate(a, b, factor);
+ const float4 v0_f{&v0.r};
+ const float4 v1_f{&v1.r};
+ const float4 v2_f{&v2.r};
+ const float4 v3_f{&v3.r};
+ float4 mixed;
+ interp_v4_v4v4v4v4(mixed, v0_f, v1_f, v2_f, v3_f, weights);
+ return ColorGeometry4b{static_cast<uint8_t>(mixed[0]),
+ static_cast<uint8_t>(mixed[1]),
+ static_cast<uint8_t>(mixed[2]),
+ static_cast<uint8_t>(mixed[3])};
}
/** \} */
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index ee9c7a964d9..46d6c97e1ff 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -30,8 +30,8 @@ extern "C" {
/* 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
* was written with too new a version. */
-#define BLENDER_FILE_MIN_VERSION 300
-#define BLENDER_FILE_MIN_SUBVERSION 43
+#define BLENDER_FILE_MIN_VERSION 304
+#define BLENDER_FILE_MIN_SUBVERSION 0
/** User readable version string. */
const char *BKE_blender_version_string(void);
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 9f150c13d6e..0d67152dec8 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -218,7 +218,7 @@ class CurvesGeometry : public ::CurvesGeometry {
/**
* How many evaluated points to create for each segment when evaluating Bezier,
- * Catmull Rom, and NURBS curves. On the curve domain.
+ * Catmull Rom, and NURBS curves. On the curve domain. Values must be one or greater.
*/
VArray<int> resolution() const;
/** Mutable access to curve resolution. Call #tag_topology_changed after changes. */
@@ -709,7 +709,7 @@ void interpolate_to_evaluated(const GSpan src,
const Span<int> evaluated_offsets,
GMutableSpan dst);
-void calculate_basis(const float parameter, float r_weights[4]);
+void calculate_basis(const float parameter, float4 &r_weights);
/**
* Interpolate the control point values for the given parameter on the piecewise segment.
@@ -720,22 +720,15 @@ void calculate_basis(const float parameter, float r_weights[4]);
template<typename T>
T interpolate(const T &a, const T &b, const T &c, const T &d, const float parameter)
{
- float n[4];
+ BLI_assert(0.0f <= parameter && parameter <= 1.0f);
+ float4 n;
calculate_basis(parameter, n);
- /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify
- * supporting more types. */
- if constexpr (!is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) {
- T return_value;
- attribute_math::DefaultMixer<T> mixer({&return_value, 1});
- mixer.mix_in(0, a, n[0] * 0.5f);
- mixer.mix_in(0, b, n[1] * 0.5f);
- mixer.mix_in(0, c, n[2] * 0.5f);
- mixer.mix_in(0, d, n[3] * 0.5f);
- mixer.finalize();
- return return_value;
+ if constexpr (is_same_any_v<T, float, float2, float3>) {
+ /* Save multiplications by adjusting weights after mix. */
+ return 0.5f * attribute_math::mix4<T>(n, a, b, c, d);
}
else {
- return 0.5f * (a * n[0] + b * n[1] + c * n[2] + d * n[3]);
+ return attribute_math::mix4<T>(n * 0.5f, a, b, c, d);
}
}
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
index 7d81847f4c1..f9155023db7 100644
--- a/source/blender/blenkernel/BKE_curves_utils.hh
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -326,8 +326,8 @@ void copy_point_data(const CurvesGeometry &src_curves,
template<typename T>
void copy_point_data(const CurvesGeometry &src_curves,
const CurvesGeometry &dst_curves,
- const IndexMask src_curve_selection,
- const Span<T> src,
+ IndexMask src_curve_selection,
+ Span<T> src,
MutableSpan<T> dst)
{
copy_point_data(src_curves, dst_curves, src_curve_selection, GSpan(src), GMutableSpan(dst));
@@ -340,13 +340,27 @@ void fill_points(const CurvesGeometry &curves,
template<typename T>
void fill_points(const CurvesGeometry &curves,
- const IndexMask curve_selection,
+ IndexMask curve_selection,
const T &value,
MutableSpan<T> dst)
{
fill_points(curves, curve_selection, &value, dst);
}
+void fill_points(const CurvesGeometry &curves,
+ Span<IndexRange> curve_ranges,
+ GPointer value,
+ GMutableSpan dst);
+
+template<typename T>
+void fill_points(const CurvesGeometry &curves,
+ Span<IndexRange> curve_ranges,
+ const T &value,
+ MutableSpan<T> dst)
+{
+ fill_points(curves, curve_ranges, &value, dst);
+}
+
/**
* Copy only the information on the point domain, but not the offsets or any point attributes,
* meant for operations that change the number of points but not the number of curves.
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 5e313443dac..0e172abd9a2 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -137,7 +137,7 @@ void CustomData_data_add(int type, void *data1, const void *data2);
/**
* Initializes a CustomData object with the same layer setup as source.
- * mask is a bitfield where `(mask & (1 << (layer type)))` indicates
+ * mask is a bit-field where `(mask & (1 << (layer type)))` indicates
* if a layer should be copied or not. alloctype must be one of the above.
*/
void CustomData_copy(const struct CustomData *source,
@@ -635,8 +635,7 @@ enum {
CD_SHAPEKEY, /* Not available as real CD layer in non-bmesh context. */
/* Edges. */
- CD_FAKE_SEAM = CD_FAKE | 100, /* UV seam flag for edges. */
- CD_FAKE_CREASE = CD_FAKE | CD_CREASE, /* *sigh*. */
+ CD_FAKE_SEAM = CD_FAKE | 100, /* UV seam flag for edges. */
/* Multiple types of mesh elements... */
CD_FAKE_UV = CD_FAKE |
@@ -741,6 +740,8 @@ void CustomData_blend_write(BlendWriter *writer,
void CustomData_blend_read(struct BlendDataReader *reader, struct CustomData *data, int count);
+size_t CustomData_get_elem_size(struct CustomDataLayer *layer);
+
#ifndef NDEBUG
struct DynStr;
/** Use to inspect mesh data when debugging. */
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index c5788c07336..c11e6353bc0 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -106,7 +106,7 @@ typedef enum eFMI_Action_Types {
/* Flags for the requirements of a FModifier Type */
typedef enum eFMI_Requirement_Flags {
- /* modifier requires original data-points (kindof beats the purpose of a modifier stack?) */
+ /* modifier requires original data-points (kind of beats the purpose of a modifier stack?) */
FMI_REQUIRES_ORIGINAL_DATA = (1 << 0),
/* modifier doesn't require on any preceding data (i.e. it will generate a curve).
* Use in conjunction with FMI_TYPE_GENRATE_CURVE
diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh
index a5c4d5e1365..2ef9556afc7 100644
--- a/source/blender/blenkernel/BKE_geometry_set.hh
+++ b/source/blender/blenkernel/BKE_geometry_set.hh
@@ -26,7 +26,6 @@
struct Curves;
struct Collection;
struct Curve;
-struct CurveEval;
struct Mesh;
struct Object;
struct PointCloud;
@@ -465,46 +464,7 @@ class PointCloudComponent : public GeometryComponent {
};
/**
- * Legacy runtime-only curves type.
- * These curves are stored differently than other geometry components, because the data structure
- * used here does not correspond exactly to the #Curve DNA data structure. A #CurveEval is stored
- * here instead, though the component does give access to a #Curve for interfacing with render
- * engines and other areas of Blender that expect to use a data-block with an #ID.
- */
-class CurveComponentLegacy : public GeometryComponent {
- private:
- CurveEval *curve_ = nullptr;
- GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
-
- public:
- CurveComponentLegacy();
- ~CurveComponentLegacy();
- GeometryComponent *copy() const override;
-
- void clear();
- bool has_curve() const;
- /**
- * Clear the component and replace it with the new curve.
- */
- void replace(CurveEval *curve, GeometryOwnershipType ownership = GeometryOwnershipType::Owned);
- CurveEval *release();
-
- const CurveEval *get_for_read() const;
- CurveEval *get_for_write();
-
- bool is_empty() const final;
-
- bool owns_direct_data() const override;
- void ensure_owns_direct_data() override;
-
- std::optional<blender::bke::AttributeAccessor> attributes() const final;
- std::optional<blender::bke::MutableAttributeAccessor> attributes_for_write() final;
-
- static constexpr inline GeometryComponentType static_type = GEO_COMPONENT_TYPE_CURVE;
-};
-
-/**
- * A geometry component that stores a group of curves, corresponding the #Curves data-block type
+ * A geometry component that stores a group of curves, corresponding the #Curves data-block
* and the #CurvesGeometry type. Attributes are stored on the control point domain and the
* curve domain.
*/
@@ -514,10 +474,9 @@ class CurveComponent : public GeometryComponent {
GeometryOwnershipType ownership_ = GeometryOwnershipType::Owned;
/**
- * Curve data necessary to hold the draw cache for rendering, consistent over multiple redraws.
- * This is necessary because Blender assumes that objects evaluate to an object data type, and
- * we use #CurveEval rather than #Curve here. It also allows us to mostly reuse the same
- * batch cache implementation.
+ * Because rendering #Curves isn't fully working yet, we must provide a #Curve for the render
+ * engine and depsgraph object iterator in some cases. This allows using the old curve rendering
+ * even when the new curve data structure is used.
*/
mutable Curve *curve_for_render_ = nullptr;
mutable std::mutex curve_for_render_mutex_;
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index 96b6f7a53b0..e28c87cd7d6 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -80,7 +80,7 @@ typedef struct Global {
* * -1: Disable faster motion paths computation (since 08/2018).
* * 1 - 30: EEVEE debug/stats values (01/2018).
* * 31: Enable the Select Debug Engine. Only available with #WITH_DRAW_DEBUG (08/2021).
- * * 101: Enable UI debug drawing of fullscreen area's corner widget (10/2014).
+ * * 101: Enable UI debug drawing of full-screen area's corner widget (10/2014).
* * 102: Enable extra items in string search UI (05/2022).
* * 666: Use quicker batch delete for outliners' delete hierarchy (01/2019).
* * 777: Enable UI node panel's sockets polling (11/2011).
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index e9b075aeb49..9ac4b4e4619 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -328,7 +328,7 @@ typedef enum eIDPropertyUIDataType {
IDP_UI_DATA_TYPE_UNSUPPORTED = -1,
/** IDP_INT or IDP_ARRAY with subtype IDP_INT. */
IDP_UI_DATA_TYPE_INT = 0,
- /** IDP_FLOAT and IDP_DOUBLE or IDP_ARRAY properties with a float or double subtypes. */
+ /** IDP_FLOAT and IDP_DOUBLE or IDP_ARRAY properties with a float or double sub-types. */
IDP_UI_DATA_TYPE_FLOAT = 1,
/** IDP_STRING properties. */
IDP_UI_DATA_TYPE_STRING = 2,
diff --git a/source/blender/blenkernel/BKE_idprop.hh b/source/blender/blenkernel/BKE_idprop.hh
index 6a42ab1669f..e8ac4119970 100644
--- a/source/blender/blenkernel/BKE_idprop.hh
+++ b/source/blender/blenkernel/BKE_idprop.hh
@@ -49,7 +49,7 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name,
std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, ID *id);
/**
- * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_INT.
+ * \brief Allocate a new IDProperty of type IDP_ARRAY and sub-type IDP_INT.
*
* \param values: The values will be copied into the IDProperty.
*/
@@ -57,14 +57,14 @@ std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name,
Span<int32_t> values);
/**
- * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_FLOAT.
+ * \brief Allocate a new IDProperty of type IDP_ARRAY and sub-type IDP_FLOAT.
*
* \param values: The values will be copied into the IDProperty.
*/
std::unique_ptr<IDProperty, IDPropertyDeleter> create(StringRefNull prop_name, Span<float> values);
/**
- * \brief Allocate a new IDProperty of type IDP_ARRAY and subtype IDP_DOUBLE.
+ * \brief Allocate a new IDProperty of type IDP_ARRAY and sub-type IDP_DOUBLE.
*
* \param values: The values will be copied into the IDProperty.
*/
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 45a72e8d7a3..0fe351c0aa4 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -22,7 +22,7 @@ extern "C" {
#endif
/**
- * Free (or release) any data used by this shapekey (does not free the key itself).
+ * Free (or release) any data used by this shape-key (does not free the key itself).
*/
void BKE_key_free_data(struct Key *key);
void BKE_key_free_nolib(struct Key *key);
diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h
index e5b013ce201..aa3bdb502f8 100644
--- a/source/blender/blenkernel/BKE_lib_id.h
+++ b/source/blender/blenkernel/BKE_lib_id.h
@@ -77,19 +77,19 @@ void BKE_libblock_runtime_reset_remapping_status(struct ID *id) ATTR_NONNULL(1);
/* *** ID's session_uuid management. *** */
/**
- * When an ID's uuid is of that value, it is unset/invalid (e.g. for runtime IDs, etc.).
+ * When an ID's UUID is of that value, it is unset/invalid (e.g. for runtime IDs, etc.).
*/
#define MAIN_ID_SESSION_UUID_UNSET 0
/**
- * Generate a session-wise uuid for the given \a id.
+ * Generate a session-wise UUID for the given \a id.
*
* \note "session-wise" here means while editing a given .blend file. Once a new .blend file is
- * loaded or created, undo history is cleared/reset, and so is the uuid counter.
+ * loaded or created, undo history is cleared/reset, and so is the UUID counter.
*/
void BKE_lib_libblock_session_uuid_ensure(struct ID *id);
/**
- * Re-generate a new session-wise uuid for the given \a id.
+ * Re-generate a new session-wise UUID for the given \a id.
*
* \warning This has a few very specific use-cases, no other usage is expected currently:
* - To handle UI-related data-blocks that are kept across new file reading, when we do keep
@@ -117,14 +117,14 @@ void *BKE_id_new_nomain(short type, const char *name);
*/
enum {
/* *** Generic options (should be handled by all ID types copying, ID creation, etc.). *** */
- /** Create datablock outside of any main database -
+ /** Create data-block outside of any main database -
* similar to 'localize' functions of materials etc. */
LIB_ID_CREATE_NO_MAIN = 1 << 0,
- /** Do not affect user refcount of datablocks used by new one
- * (which also gets zero usercount then).
+ /** Do not affect user refcount of data-blocks used by new one
+ * (which also gets zero user-count then).
* Implies LIB_ID_CREATE_NO_MAIN. */
LIB_ID_CREATE_NO_USER_REFCOUNT = 1 << 1,
- /** Assume given 'newid' already points to allocated memory for whole datablock
+ /** Assume given 'newid' already points to allocated memory for whole data-block
* (ID + data) - USE WITH CAUTION!
* Implies LIB_ID_CREATE_NO_MAIN. */
LIB_ID_CREATE_NO_ALLOCATE = 1 << 2,
@@ -150,7 +150,7 @@ enum {
LIB_ID_COPY_NO_PREVIEW = 1 << 17,
/** Copy runtime data caches. */
LIB_ID_COPY_CACHES = 1 << 18,
- /** Don't copy id->adt, used by ID data-block localization routines. */
+ /** Don't copy `id->adt`, used by ID data-block localization routines. */
LIB_ID_COPY_NO_ANIMDATA = 1 << 19,
/** Mesh: Reference CD data layers instead of doing real copy - USE WITH CAUTION! */
LIB_ID_COPY_CD_REFERENCE = 1 << 20,
@@ -239,12 +239,12 @@ enum {
/** Do not try to remove freed ID from given Main (passed Main may be NULL). */
LIB_ID_FREE_NO_MAIN = 1 << 0,
/**
- * Do not affect user refcount of datablocks used by freed one.
+ * Do not affect user refcount of data-blocks used by freed one.
* Implies LIB_ID_FREE_NO_MAIN.
*/
LIB_ID_FREE_NO_USER_REFCOUNT = 1 << 1,
/**
- * Assume freed ID datablock memory is managed elsewhere, do not free it
+ * Assume freed ID data-block memory is managed elsewhere, do not free it
* (still calls relevant ID type's freeing function though) - USE WITH CAUTION!
* Implies LIB_ID_FREE_NO_MAIN.
*/
@@ -254,7 +254,7 @@ enum {
LIB_ID_FREE_NO_DEG_TAG = 1 << 8,
/** Do not attempt to remove freed ID from UI data/notifiers/... */
LIB_ID_FREE_NO_UI_USER = 1 << 9,
- /** Do not remove freed ID's name from a potential runtime namemap. */
+ /** Do not remove freed ID's name from a potential runtime name-map. */
LIB_ID_FREE_NO_NAMEMAP_REMOVE = 1 << 10,
};
@@ -283,7 +283,7 @@ void BKE_libblock_free_data_py(struct ID *id);
* \param idv: Pointer to ID to be freed.
* \param flag: Set of \a LIB_ID_FREE_... flags controlling/overriding usual freeing process,
* 0 to get default safe behavior.
- * \param use_flag_from_idtag: Still use freeing info flags from given #ID datablock,
+ * \param use_flag_from_idtag: Still use freeing info flags from given #ID data-block,
* even if some overriding ones are passed in \a flag parameter.
*/
void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, bool use_flag_from_idtag);
@@ -300,7 +300,7 @@ void BKE_id_free(struct Main *bmain, void *idv);
/**
* Not really a freeing function by itself,
- * it decrements usercount of given id, and only frees it if it reaches 0.
+ * it decrements user-count of given id, and only frees it if it reaches 0.
*/
void BKE_id_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
@@ -316,12 +316,12 @@ void BKE_id_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
*
* \warning Considered experimental for now, seems to be working OK but this is
* risky code in a complicated area.
- * \return Number of deleted datablocks.
+ * \return Number of deleted data-blocks.
*/
size_t BKE_id_multi_tagged_delete(struct Main *bmain) ATTR_NONNULL();
/**
- * Add a 'NO_MAIN' data-block to given main (also sets usercounts of its IDs if needed).
+ * Add a 'NO_MAIN' data-block to given main (also sets user-counts of its IDs if needed).
*/
void BKE_libblock_management_main_add(struct Main *bmain, void *idv);
/** Remove a data-block from given main (set it to 'NO_MAIN' status). */
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h
index 37b626fb4da..a17ef8c7c5d 100644
--- a/source/blender/blenkernel/BKE_lib_remap.h
+++ b/source/blender/blenkernel/BKE_lib_remap.h
@@ -180,12 +180,12 @@ typedef enum IDRemapperApplyResult {
typedef enum IDRemapperApplyOptions {
/**
- * Update the user count of the old and new ID datablock.
+ * Update the user count of the old and new ID data-block.
*
* For remapping the old ID users will be decremented and the new ID users will be
* incremented. When un-assigning the old ID users will be decremented.
*
- * NOTE: Currently unused by main remapping code, since usercount is handled by
+ * NOTE: Currently unused by main remapping code, since user-count is handled by
* `foreach_libblock_remap_callback_apply` there, depending on whether the remapped pointer does
* use it or not. Need for rare cases in UI handling though (see e.g. `image_id_remap` in
* `space_image.c`).
@@ -193,14 +193,14 @@ typedef enum IDRemapperApplyOptions {
ID_REMAP_APPLY_UPDATE_REFCOUNT = (1 << 0),
/**
- * Make sure that the new ID datablock will have a 'real' user.
+ * Make sure that the new ID data-block will have a 'real' user.
*
* NOTE: See Note for #ID_REMAP_APPLY_UPDATE_REFCOUNT above.
*/
ID_REMAP_APPLY_ENSURE_REAL = (1 << 1),
/**
- * Unassign in stead of remap when the new ID datablock would become id_self.
+ * Unassign in stead of remap when the new ID data-block would become id_self.
*
* To use this option 'BKE_id_remapper_apply_ex' must be used with a not-null id_self parameter.
*/
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index b741489d929..0048ad4dde5 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -113,8 +113,10 @@ typedef struct Main {
char filepath[1024]; /* 1024 = FILE_MAX */
short versionfile, subversionfile; /* see BLENDER_FILE_VERSION, BLENDER_FILE_SUBVERSION */
short minversionfile, minsubversionfile;
- uint64_t build_commit_timestamp; /* commit's timestamp from buildinfo */
- char build_hash[16]; /* hash from buildinfo */
+ /** Commit timestamp from `buildinfo`. */
+ uint64_t build_commit_timestamp;
+ /** Commit Hash from `buildinfo`. */
+ char build_hash[16];
/** Indicate the #Main.filepath (file) is the recovered one. */
bool recovered;
/** All current ID's exist in the last memfile undo step. */
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 7d265ceb102..5ffaa13d9d2 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -88,7 +88,7 @@ void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
*/
struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, int type);
-/* *** select funcs *** */
+/* *** Select functions *** */
int BKE_mball_select_count(const struct MetaBall *mb);
int BKE_mball_select_count_multi(struct Base **bases, int bases_len);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index ef57c9a2e0e..de89abf9cf6 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -870,16 +870,7 @@ void BKE_mesh_merge_customdata_for_apply_modifier(struct Mesh *me);
*/
void BKE_mesh_flush_hidden_from_verts(struct Mesh *me);
void BKE_mesh_flush_hidden_from_polys(struct Mesh *me);
-/**
- * simple poly -> vert/edge selection.
- */
-void BKE_mesh_flush_select_from_polys_ex(struct MVert *mvert,
- int totvert,
- const struct MLoop *mloop,
- struct MEdge *medge,
- int totedge,
- const struct MPoly *mpoly,
- int totpoly);
+
void BKE_mesh_flush_select_from_polys(struct Mesh *me);
void BKE_mesh_flush_select_from_verts(struct Mesh *me);
@@ -1148,7 +1139,11 @@ inline blender::MutableSpan<MLoop> Mesh::loops_for_write()
inline blender::Span<MDeformVert> Mesh::deform_verts() const
{
- return {BKE_mesh_deform_verts(this), this->totvert};
+ const MDeformVert *dverts = BKE_mesh_deform_verts(this);
+ if (!dverts) {
+ return {};
+ }
+ return {dverts, this->totvert};
}
inline blender::MutableSpan<MDeformVert> Mesh::deform_verts_for_write()
{
diff --git a/source/blender/blenkernel/BKE_mesh_legacy_convert.h b/source/blender/blenkernel/BKE_mesh_legacy_convert.h
index e67aec0b9ce..d3e582ff197 100644
--- a/source/blender/blenkernel/BKE_mesh_legacy_convert.h
+++ b/source/blender/blenkernel/BKE_mesh_legacy_convert.h
@@ -18,6 +18,24 @@ struct Mesh;
struct MFace;
/**
+ * Move face sets to the legacy type from a generic type.
+ */
+void BKE_mesh_legacy_face_set_from_generic(struct Mesh *mesh);
+/**
+ * Copy face sets to the generic data type from the legacy type.
+ */
+void BKE_mesh_legacy_face_set_to_generic(struct Mesh *mesh);
+
+/**
+ * Copy edge creases from a separate layer into edges.
+ */
+void BKE_mesh_legacy_edge_crease_from_layers(struct Mesh *mesh);
+/**
+ * Copy edge creases from edges to a separate layer.
+ */
+void BKE_mesh_legacy_edge_crease_to_layers(struct Mesh *mesh);
+
+/**
* Copy bevel weights from separate layers into vertices and edges.
*/
void BKE_mesh_legacy_bevel_weight_from_layers(struct Mesh *mesh);
@@ -37,6 +55,16 @@ void BKE_mesh_legacy_convert_hide_layers_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_convert_flags_to_hide_layers(struct Mesh *mesh);
/**
+ * Convert the selected element attributes to the old flag format for writing.
+ */
+void BKE_mesh_legacy_convert_selection_layers_to_flags(struct Mesh *mesh);
+/**
+ * Convert the old selection flags (#SELECT/#ME_FACE_SEL) to the selected element attribute for
+ * reading. Only add the attributes when there are any elements in each domain selected.
+ */
+void BKE_mesh_legacy_convert_flags_to_selection_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);
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index cf9763d50a4..2ee50fbaaee 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -93,6 +93,7 @@ typedef struct MeshElemMap {
/* mapping */
UvVertMap *BKE_mesh_uv_vert_map_create(const struct MPoly *mpoly,
const bool *hide_poly,
+ const bool *select_poly,
const struct MLoop *mloop,
const struct MLoopUV *mloopuv,
unsigned int totpoly,
diff --git a/source/blender/blenkernel/BKE_nla.h b/source/blender/blenkernel/BKE_nla.h
index 2613f4286f0..9d3000759ab 100644
--- a/source/blender/blenkernel/BKE_nla.h
+++ b/source/blender/blenkernel/BKE_nla.h
@@ -7,7 +7,7 @@
* \ingroup bke
*/
-/* temp constant defined for these funcs only... */
+/** Temp constant defined for these functions only. */
#define NLASTRIP_MIN_LEN_THRESH 0.1f
#ifdef __cplusplus
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 55bf24f943e..14cf8164b79 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -477,7 +477,7 @@ struct bNodeTree *ntreeAddTreeEmbedded(struct Main *bmain,
const char *name,
const char *idname);
-/* copy/free funcs, need to manage ID users */
+/* Copy/free functions, need to manage ID users. */
/**
* Free (or release) any data used by this node-tree.
@@ -960,8 +960,8 @@ void nodeLabel(const struct bNodeTree *ntree, const struct bNode *node, char *la
*/
const char *nodeSocketLabel(const struct bNodeSocket *sock);
-bool nodeGroupPoll(struct bNodeTree *nodetree,
- struct bNodeTree *grouptree,
+bool nodeGroupPoll(const struct bNodeTree *nodetree,
+ const struct bNodeTree *grouptree,
const char **r_disabled_hint);
/**
@@ -1480,7 +1480,7 @@ struct TexResult;
#define GEO_NODE_ROTATE_INSTANCES 1122
#define GEO_NODE_SPLIT_EDGES 1123
#define GEO_NODE_MESH_TO_CURVE 1124
-#define GEO_NODE_TRANSFER_ATTRIBUTE 1125
+#define GEO_NODE_TRANSFER_ATTRIBUTE_DEPRECATED 1125
#define GEO_NODE_SUBDIVISION_SURFACE 1126
#define GEO_NODE_CURVE_ENDPOINT_SELECTION 1127
#define GEO_NODE_RAYCAST 1128
@@ -1525,6 +1525,12 @@ struct TexResult;
#define GEO_NODE_INPUT_SHORTEST_EDGE_PATHS 1168
#define GEO_NODE_EDGE_PATHS_TO_CURVES 1169
#define GEO_NODE_EDGE_PATHS_TO_SELECTION 1170
+#define GEO_NODE_MESH_FACE_SET_BOUNDARIES 1171
+#define GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME 1172
+#define GEO_NODE_SELF_OBJECT 1173
+#define GEO_NODE_SAMPLE_INDEX 1174
+#define GEO_NODE_SAMPLE_NEAREST 1175
+#define GEO_NODE_SAMPLE_NEAREST_SURFACE 1176
/** \} */
diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh
index 194820aa4ba..65c801a087b 100644
--- a/source/blender/blenkernel/BKE_node_runtime.hh
+++ b/source/blender/blenkernel/BKE_node_runtime.hh
@@ -81,7 +81,7 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
Vector<bNode *> toposort_left_to_right;
Vector<bNode *> toposort_right_to_left;
Vector<bNode *> group_nodes;
- bool has_link_cycle = false;
+ bool has_available_link_cycle = false;
bool has_undefined_nodes_or_sockets = false;
bNode *group_output_node = nullptr;
};
@@ -152,18 +152,17 @@ class bNodeRuntime : NonCopyable, NonMovable {
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;
+ bool has_available_linked_inputs = false;
+ bool has_available_linked_outputs = false;
bNodeTree *owner_tree = nullptr;
};
namespace node_tree_runtime {
/**
- * Is executed when the depsgraph determines that something in the node group changed that will
- * affect the output.
+ * Is executed when the node tree changed in the depsgraph.
*/
-void handle_node_tree_output_changed(bNodeTree &tree_cow);
+void preprocess_geometry_node_tree_for_evaluation(bNodeTree &tree_cow);
class AllowUsingOutdatedInfo : NonCopyable, NonMovable {
private:
@@ -270,10 +269,10 @@ inline blender::Span<bNode *> bNodeTree::group_nodes()
return this->runtime->group_nodes;
}
-inline bool bNodeTree::has_link_cycle() const
+inline bool bNodeTree::has_available_link_cycle() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
- return this->runtime->has_link_cycle;
+ return this->runtime->has_available_link_cycle;
}
inline bool bNodeTree::has_undefined_nodes_or_sockets() const
@@ -456,6 +455,11 @@ inline bool bNodeLink::is_muted() const
return this->flag & NODE_LINK_MUTED;
}
+inline bool bNodeLink::is_available() const
+{
+ return this->fromsock->is_available() && this->tosock->is_available();
+}
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 774765c3ca1..ed0969a6306 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -8,7 +8,9 @@
*/
#include "BLI_bitmap.h"
+#include "BLI_compiler_compat.h"
#include "BLI_utildefines.h"
+
#include "DNA_brush_enums.h"
#include "DNA_object_enums.h"
@@ -415,7 +417,6 @@ typedef struct SculptBoundaryPreviewEdge {
typedef struct SculptBoundary {
/* Vertex indices of the active boundary. */
PBVHVertRef *verts;
- int *verts_i;
int verts_capacity;
int verts_num;
@@ -485,6 +486,74 @@ typedef struct SculptFakeNeighbors {
/* Session data (mode-specific) */
+/* Custom Temporary Attributes */
+
+typedef struct SculptAttributeParams {
+ /* Allocate a flat array outside the CustomData system. Cannot be combined with permanent. */
+ int simple_array : 1;
+
+ /* Do not mark CustomData layer as temporary. Cannot be combined with simple_array. Doesn't
+ * work with PBVH_GRIDS.
+ */
+ int permanent : 1; /* Cannot be combined with simple_array. */
+ int stroke_only : 1; /* Release layer at end of struct */
+} SculptAttributeParams;
+
+typedef struct SculptAttribute {
+ /* Domain, data type and name */
+ eAttrDomain domain;
+ eCustomDataType proptype;
+ char name[MAX_CUSTOMDATA_LAYER_NAME];
+
+ /* Source layer on mesh/bmesh, if any. */
+ struct CustomDataLayer *layer;
+
+ /* Data stored as flat array. */
+ void *data;
+ int elem_size, elem_num;
+ bool data_for_bmesh; /* Temporary data store as array outside of bmesh. */
+
+ /* Data stored per BMesh element. */
+ int bmesh_cd_offset;
+
+ /* Sculpt usage */
+ SculptAttributeParams params;
+
+ /* Used to keep track of which preallocated SculptAttribute instances
+ * inside of SculptSession.temp_attribute are used.
+ */
+ bool used;
+} SculptAttribute;
+
+#define SCULPT_MAX_ATTRIBUTES 64
+
+/* Get a standard attribute name. Key must match up with a member
+ * of SculptAttributePointers.
+ */
+
+#define SCULPT_ATTRIBUTE_NAME(key) \
+ (offsetof(SculptAttributePointers, key) >= 0 ? /* Spellcheck name. */ \
+ (".sculpt_" #key) /* Make name. */ \
+ : \
+ "You misspelled the layer name key")
+
+/* Convenience pointers for standard sculpt attributes. */
+
+typedef struct SculptAttributePointers {
+ /* Persistent base. */
+ SculptAttribute *persistent_co;
+ SculptAttribute *persistent_no;
+ SculptAttribute *persistent_disp;
+
+ /* Precomputed auto-mask factor indexed by vertex, owned by the auto-masking system and
+ * initialized in #SCULPT_automasking_cache_init when needed. */
+ SculptAttribute *automasking_factor;
+
+ /* BMesh */
+ SculptAttribute *dyntopo_node_id_vertex;
+ SculptAttribute *dyntopo_node_id_face;
+} SculptAttributePointers;
+
typedef struct SculptSession {
/* Mesh data (not copied) can come either directly from a Mesh, or from a MultiresDM */
struct { /* Special handling for multires meshes */
@@ -529,6 +598,7 @@ typedef struct SculptSession {
/* Mesh Face Sets */
/* Total number of polys of the base mesh. */
int totfaces;
+
/* The 0 ID is not used by the tools or the visibility system, it is just used when creating new
* geometry (the trim tool, for example) to detect which geometry was just added, so it can be
* assigned a valid Face Set after creation. Tools are not intended to run with Face Sets IDs set
@@ -542,8 +612,6 @@ typedef struct SculptSession {
/* BMesh for dynamic topology sculpting */
struct BMesh *bm;
- int cd_vert_node_offset;
- int cd_face_node_offset;
bool bm_smooth_shading;
/* Undo/redo log for dynamic topology sculpting */
struct BMLog *bm_log;
@@ -575,7 +643,8 @@ typedef struct SculptSession {
int active_face_index;
int active_grid_index;
- /* When active, the cursor draws with faded colors, indicating that there is an action enabled.
+ /* When active, the cursor draws with faded colors, indicating that there is an action
+ * enabled.
*/
bool draw_faded_cursor;
float cursor_radius;
@@ -584,8 +653,10 @@ typedef struct SculptSession {
float cursor_sampled_normal[3];
float cursor_view_normal[3];
- /* For Sculpt trimming gesture tools, initial ray-cast data from the position of the mouse when
- * the gesture starts (intersection with the surface and if they ray hit the surface or not). */
+ /* For Sculpt trimming gesture tools, initial ray-cast data from the position of the mouse
+ * when
+ * the gesture starts (intersection with the surface and if they ray hit the surface or not).
+ */
float gesture_initial_location[3];
float gesture_initial_normal[3];
bool gesture_initial_hit;
@@ -606,10 +677,6 @@ typedef struct SculptSession {
/* Boundary Brush Preview */
SculptBoundary *boundary_preview;
- /* Mesh State Persistence */
- /* This is freed with the PBVH, so it is always in sync with the mesh. */
- SculptPersistentBase *persistent_base;
-
SculptVertexInfo vertex_info;
SculptFakeNeighbors fake_neighbors;
@@ -655,6 +722,14 @@ typedef struct SculptSession {
*/
char needs_flush_to_id;
+ /* This is a fixed-size array so we can pass pointers to its elements
+ * to client code. This is important to keep bmesh offsets up to date.
+ */
+ struct SculptAttribute temp_attributes[SCULPT_MAX_ATTRIBUTES];
+
+ /* Convenience #SculptAttribute pointers. */
+ SculptAttributePointers attrs;
+
/**
* Some tools follows the shading chosen by the last used tool canvas.
* When not set the viewport shading color would be used.
@@ -675,6 +750,75 @@ void BKE_sculptsession_free_deformMats(struct SculptSession *ss);
void BKE_sculptsession_free_vwpaint_data(struct SculptSession *ss);
void BKE_sculptsession_bm_to_me(struct Object *ob, bool reorder);
void BKE_sculptsession_bm_to_me_for_render(struct Object *object);
+int BKE_sculptsession_vertex_count(const SculptSession *ss);
+
+/* Ensure an attribute layer exists. */
+SculptAttribute *BKE_sculpt_attribute_ensure(struct Object *ob,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name,
+ const SculptAttributeParams *params);
+
+/* Returns nullptr if attribute does not exist. */
+SculptAttribute *BKE_sculpt_attribute_get(struct Object *ob,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name);
+
+bool BKE_sculpt_attribute_exists(struct Object *ob,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name);
+
+bool BKE_sculpt_attribute_destroy(struct Object *ob, SculptAttribute *attr);
+
+/* Destroy all attributes and pseudo-attributes created by sculpt mode. */
+void BKE_sculpt_attribute_destroy_temporary_all(struct Object *ob);
+
+/* Destroy attributes that were marked as stroke only in SculptAttributeParams. */
+void BKE_sculpt_attributes_destroy_temporary_stroke(struct Object *ob);
+
+BLI_INLINE void *BKE_sculpt_vertex_attr_get(const PBVHVertRef vertex, const SculptAttribute *attr)
+{
+ if (attr->data) {
+ char *p = (char *)attr->data;
+ int idx = (int)vertex.i;
+
+ if (attr->data_for_bmesh) {
+ BMElem *v = (BMElem *)vertex.i;
+ idx = v->head.index;
+ }
+
+ return p + attr->elem_size * (int)idx;
+ }
+ else {
+ BMElem *v = (BMElem *)vertex.i;
+ return BM_ELEM_CD_GET_VOID_P(v, attr->bmesh_cd_offset);
+ }
+
+ return NULL;
+}
+
+BLI_INLINE void *BKE_sculpt_face_attr_get(const PBVHFaceRef vertex, const SculptAttribute *attr)
+{
+ if (attr->data) {
+ char *p = (char *)attr->data;
+ int idx = (int)vertex.i;
+
+ if (attr->data_for_bmesh) {
+ BMElem *v = (BMElem *)vertex.i;
+ idx = v->head.index;
+ }
+
+ return p + attr->elem_size * (int)idx;
+ }
+ else {
+ BMElem *v = (BMElem *)vertex.i;
+ return BM_ELEM_CD_GET_VOID_P(v, attr->bmesh_cd_offset);
+ }
+
+ return NULL;
+}
/**
* Create new color layer on object if it doesn't have one and if experimental feature set has
@@ -713,6 +857,7 @@ struct PBVH *BKE_sculpt_object_pbvh_ensure(struct Depsgraph *depsgraph, struct O
void BKE_sculpt_bvh_update_from_ccg(struct PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
+void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object);
void BKE_sculpt_sync_face_visibility_to_grids(struct Mesh *mesh, struct SubdivCCG *subdiv_ccg);
/**
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index d4badbf2dc1..9e0884a8c76 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -238,7 +238,7 @@ typedef void (*BKE_pbvh_SearchNearestCallback)(PBVHNode *node, void *data, float
/* Building */
-PBVH *BKE_pbvh_new(void);
+PBVH *BKE_pbvh_new(PBVHType type);
/**
* Do a full rebuild with on Mesh data structure.
*
@@ -276,6 +276,8 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
int cd_vert_node_offset,
int cd_face_node_offset);
+void BKE_pbvh_update_bmesh_offsets(PBVH *pbvh, int cd_vert_node_offset, int cd_face_node_offset);
+
void BKE_pbvh_build_pixels(PBVH *pbvh,
struct Mesh *mesh,
struct Image *image,
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 48402123365..efb8c2a9bb1 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -285,7 +285,7 @@ void BKE_ptcache_ids_from_object(struct ListBase *lb,
struct Scene *scene,
int duplis);
-/****************** Query funcs ****************************/
+/****************** Query functions ****************************/
/**
* Check whether object has a point cache.
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 3691ab677b7..62b04785983 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -113,7 +113,7 @@ typedef struct SpaceType {
/* read and write... */
- /* default keymaps to add */
+ /** Default key-maps to add. */
int keymapflag;
} SpaceType;
diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh
deleted file mode 100644
index 27542aa3586..00000000000
--- a/source/blender/blenkernel/BKE_spline.hh
+++ /dev/null
@@ -1,688 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#pragma once
-
-/** \file
- * \ingroup bke
- */
-
-#include <mutex>
-
-#include "DNA_curves_types.h"
-
-#include "BLI_float4x4.hh"
-#include "BLI_generic_virtual_array.hh"
-#include "BLI_math_vec_types.hh"
-#include "BLI_vector.hh"
-
-#include "BKE_attribute.hh"
-#include "BKE_attribute_math.hh"
-
-struct Curve;
-struct Curves;
-struct ListBase;
-
-class Spline;
-using SplinePtr = std::unique_ptr<Spline>;
-
-/**
- * A spline is an abstraction of a single branch-less curve section, its evaluation methods,
- * and data. The spline data itself is just control points and a set of attributes by the set
- * of "evaluated" data is often used instead. Conceptually, the derived vs. original data is
- * an essential distinction. Derived data is usually calculated lazily and cached on the spline.
- *
- * Any derived class of Spline has to manage two things:
- * 1. Interpolating arbitrary attribute data from the control points to evaluated points.
- * 2. Evaluating the positions based on the stored control point data.
- *
- * Beyond that, everything is the base class's responsibility, with minor exceptions. Further
- * evaluation happens in a layer on top of the evaluated points generated by the derived types.
- *
- * There are a few methods to evaluate a spline:
- * 1. #evaluated_positions and #interpolate_to_evaluated give data for the initial
- * evaluated points, depending on the resolution.
- * 2. #lookup_evaluated_factor and #lookup_evaluated_factor are meant for one-off lookups
- * along the length of a curve.
- * 3. #sample_uniform_index_factors returns an array that stores uniform-length samples
- * along the spline which can be used to interpolate data from method 1.
- *
- * Commonly used evaluated data is stored in caches on the spline itself so that operations on
- * splines don't need to worry about taking ownership of evaluated data when they don't need to.
- */
-class Spline {
- public:
- NormalMode normal_mode = NORMAL_MODE_MINIMUM_TWIST;
-
- blender::bke::CustomDataAttributes attributes;
-
- protected:
- CurveType type_;
- bool is_cyclic_ = false;
-
- /** Direction of the spline at each evaluated point. */
- mutable blender::Vector<blender::float3> evaluated_tangents_cache_;
- mutable std::mutex tangent_cache_mutex_;
- mutable bool tangent_cache_dirty_ = true;
-
- /** Normal direction vectors for each evaluated point. */
- mutable blender::Vector<blender::float3> evaluated_normals_cache_;
- mutable std::mutex normal_cache_mutex_;
- mutable bool normal_cache_dirty_ = true;
-
- /** Accumulated lengths along the evaluated points. */
- mutable blender::Vector<float> evaluated_lengths_cache_;
- mutable std::mutex length_cache_mutex_;
- mutable bool length_cache_dirty_ = true;
-
- public:
- virtual ~Spline() = default;
- Spline(const CurveType type) : type_(type)
- {
- }
- Spline(Spline &other) : attributes(other.attributes), type_(other.type_)
- {
- copy_base_settings(other, *this);
- }
-
- /**
- * Return a new spline with the same data, settings, and attributes.
- */
- SplinePtr copy() const;
- /**
- * Return a new spline with the same type and settings like "cyclic", but without any data.
- */
- SplinePtr copy_only_settings() const;
- /**
- * The same as #copy, but skips copying dynamic attributes to the new spline.
- */
- SplinePtr copy_without_attributes() const;
- static void copy_base_settings(const Spline &src, Spline &dst);
-
- CurveType type() const;
-
- /** Return the number of control points. */
- virtual int size() const = 0;
- int segments_num() const;
- bool is_cyclic() const;
- void set_cyclic(bool value);
-
- virtual void resize(int size) = 0;
- virtual blender::MutableSpan<blender::float3> positions() = 0;
- virtual blender::Span<blender::float3> positions() const = 0;
- virtual blender::MutableSpan<float> radii() = 0;
- virtual blender::Span<float> radii() const = 0;
- virtual blender::MutableSpan<float> tilts() = 0;
- virtual blender::Span<float> tilts() const = 0;
-
- virtual void translate(const blender::float3 &translation);
- virtual void transform(const blender::float4x4 &matrix);
-
- /**
- * Change the direction of the spline (switch the start and end) without changing its shape.
- */
- void reverse();
-
- /**
- * Mark all caches for re-computation. This must be called after any operation that would
- * change the generated positions, tangents, normals, mapping, etc. of the evaluated points.
- */
- virtual void mark_cache_invalid() = 0;
- virtual int evaluated_points_num() const = 0;
- int evaluated_edges_num() const;
-
- float length() const;
-
- virtual blender::Span<blender::float3> evaluated_positions() const = 0;
-
- /**
- * Return non-owning access to the cache of accumulated lengths along the spline. Each item is
- * the length of the subsequent segment, i.e. the first value is the length of the first segment
- * rather than 0. This calculation is rather trivial, and only depends on the evaluated
- * positions. However, the results are used often, and it is necessarily single threaded, so it
- * is cached.
- */
- blender::Span<float> evaluated_lengths() const;
- /**
- * Return non-owning access to the direction of the curve at each evaluated point.
- */
- blender::Span<blender::float3> evaluated_tangents() const;
- /**
- * Return non-owning access to the direction vectors perpendicular to the tangents at every
- * evaluated point. The method used to generate the normal vectors depends on Spline.normal_mode.
- */
- blender::Span<blender::float3> evaluated_normals() const;
-
- void bounds_min_max(blender::float3 &min, blender::float3 &max, bool use_evaluated) const;
-
- struct LookupResult {
- /**
- * The index of the evaluated point before the result location. In other words, the index of
- * the edge that the result lies on. If the sampled factor/length is the very end of the
- * spline, this will be the second to last index, if it's the very beginning, this will be 0.
- */
- int evaluated_index;
- /**
- * The index of the evaluated point after the result location, accounting for wrapping when
- * the spline is cyclic. If the sampled factor/length is the very end of the spline, this will
- * be the last index (#evaluated_points_num - 1).
- */
- int next_evaluated_index;
- /**
- * The portion of the way from the evaluated point at #evaluated_index to the next point.
- * If the sampled factor/length is the very end of the spline, this will be the 1.0f
- */
- float factor;
- };
- /**
- * Find the position on the evaluated spline at the given portion of the total length.
- * The return value is the indices of the two neighboring points at that location and the
- * factor between them, which can be used to look up any attribute on the evaluated points.
- * \note This does not support extrapolation.
- */
- LookupResult lookup_evaluated_factor(float factor) const;
- /**
- * The same as #lookup_evaluated_factor, but looks up a length directly instead of
- * a portion of the total.
- */
- LookupResult lookup_evaluated_length(float length) const;
-
- /**
- * Return an array of evenly spaced samples along the length of the spline. The samples are
- * indices and factors to the next index encoded in floats. The logic for converting from the
- * float values to interpolation data is in #lookup_data_from_index_factor.
- */
- blender::Array<float> sample_uniform_index_factors(int samples_num) const;
- LookupResult lookup_data_from_index_factor(float index_factor) const;
-
- /**
- * Sample any input data with a value for each evaluated point (already interpolated to evaluated
- * points) to arbitrary parameters in between the evaluated points. The interpolation is quite
- * simple, but this handles the cyclic and end point special cases.
- */
- void sample_with_index_factors(const blender::GVArray &src,
- blender::Span<float> index_factors,
- blender::GMutableSpan dst) const;
- template<typename T>
- void sample_with_index_factors(const blender::VArray<T> &src,
- blender::Span<float> index_factors,
- blender::MutableSpan<T> dst) const
- {
- this->sample_with_index_factors(
- blender::GVArray(src), index_factors, blender::GMutableSpan(dst));
- }
- template<typename T>
- void sample_with_index_factors(blender::Span<T> src,
- blender::Span<float> index_factors,
- blender::MutableSpan<T> dst) const
- {
- this->sample_with_index_factors(blender::VArray<T>::ForSpan(src), index_factors, dst);
- }
-
- /**
- * Interpolate a virtual array of data with the size of the number of control points to the
- * evaluated points. For poly splines, the lifetime of the returned virtual array must not
- * exceed the lifetime of the input data.
- */
- virtual blender::GVArray interpolate_to_evaluated(const blender::GVArray &src) const = 0;
- blender::GVArray interpolate_to_evaluated(blender::GSpan data) const;
- template<typename T> blender::VArray<T> interpolate_to_evaluated(blender::Span<T> data) const
- {
- return this->interpolate_to_evaluated(blender::GSpan(data)).typed<T>();
- }
-
- protected:
- virtual void correct_end_tangents() const = 0;
- virtual void copy_settings(Spline &dst) const = 0;
- virtual void copy_data(Spline &dst) const = 0;
- virtual void reverse_impl() = 0;
-};
-
-/**
- * A Bezier spline is made up of a many curve segments, possibly achieving continuity of curvature
- * by constraining the alignment of curve handles. Evaluation stores the positions and a map of
- * factors and indices in a list of floats, which is then used to interpolate any other data.
- */
-class BezierSpline final : public Spline {
- blender::Vector<blender::float3> positions_;
- blender::Vector<float> radii_;
- blender::Vector<float> tilts_;
- int resolution_;
-
- blender::Vector<int8_t> handle_types_left_;
- blender::Vector<int8_t> handle_types_right_;
-
- /* These are mutable to allow lazy recalculation of #Auto and #Vector handle positions. */
- mutable blender::Vector<blender::float3> handle_positions_left_;
- mutable blender::Vector<blender::float3> handle_positions_right_;
-
- mutable std::mutex auto_handle_mutex_;
- mutable bool auto_handles_dirty_ = true;
-
- /** Start index in evaluated points array for every control point. */
- mutable blender::Vector<int> offset_cache_;
- mutable std::mutex offset_cache_mutex_;
- mutable bool offset_cache_dirty_ = true;
-
- /** Cache of evaluated positions. */
- mutable blender::Vector<blender::float3> evaluated_position_cache_;
- mutable std::mutex position_cache_mutex_;
- mutable bool position_cache_dirty_ = true;
-
- /** Cache of "index factors" based calculated from the evaluated positions. */
- mutable blender::Vector<float> evaluated_mapping_cache_;
- mutable std::mutex mapping_cache_mutex_;
- mutable bool mapping_cache_dirty_ = true;
-
- public:
- BezierSpline() : Spline(CURVE_TYPE_BEZIER)
- {
- }
- BezierSpline(const BezierSpline &other)
- : Spline((Spline &)other),
- positions_(other.positions_),
- radii_(other.radii_),
- tilts_(other.tilts_),
- resolution_(other.resolution_),
- handle_types_left_(other.handle_types_left_),
- handle_types_right_(other.handle_types_right_),
- handle_positions_left_(other.handle_positions_left_),
- handle_positions_right_(other.handle_positions_right_)
- {
- }
-
- int size() const final;
- int resolution() const;
- void set_resolution(int value);
-
- void resize(int size) final;
- blender::MutableSpan<blender::float3> positions() final;
- blender::Span<blender::float3> positions() const final;
- blender::MutableSpan<float> radii() final;
- blender::Span<float> radii() const final;
- blender::MutableSpan<float> tilts() final;
- blender::Span<float> tilts() const final;
- blender::Span<int8_t> handle_types_left() const;
- blender::MutableSpan<int8_t> handle_types_left();
- blender::Span<blender::float3> handle_positions_left() const;
- /**
- * Get writable access to the handle position.
- *
- * \param write_only: pass true for an uninitialized spline, this prevents accessing
- * uninitialized memory while auto-generating handles.
- */
- blender::MutableSpan<blender::float3> handle_positions_left(bool write_only = false);
- blender::Span<int8_t> handle_types_right() const;
- blender::MutableSpan<int8_t> handle_types_right();
- blender::Span<blender::float3> handle_positions_right() const;
- /**
- * Get writable access to the handle position.
- *
- * \param write_only: pass true for an uninitialized spline, this prevents accessing
- * uninitialized memory while auto-generating handles.
- */
- blender::MutableSpan<blender::float3> handle_positions_right(bool write_only = false);
- /**
- * Recalculate all #Auto and #Vector handles with positions automatically
- * derived from the neighboring control points.
- */
- void ensure_auto_handles() const;
-
- void translate(const blender::float3 &translation) override;
- void transform(const blender::float4x4 &matrix) override;
-
- /**
- * Set positions for the right handle of the control point, ensuring that
- * aligned handles stay aligned. Has no effect for auto and vector type handles.
- */
- void set_handle_position_right(int index, const blender::float3 &value);
- /**
- * Set positions for the left handle of the control point, ensuring that
- * aligned handles stay aligned. Has no effect for auto and vector type handles.
- */
- void set_handle_position_left(int index, const blender::float3 &value);
-
- bool point_is_sharp(int index) const;
-
- void mark_cache_invalid() final;
- int evaluated_points_num() const final;
-
- /**
- * Returns access to a cache of offsets into the evaluated point array for each control point.
- * While most control point edges generate the number of edges specified by the resolution,
- * vector segments only generate one edge.
- *
- * \note The length of the result is one greater than the number of points, so that the last item
- * is the total number of evaluated points. This is useful to avoid recalculating the size of the
- * last segment everywhere.
- */
- blender::Span<int> control_point_offsets() const;
- /**
- * 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 fractional part.
- */
- blender::Span<float> evaluated_mappings() const;
- blender::Span<blender::float3> evaluated_positions() const final;
- struct InterpolationData {
- int control_point_index;
- int next_control_point_index;
- /**
- * Linear interpolation weight between the two indices, from 0 to 1.
- * Higher means closer to next control point.
- */
- float factor;
- };
- /**
- * Convert the data encoded in #evaulated_mappings into its parts-- the information necessary
- * to interpolate data from control points to evaluated points between them. The next control
- * point index result will not overflow the size of the control point vectors.
- */
- InterpolationData interpolation_data_from_index_factor(float index_factor) const;
-
- virtual blender::GVArray interpolate_to_evaluated(const blender::GVArray &src) const override;
-
- void evaluate_segment(int index,
- int next_index,
- blender::MutableSpan<blender::float3> positions) const;
- /**
- * \warning This functional assumes that the spline has more than one point.
- */
- bool segment_is_vector(int start_index) const;
-
- /** See comment and diagram for #calculate_segment_insertion. */
- struct InsertResult {
- blender::float3 handle_prev;
- blender::float3 left_handle;
- blender::float3 position;
- blender::float3 right_handle;
- blender::float3 handle_next;
- };
- /**
- * De Casteljau Bezier subdivision.
- * \param index: The index of the segment's start control point.
- * \param next_index: The index of the control point at the end of the segment. Could be 0,
- * if the spline is cyclic.
- * \param parameter: The factor along the segment, between 0 and 1. Note that this is used
- * directly by the calculation, it doesn't correspond to a portion of the evaluated length.
- *
- * <pre>
- * handle_prev handle_next
- * x----------------x
- * / \
- * / x---O---x \
- * / result \
- * / \
- * O O
- * point_prev point_next
- * </pre>
- */
- InsertResult calculate_segment_insertion(int index, int next_index, float parameter);
-
- private:
- /**
- * If the spline is not cyclic, the direction for the first and last points is just the
- * direction formed by the corresponding handles and control points. In the unlikely situation
- * that the handles define a zero direction, fallback to using the direction defined by the
- * first and last evaluated segments already calculated in #Spline::evaluated_tangents().
- */
- void correct_end_tangents() const final;
- void copy_settings(Spline &dst) const final;
- void copy_data(Spline &dst) const final;
-
- protected:
- void reverse_impl() override;
-};
-
-/**
- * Data for Non-Uniform Rational B-Splines. The mapping from control points to evaluated points is
- * influenced by a vector of knots, weights for each point, and the order of the spline. Every
- * mapping of data to evaluated points is handled the same way, but the positions are cached in
- * the spline.
- */
-class NURBSpline final : public Spline {
- public:
- /** Method used to recalculate the knots vector when points are added or removed. */
- KnotsMode knots_mode;
-
- struct BasisCache {
- /**
- * For each evaluated point, the weight for all control points that influences it.
- * The vector's size is the evaluated point count multiplied by the spline's order.
- */
- blender::Vector<float> weights;
- /**
- * An offset for the start of #weights: the first control point index with a non-zero weight.
- */
- blender::Vector<int> start_indices;
- };
-
- private:
- blender::Vector<blender::float3> positions_;
- blender::Vector<float> radii_;
- blender::Vector<float> tilts_;
- blender::Vector<float> weights_;
- int resolution_;
- /**
- * Defines the number of nearby control points that influence a given evaluated point. Higher
- * orders give smoother results. The number of control points must be greater than or equal to
- * this value.
- */
- uint8_t order_;
-
- /**
- * Determines where and how the control points affect the evaluated points. The length should
- * always be the value returned by #knots_num(), and each value should be greater than or equal
- * to the previous. Only invalidated when a point is added or removed.
- */
- mutable blender::Vector<float> knots_;
- mutable std::mutex knots_mutex_;
- mutable bool knots_dirty_ = true;
-
- /** Cache of control point influences on each evaluated point. */
- mutable BasisCache basis_cache_;
- mutable std::mutex basis_cache_mutex_;
- mutable bool basis_cache_dirty_ = true;
-
- /**
- * Cache of position data calculated from the basis cache. Though it is interpolated
- * in the same way as any other attribute, it is stored to save unnecessary recalculation.
- */
- mutable blender::Vector<blender::float3> evaluated_position_cache_;
- mutable std::mutex position_cache_mutex_;
- mutable bool position_cache_dirty_ = true;
-
- public:
- NURBSpline() : Spline(CURVE_TYPE_NURBS)
- {
- }
- NURBSpline(const NURBSpline &other)
- : Spline((Spline &)other),
- knots_mode(other.knots_mode),
- positions_(other.positions_),
- radii_(other.radii_),
- tilts_(other.tilts_),
- weights_(other.weights_),
- resolution_(other.resolution_),
- order_(other.order_)
- {
- }
-
- int size() const final;
- int resolution() const;
- void set_resolution(int value);
- uint8_t order() const;
- void set_order(uint8_t value);
-
- bool check_valid_num_and_order() const;
- int knots_num() const;
-
- void resize(int size) final;
- blender::MutableSpan<blender::float3> positions() final;
- blender::Span<blender::float3> positions() const final;
- blender::MutableSpan<float> radii() final;
- blender::Span<float> radii() const final;
- blender::MutableSpan<float> tilts() final;
- blender::Span<float> tilts() const final;
- blender::Span<float> knots() const;
-
- blender::MutableSpan<float> weights();
- blender::Span<float> weights() const;
-
- void mark_cache_invalid() final;
- int evaluated_points_num() const final;
-
- blender::Span<blender::float3> evaluated_positions() const final;
-
- blender::GVArray interpolate_to_evaluated(const blender::GVArray &src) const final;
-
- protected:
- void correct_end_tangents() const final;
- void copy_settings(Spline &dst) const final;
- void copy_data(Spline &dst) const final;
- void reverse_impl() override;
-
- void calculate_knots() const;
- const BasisCache &calculate_basis_cache() const;
-};
-
-/**
- * A Poly spline is like a Bezier spline with a resolution of one. The main reason to distinguish
- * the two is for reduced complexity and increased performance, since interpolating data to control
- * points does not change it.
- *
- * Poly spline code is very simple, since it doesn't do anything that the base #Spline doesn't
- * handle. Mostly it just worries about storing the data used by the base class.
- */
-class PolySpline final : public Spline {
- blender::Vector<blender::float3> positions_;
- blender::Vector<float> radii_;
- blender::Vector<float> tilts_;
-
- public:
- PolySpline() : Spline(CURVE_TYPE_POLY)
- {
- }
- PolySpline(const PolySpline &other)
- : Spline((Spline &)other),
- positions_(other.positions_),
- radii_(other.radii_),
- tilts_(other.tilts_)
- {
- }
-
- int size() const final;
-
- void resize(int size) final;
- blender::MutableSpan<blender::float3> positions() final;
- blender::Span<blender::float3> positions() const final;
- blender::MutableSpan<float> radii() final;
- blender::Span<float> radii() const final;
- blender::MutableSpan<float> tilts() final;
- blender::Span<float> tilts() const final;
-
- void mark_cache_invalid() final;
- int evaluated_points_num() const final;
-
- blender::Span<blender::float3> evaluated_positions() const final;
-
- /**
- * Poly spline interpolation from control points to evaluated points is a special case, since
- * the result data is the same as the input data. This function returns a #GVArray that points to
- * the original data. Therefore the lifetime of the returned virtual array must not be longer
- * than the source data.
- */
- blender::GVArray interpolate_to_evaluated(const blender::GVArray &src) const final;
-
- protected:
- void correct_end_tangents() const final;
- void copy_settings(Spline &dst) const final;
- void copy_data(Spline &dst) const final;
- void reverse_impl() override;
-};
-
-/**
- * A collection of #Spline objects with the same attribute types and names. Most data and
- * functionality is in splines, but this contains some helpers for working with them as a group.
- *
- * \note A #CurveEval corresponds to the #Curve object data. The name is different for clarity,
- * since more of the data is stored in the splines, but also just to be different than the name in
- * DNA.
- */
-struct CurveEval {
- private:
- blender::Vector<SplinePtr> splines_;
-
- public:
- blender::bke::CustomDataAttributes attributes;
-
- CurveEval() = default;
- CurveEval(const CurveEval &other) : attributes(other.attributes)
- {
- for (const SplinePtr &spline : other.splines()) {
- this->add_spline(spline->copy());
- }
- }
-
- blender::Span<SplinePtr> splines() const;
- blender::MutableSpan<SplinePtr> splines();
- /**
- * \return True if the curve contains a spline with the given type.
- *
- * \note If you are looping over all of the splines in the same scope anyway,
- * it's better to avoid calling this function, in case there are many splines.
- */
- bool has_spline_with_type(const CurveType type) const;
-
- void resize(int size);
- /**
- * \warning Call #reallocate on the spline's attributes after adding all splines.
- */
- void add_spline(SplinePtr spline);
- void add_splines(blender::MutableSpan<SplinePtr> splines);
- void remove_splines(blender::IndexMask mask);
-
- void translate(const blender::float3 &translation);
- void transform(const blender::float4x4 &matrix);
- bool bounds_min_max(blender::float3 &min, blender::float3 &max, bool use_evaluated) const;
-
- blender::bke::MutableAttributeAccessor attributes_for_write();
-
- /**
- * Return the start indices for each of the curve spline's control points, if they were part
- * of a flattened array. This can be used to facilitate parallelism by avoiding the need to
- * accumulate an offset while doing more complex calculations.
- *
- * \note The result is one longer than the spline count; the last element is the total size.
- */
- blender::Array<int> control_point_offsets() const;
- /**
- * Exactly like #control_point_offsets, but uses the number of evaluated points instead.
- */
- blender::Array<int> evaluated_point_offsets() const;
- /**
- * Return the accumulated length at the start of every spline in the curve.
- * \note The result is one longer than the spline count; the last element is the total length.
- */
- blender::Array<float> accumulated_spline_lengths() const;
-
- float total_length() const;
- int total_control_point_num() const;
-
- void mark_cache_invalid();
-
- /**
- * Check the invariants that curve control point attributes should always uphold, necessary
- * because attributes are stored on splines rather than in a flat array on the curve:
- * - The same set of attributes exists on every spline.
- * - Attributes with the same name have the same type on every spline.
- * - Attributes are in the same order on every spline.
- */
- void assert_valid_point_attributes() const;
-};
-
-std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &curve,
- const ListBase &nurbs_list);
-std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve);
-std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves);
-Curves *curve_eval_to_curves(const CurveEval &curve_eval);
diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h
index 486c9430279..5a6e8cbb64a 100644
--- a/source/blender/blenkernel/BKE_subdiv.h
+++ b/source/blender/blenkernel/BKE_subdiv.h
@@ -307,7 +307,6 @@ BLI_INLINE void BKE_subdiv_rotate_grid_to_quad(
/* Convert Blender edge crease value to OpenSubdiv sharpness. */
BLI_INLINE float BKE_subdiv_crease_to_sharpness_f(float edge_crease);
-BLI_INLINE float BKE_subdiv_crease_to_sharpness_char(char edge_crease);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 2f1e1897f8d..877407a644c 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -110,7 +110,6 @@ set(SRC
intern/curve_convert.c
intern/curve_decimate.c
intern/curve_deform.c
- intern/curve_eval.cc
intern/curve_legacy_convert.cc
intern/curve_nurbs.cc
intern/curve_poly.cc
@@ -137,7 +136,6 @@ set(SRC
intern/fluid.c
intern/fmodifier.c
intern/freestyle.c
- intern/geometry_component_curve.cc
intern/geometry_component_curves.cc
intern/geometry_component_edit_data.cc
intern/geometry_component_instances.cc
@@ -203,7 +201,7 @@ set(SRC
intern/mesh_fair.cc
intern/mesh_iterators.c
intern/mesh_legacy_convert.cc
- intern/mesh_mapping.c
+ intern/mesh_mapping.cc
intern/mesh_merge.c
intern/mesh_merge_customdata.cc
intern/mesh_mirror.c
@@ -266,10 +264,6 @@ set(SRC
intern/softbody.c
intern/sound.c
intern/speaker.c
- intern/spline_base.cc
- intern/spline_bezier.cc
- intern/spline_nurbs.cc
- intern/spline_poly.cc
intern/studiolight.c
intern/subdiv.c
intern/subdiv_ccg.c
@@ -306,7 +300,7 @@ set(SRC
intern/volume.cc
intern/volume_render.cc
intern/volume_to_mesh.cc
- intern/workspace.c
+ intern/workspace.cc
intern/world.c
intern/writeavi.c
@@ -469,7 +463,6 @@ set(SRC
BKE_softbody.h
BKE_sound.h
BKE_speaker.h
- BKE_spline.hh
BKE_studiolight.h
BKE_subdiv.h
BKE_subdiv_ccg.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 9c05a2c4061..375e7b456cd 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -188,7 +188,7 @@ void DM_init_funcs(DerivedMesh *dm)
dm->getLoopTriArray = dm_getLoopTriArray;
- /* subtypes handle getting actual data */
+ /* Sub-types handle getting actual data. */
dm->getNumLoopTri = dm_getNumLoopTri;
dm->getVertDataArray = DM_get_vert_data_layer;
@@ -240,8 +240,6 @@ void DM_from_template(DerivedMesh *dm,
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;
-
dm->type = type;
dm->numVertData = numVerts;
dm->numEdgeData = numEdges;
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index e0ae1d88760..10aa4ec7906 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -113,7 +113,7 @@ static void action_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src,
BLI_addtail(&action_dst->curves, fcurve_dst);
- /* Fix group links (kindof bad list-in-list search, but this is the most reliable way). */
+ /* Fix group links (kind of bad list-in-list search, but this is the most reliable way). */
for (group_dst = action_dst->groups.first, group_src = action_src->groups.first;
group_dst && group_src;
group_dst = group_dst->next, group_src = group_src->next) {
diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c
index b5b00e031b2..9b68c19c6e2 100644
--- a/source/blender/blenkernel/intern/anim_data.c
+++ b/source/blender/blenkernel/intern/anim_data.c
@@ -136,7 +136,7 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
return false;
}
- /* Reduce usercount for current action. */
+ /* Reduce user-count for current action. */
if (adt->action) {
id_us_min((ID *)adt->action);
}
@@ -287,11 +287,11 @@ AnimData *BKE_animdata_copy(Main *bmain, AnimData *adt, const int flag)
/* make a copy of action - at worst, user has to delete copies... */
if (do_action) {
- /* Recursive copy of 'real' IDs is a bit hairy. Even if do not want to deal with usercount
- * when copying ID's data itself, we still need to do so with sub-IDs, since those will not be
- * handled by later 'update usercounts of used IDs' code as used e.g. at end of
- * BKE_id_copy_ex().
- * So in case we do copy the ID and its sub-IDs in bmain, silence the 'no usercount' flag for
+ /* Recursive copy of 'real' IDs is a bit hairy. Even if do not want to deal with user-count
+ * when copying ID's data itself, we still need to do so with sub-IDs, since those will not be
+ * handled by later 'update user-counts of used IDs' code as used e.g. at end of
+ * #BKE_id_copy_ex().
+ * So in case we do copy the ID and its sub-IDs in bmain, silence the 'no user-count' flag for
* the sub-IDs copying.
* NOTE: This is a bit weak, as usually when it comes to recursive ID copy. Should work for
* now, but we may have to revisit this at some point and add a proper extra flag to deal with
@@ -659,6 +659,8 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa
srcAdt, dstAdt, basepath_change->src_basepath, basepath_change->dst_basepath);
}
}
+ /* Tag source action because list of fcurves changed. */
+ DEG_id_tag_update(&srcAdt->action->id, ID_RECALC_COPY_ON_WRITE);
}
/* Path Validation -------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 96ac81fdb63..e3c42c8bb78 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -888,7 +888,7 @@ void BKE_appdir_program_path_init(const char *argv0)
const char *BKE_appdir_program_path(void)
{
-#ifndef WITH_PYTHON_MODULE /* Default's to empty when building as as Python module. */
+#ifndef WITH_PYTHON_MODULE /* Default's to empty when building as a Python module. */
BLI_assert(g_app.program_filepath[0]);
#endif
return g_app.program_filepath;
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 0027f6dd707..9b00d427320 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -97,7 +97,7 @@ static void armature_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src
Bone *bone_src, *bone_dst;
Bone *bone_dst_act = NULL;
- /* We never handle usercount here for own data. */
+ /* We never handle user-count here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
armature_dst->bonehash = NULL;
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 1e237da8119..b86353bdb74 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -19,6 +19,8 @@
#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
+#include "FN_field.hh"
+
#include "BLT_translation.h"
#include "CLG_log.h"
@@ -56,7 +58,8 @@ const char *no_procedural_access_message =
bool allow_procedural_attribute_access(StringRef attribute_name)
{
- return !attribute_name.startswith(".selection") && !attribute_name.startswith(".hide");
+ return !attribute_name.startswith(".sculpt") && !attribute_name.startswith(".select") &&
+ !attribute_name.startswith(".hide");
}
static int attribute_data_type_complexity(const eCustomDataType data_type)
@@ -944,6 +947,15 @@ GSpanAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write_only_span
return {};
}
+fn::GField AttributeValidator::validate_field_if_necessary(const fn::GField &field) const
+{
+ if (function) {
+ auto validate_op = fn::FieldOperation::Create(*function, {field});
+ return fn::GField(validate_op);
+ }
+ return field;
+}
+
Vector<AttributeTransferData> retrieve_attributes_for_transfer(
const bke::AttributeAccessor src_attributes,
bke::MutableAttributeAccessor dst_attributes,
diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh
index 8050f45da94..5fbca283399 100644
--- a/source/blender/blenkernel/intern/attribute_access_intern.hh
+++ b/source/blender/blenkernel/intern/attribute_access_intern.hh
@@ -53,6 +53,7 @@ class BuiltinAttributeProvider {
const CreatableEnum createable_;
const WritableEnum writable_;
const DeletableEnum deletable_;
+ const AttributeValidator validator_;
public:
BuiltinAttributeProvider(std::string name,
@@ -60,13 +61,15 @@ class BuiltinAttributeProvider {
const eCustomDataType data_type,
const CreatableEnum createable,
const WritableEnum writable,
- const DeletableEnum deletable)
+ const DeletableEnum deletable,
+ AttributeValidator validator = {})
: name_(std::move(name)),
domain_(domain),
data_type_(data_type),
createable_(createable),
writable_(writable),
- deletable_(deletable)
+ deletable_(deletable),
+ validator_(validator)
{
}
@@ -90,6 +93,11 @@ class BuiltinAttributeProvider {
{
return data_type_;
}
+
+ AttributeValidator validator() const
+ {
+ return validator_;
+ }
};
/**
@@ -241,9 +249,15 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider {
const CustomDataAccessInfo custom_data_access,
const AsReadAttribute as_read_attribute,
const AsWriteAttribute as_write_attribute,
- const UpdateOnChange update_on_write)
- : BuiltinAttributeProvider(
- std::move(attribute_name), domain, attribute_type, creatable, writable, deletable),
+ const UpdateOnChange update_on_write,
+ const AttributeValidator validator = {})
+ : BuiltinAttributeProvider(std::move(attribute_name),
+ domain,
+ attribute_type,
+ creatable,
+ writable,
+ deletable,
+ validator),
stored_type_(stored_type),
custom_data_access_(custom_data_access),
as_read_attribute_(as_read_attribute),
@@ -379,6 +393,21 @@ inline bool for_all(const void *owner,
}
template<const ComponentAttributeProviders &providers>
+inline AttributeValidator lookup_validator(const void * /*owner*/,
+ const blender::bke::AttributeIDRef &attribute_id)
+{
+ if (!attribute_id.is_named()) {
+ return {};
+ }
+ const BuiltinAttributeProvider *provider =
+ providers.builtin_attribute_providers().lookup_default_as(attribute_id.name(), nullptr);
+ if (!provider) {
+ return {};
+ }
+ return provider->validator();
+}
+
+template<const ComponentAttributeProviders &providers>
inline bool contains(const void *owner, const blender::bke::AttributeIDRef &attribute_id)
{
bool found = false;
@@ -489,6 +518,7 @@ inline AttributeAccessorFunctions accessor_functions_for_providers()
lookup<providers>,
nullptr,
for_all<providers>,
+ lookup_validator<providers>,
lookup_for_write<providers>,
remove<providers>,
add<providers>};
diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc
index c206a04fecc..a998fc0a75f 100644
--- a/source/blender/blenkernel/intern/brush.cc
+++ b/source/blender/blenkernel/intern/brush.cc
@@ -982,7 +982,6 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
case GP_BRUSH_PRESET_FILL_AREA: {
brush->size = 5.0f;
- brush->gpencil_settings->fill_leak = 3;
brush->gpencil_settings->fill_threshold = 0.1f;
brush->gpencil_settings->fill_simplylvl = 1;
brush->gpencil_settings->fill_factor = 1.0f;
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index 158e0bb776c..c3384239cb6 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -72,7 +72,7 @@ static void camera_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src,
Camera *cam_dst = (Camera *)id_dst;
const Camera *cam_src = (const Camera *)id_src;
- /* We never handle usercount here for own data. */
+ /* We never handle user-count here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
BLI_listbase_clear(&cam_dst->bg_images);
@@ -350,7 +350,7 @@ void BKE_camera_params_from_view3d(CameraParams *params,
/* orthographic view */
float sensor_size = BKE_camera_sensor_size(
params->sensor_fit, params->sensor_x, params->sensor_y);
- /* Halve, otherwise too extreme low zbuffer quality. */
+ /* Halve, otherwise too extreme low Z-buffer quality. */
params->clip_end *= 0.5f;
params->clip_start = -params->clip_end;
@@ -401,7 +401,7 @@ void BKE_camera_params_compute_viewplane(
pixsize *= params->zoom;
/* compute view plane:
- * fully centered, zbuffer fills in jittered between -.5 and +.5 */
+ * Fully centered, Z-buffer fills in jittered between `-.5` and `+.5`. */
viewplane.xmin = -0.5f * (float)winx;
viewplane.ymin = -0.5f * params->ycor * (float)winy;
viewplane.xmax = 0.5f * (float)winx;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 0261b2d7674..bcdd01aa8b3 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -206,7 +206,6 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh,
* but only if the original mesh had its deformed_only flag correctly set
* (which isn't generally the case). */
dm->deformedOnly = 1;
- dm->cd_flag = mesh->cd_flag;
CustomData_merge(&mesh->vdata, &dm->vertData, cddata_masks.vmask, alloctype, mesh->totvert);
CustomData_merge(&mesh->edata, &dm->edgeData, cddata_masks.emask, alloctype, mesh->totedge);
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index bcc3db48947..cd381e15635 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -1283,9 +1283,8 @@ static void trackto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
cob->matrix[2][1] = 0;
cob->matrix[2][2] = size[2];
- /* targetmat[2] instead of ownermat[2] is passed to vectomat
- * for backwards compatibility it seems... (Aligorith)
- */
+ /* NOTE(@joshualung): `targetmat[2]` instead of `ownermat[2]` is passed to #vectomat
+ * for backwards compatibility it seems. */
sub_v3_v3v3(vec, cob->matrix[3], ct->matrix[3]);
vectomat(
vec, ct->matrix[2], (short)data->reserved1, (short)data->reserved2, data->flags, totmat);
@@ -5932,12 +5931,12 @@ static void constraint_copy_data_ex(bConstraint *dst,
cti->copy_data(dst, src);
}
- /* Fix usercounts for all referenced data that need it. */
+ /* Fix user-counts for all referenced data that need it. */
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
con_invoke_id_looper(cti, dst, con_fix_copied_refs_cb, NULL);
}
- /* for proxies we don't want to make extern */
+ /* For proxies we don't want to make external. */
if (do_extern) {
/* go over used ID-links for this constraint to ensure that they are valid for proxies */
con_invoke_id_looper(cti, dst, con_extern_cb, NULL);
diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc
index aebdb8cc690..ca390fae424 100644
--- a/source/blender/blenkernel/intern/curve.cc
+++ b/source/blender/blenkernel/intern/curve.cc
@@ -2247,7 +2247,7 @@ static void minimum_twist_between_two_points(BevPoint *current_point, BevPoint *
static void make_bevel_list_3D_minimum_twist(BevList *bl)
{
- BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
+ BevPoint *bevp2, *bevp1, *bevp0; /* Standard for all make_bevel_list_3D_* functions. */
int nr;
float q[4];
@@ -2358,7 +2358,7 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
static void make_bevel_list_3D_tangent(BevList *bl)
{
- BevPoint *bevp2, *bevp1, *bevp0; /* standard for all make_bevel_list_3D_* funcs */
+ BevPoint *bevp2, *bevp1, *bevp0; /* Standard for all make_bevel_list_3D_* functions. */
int nr;
float bevp0_tan[3];
diff --git a/source/blender/blenkernel/intern/curve_catmull_rom.cc b/source/blender/blenkernel/intern/curve_catmull_rom.cc
index dac88948036..b5f1a7cc450 100644
--- a/source/blender/blenkernel/intern/curve_catmull_rom.cc
+++ b/source/blender/blenkernel/intern/curve_catmull_rom.cc
@@ -17,7 +17,7 @@ int calculate_evaluated_num(const int points_num, const bool cyclic, const int r
}
/* Adapted from Cycles #catmull_rom_basis_eval function. */
-void calculate_basis(const float parameter, float r_weights[4])
+void calculate_basis(const float parameter, float4 &r_weights)
{
const float t = parameter;
const float s = 1.0f - parameter;
@@ -139,11 +139,7 @@ void interpolate_to_evaluated(const GSpan src,
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
- /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify
- * supporting more types. */
- if constexpr (is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) {
- interpolate_to_evaluated(src.typed<T>(), cyclic, resolution, dst.typed<T>());
- }
+ interpolate_to_evaluated(src.typed<T>(), cyclic, resolution, dst.typed<T>());
});
}
@@ -154,11 +150,7 @@ void interpolate_to_evaluated(const GSpan src,
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
- /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify
- * supporting more types. */
- if constexpr (is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) {
- interpolate_to_evaluated(src.typed<T>(), cyclic, evaluated_offsets, dst.typed<T>());
- }
+ interpolate_to_evaluated(src.typed<T>(), cyclic, evaluated_offsets, dst.typed<T>());
});
}
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
deleted file mode 100644
index 3bee82fadab..00000000000
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ /dev/null
@@ -1,587 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_array.hh"
-#include "BLI_index_range.hh"
-#include "BLI_listbase.h"
-#include "BLI_map.hh"
-#include "BLI_span.hh"
-#include "BLI_string_ref.hh"
-#include "BLI_task.hh"
-#include "BLI_vector.hh"
-
-#include "DNA_curve_types.h"
-
-#include "BKE_anonymous_attribute.hh"
-#include "BKE_curve.h"
-#include "BKE_curves.hh"
-#include "BKE_geometry_set.hh"
-#include "BKE_spline.hh"
-
-using blender::Array;
-using blender::float3;
-using blender::float4x4;
-using blender::GVArray;
-using blender::GVArraySpan;
-using blender::IndexRange;
-using blender::Map;
-using blender::MutableSpan;
-using blender::Span;
-using blender::StringRefNull;
-using blender::VArray;
-using blender::VArraySpan;
-using blender::Vector;
-using blender::bke::AttributeIDRef;
-using blender::bke::AttributeMetaData;
-
-blender::Span<SplinePtr> CurveEval::splines() const
-{
- return splines_;
-}
-
-blender::MutableSpan<SplinePtr> CurveEval::splines()
-{
- return splines_;
-}
-
-bool CurveEval::has_spline_with_type(const CurveType type) const
-{
- for (const SplinePtr &spline : this->splines()) {
- if (spline->type() == type) {
- return true;
- }
- }
- return false;
-}
-
-void CurveEval::resize(const int size)
-{
- splines_.resize(size);
- attributes.reallocate(size);
-}
-
-void CurveEval::add_spline(SplinePtr spline)
-{
- splines_.append(std::move(spline));
-}
-
-void CurveEval::add_splines(MutableSpan<SplinePtr> splines)
-{
- for (SplinePtr &spline : splines) {
- this->add_spline(std::move(spline));
- }
-}
-
-void CurveEval::remove_splines(blender::IndexMask mask)
-{
- for (int i = mask.size() - 1; i >= 0; i--) {
- splines_.remove_and_reorder(mask.indices()[i]);
- }
-}
-
-void CurveEval::translate(const float3 &translation)
-{
- for (SplinePtr &spline : this->splines()) {
- spline->translate(translation);
- spline->mark_cache_invalid();
- }
-}
-
-void CurveEval::transform(const float4x4 &matrix)
-{
- for (SplinePtr &spline : this->splines()) {
- spline->transform(matrix);
- }
-}
-
-bool CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
-{
- bool have_minmax = false;
- for (const SplinePtr &spline : this->splines()) {
- if (spline->size()) {
- spline->bounds_min_max(min, max, use_evaluated);
- have_minmax = true;
- }
- }
-
- return have_minmax;
-}
-
-float CurveEval::total_length() const
-{
- float length = 0.0f;
- for (const SplinePtr &spline : this->splines()) {
- length += spline->length();
- }
- return length;
-}
-
-int CurveEval::total_control_point_num() const
-{
- int count = 0;
- for (const SplinePtr &spline : this->splines()) {
- count += spline->size();
- }
- return count;
-}
-
-blender::Array<int> CurveEval::control_point_offsets() const
-{
- Array<int> offsets(splines_.size() + 1);
- int offset = 0;
- for (const int i : splines_.index_range()) {
- offsets[i] = offset;
- offset += splines_[i]->size();
- }
- offsets.last() = offset;
- return offsets;
-}
-
-blender::Array<int> CurveEval::evaluated_point_offsets() const
-{
- Array<int> offsets(splines_.size() + 1);
- int offset = 0;
- for (const int i : splines_.index_range()) {
- offsets[i] = offset;
- offset += splines_[i]->evaluated_points_num();
- }
- offsets.last() = offset;
- return offsets;
-}
-
-blender::Array<float> CurveEval::accumulated_spline_lengths() const
-{
- Array<float> spline_lengths(splines_.size() + 1);
- float spline_length = 0.0f;
- for (const int i : splines_.index_range()) {
- spline_lengths[i] = spline_length;
- spline_length += splines_[i]->length();
- }
- spline_lengths.last() = spline_length;
- return spline_lengths;
-}
-
-void CurveEval::mark_cache_invalid()
-{
- for (SplinePtr &spline : splines_) {
- spline->mark_cache_invalid();
- }
-}
-
-static HandleType handle_type_from_dna_bezt(const eBezTriple_Handle dna_handle_type)
-{
- switch (dna_handle_type) {
- case HD_FREE:
- return BEZIER_HANDLE_FREE;
- case HD_AUTO:
- return BEZIER_HANDLE_AUTO;
- case HD_VECT:
- return BEZIER_HANDLE_VECTOR;
- case HD_ALIGN:
- return BEZIER_HANDLE_ALIGN;
- case HD_AUTO_ANIM:
- return BEZIER_HANDLE_AUTO;
- case HD_ALIGN_DOUBLESIDE:
- return BEZIER_HANDLE_ALIGN;
- }
- BLI_assert_unreachable();
- return BEZIER_HANDLE_AUTO;
-}
-
-static NormalMode normal_mode_from_dna_curve(const int twist_mode)
-{
- switch (twist_mode) {
- case CU_TWIST_Z_UP:
- case CU_TWIST_TANGENT:
- return NORMAL_MODE_Z_UP;
- case CU_TWIST_MINIMUM:
- return NORMAL_MODE_MINIMUM_TWIST;
- }
- BLI_assert_unreachable();
- return NORMAL_MODE_MINIMUM_TWIST;
-}
-
-static KnotsMode knots_mode_from_dna_nurb(const short flag)
-{
- switch (flag & (CU_NURB_ENDPOINT | CU_NURB_BEZIER)) {
- case CU_NURB_ENDPOINT:
- return NURBS_KNOT_MODE_ENDPOINT;
- case CU_NURB_BEZIER:
- return NURBS_KNOT_MODE_BEZIER;
- case CU_NURB_ENDPOINT | CU_NURB_BEZIER:
- return NURBS_KNOT_MODE_ENDPOINT_BEZIER;
- default:
- return NURBS_KNOT_MODE_NORMAL;
- }
-
- BLI_assert_unreachable();
- return NURBS_KNOT_MODE_NORMAL;
-}
-
-static SplinePtr spline_from_dna_bezier(const Nurb &nurb)
-{
- std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>();
- spline->set_resolution(nurb.resolu);
- spline->set_cyclic(nurb.flagu & CU_NURB_CYCLIC);
-
- Span<const BezTriple> src_points{nurb.bezt, nurb.pntsu};
- spline->resize(src_points.size());
- MutableSpan<float3> positions = spline->positions();
- MutableSpan<float3> handle_positions_left = spline->handle_positions_left(true);
- MutableSpan<float3> handle_positions_right = spline->handle_positions_right(true);
- MutableSpan<int8_t> handle_types_left = spline->handle_types_left();
- MutableSpan<int8_t> handle_types_right = spline->handle_types_right();
- MutableSpan<float> radii = spline->radii();
- MutableSpan<float> tilts = spline->tilts();
-
- blender::threading::parallel_for(src_points.index_range(), 2048, [&](IndexRange range) {
- for (const int i : range) {
- const BezTriple &bezt = src_points[i];
- positions[i] = bezt.vec[1];
- handle_positions_left[i] = bezt.vec[0];
- handle_types_left[i] = handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h1);
- handle_positions_right[i] = bezt.vec[2];
- handle_types_right[i] = handle_type_from_dna_bezt((eBezTriple_Handle)bezt.h2);
- radii[i] = bezt.radius;
- tilts[i] = bezt.tilt;
- }
- });
-
- return spline;
-}
-
-static SplinePtr spline_from_dna_nurbs(const Nurb &nurb)
-{
- std::unique_ptr<NURBSpline> spline = std::make_unique<NURBSpline>();
- spline->set_resolution(nurb.resolu);
- spline->set_cyclic(nurb.flagu & CU_NURB_CYCLIC);
- spline->set_order(nurb.orderu);
- spline->knots_mode = knots_mode_from_dna_nurb(nurb.flagu);
-
- Span<const BPoint> src_points{nurb.bp, nurb.pntsu};
- spline->resize(src_points.size());
- MutableSpan<float3> positions = spline->positions();
- MutableSpan<float> weights = spline->weights();
- MutableSpan<float> radii = spline->radii();
- MutableSpan<float> tilts = spline->tilts();
-
- blender::threading::parallel_for(src_points.index_range(), 2048, [&](IndexRange range) {
- for (const int i : range) {
- const BPoint &bp = src_points[i];
- positions[i] = bp.vec;
- weights[i] = bp.vec[3];
- radii[i] = bp.radius;
- tilts[i] = bp.tilt;
- }
- });
-
- return spline;
-}
-
-static SplinePtr spline_from_dna_poly(const Nurb &nurb)
-{
- std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
- spline->set_cyclic(nurb.flagu & CU_NURB_CYCLIC);
-
- Span<const BPoint> src_points{nurb.bp, nurb.pntsu};
- spline->resize(src_points.size());
- MutableSpan<float3> positions = spline->positions();
- MutableSpan<float> radii = spline->radii();
- MutableSpan<float> tilts = spline->tilts();
-
- blender::threading::parallel_for(src_points.index_range(), 2048, [&](IndexRange range) {
- for (const int i : range) {
- const BPoint &bp = src_points[i];
- positions[i] = bp.vec;
- radii[i] = bp.radius;
- tilts[i] = bp.tilt;
- }
- });
-
- return spline;
-}
-
-std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve,
- const ListBase &nurbs_list)
-{
- Vector<const Nurb *> nurbs(nurbs_list);
-
- std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
- curve->resize(nurbs.size());
- MutableSpan<SplinePtr> splines = curve->splines();
-
- blender::threading::parallel_for(nurbs.index_range(), 256, [&](IndexRange range) {
- for (const int i : range) {
- switch (nurbs[i]->type) {
- case CU_BEZIER:
- splines[i] = spline_from_dna_bezier(*nurbs[i]);
- break;
- case CU_NURBS:
- splines[i] = spline_from_dna_nurbs(*nurbs[i]);
- break;
- case CU_POLY:
- splines[i] = spline_from_dna_poly(*nurbs[i]);
- break;
- default:
- BLI_assert_unreachable();
- break;
- }
- }
- });
-
- /* Normal mode is stored separately in each spline to facilitate combining
- * splines from multiple curve objects, where the value may be different. */
- const NormalMode normal_mode = normal_mode_from_dna_curve(dna_curve.twist_mode);
- for (SplinePtr &spline : curve->splines()) {
- spline->normal_mode = normal_mode;
- }
-
- return curve;
-}
-
-std::unique_ptr<CurveEval> curve_eval_from_dna_curve(const Curve &dna_curve)
-{
- return curve_eval_from_dna_curve(dna_curve, *BKE_curve_nurbs_get_for_read(&dna_curve));
-}
-
-static void copy_attributes_between_components(
- const blender::bke::AttributeAccessor &src_attributes,
- blender::bke::MutableAttributeAccessor &dst_attributes,
- Span<std::string> skip)
-{
- src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
- if (id.is_named() && skip.contains(id.name())) {
- return true;
- }
-
- GVArray src_attribute = src_attributes.lookup(id, meta_data.domain, meta_data.data_type);
- if (!src_attribute) {
- return true;
- }
- GVArraySpan src_attribute_data{src_attribute};
-
- blender::bke::GAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write(
- id, meta_data.domain, meta_data.data_type);
- if (!dst_attribute) {
- return true;
- }
- dst_attribute.varray.set_all(src_attribute_data.data());
- dst_attribute.finish();
- return true;
- });
-}
-
-std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves_id)
-{
- CurveComponent src_component;
- src_component.replace(&const_cast<Curves &>(curves_id), GeometryOwnershipType::ReadOnly);
- const blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(
- curves_id.geometry);
- const blender::bke::AttributeAccessor src_attributes = curves.attributes();
-
- VArray<int> resolution = curves.resolution();
- VArray<int8_t> normal_mode = curves.normal_mode();
-
- VArraySpan<float> nurbs_weights{
- src_attributes.lookup_or_default<float>("nurbs_weight", ATTR_DOMAIN_POINT, 1.0f)};
- VArraySpan<int8_t> nurbs_orders{
- src_attributes.lookup_or_default<int8_t>("nurbs_order", ATTR_DOMAIN_CURVE, 4)};
- VArraySpan<int8_t> nurbs_knots_modes{
- src_attributes.lookup_or_default<int8_t>("knots_mode", ATTR_DOMAIN_CURVE, 0)};
-
- VArraySpan<int8_t> handle_types_right{
- src_attributes.lookup_or_default<int8_t>("handle_type_right", ATTR_DOMAIN_POINT, 0)};
- VArraySpan<int8_t> handle_types_left{
- src_attributes.lookup_or_default<int8_t>("handle_type_left", ATTR_DOMAIN_POINT, 0)};
-
- /* Create splines with the correct size and type. */
- VArray<int8_t> curve_types = curves.curve_types();
- std::unique_ptr<CurveEval> curve_eval = std::make_unique<CurveEval>();
- for (const int curve_index : curve_types.index_range()) {
- const IndexRange points = curves.points_for_curve(curve_index);
-
- std::unique_ptr<Spline> spline;
- /* #CurveEval does not support catmull rom curves, so convert those to poly splines. */
- switch (std::max<int8_t>(1, curve_types[curve_index])) {
- case CURVE_TYPE_POLY: {
- spline = std::make_unique<PolySpline>();
- spline->resize(points.size());
- break;
- }
- case CURVE_TYPE_BEZIER: {
- std::unique_ptr<BezierSpline> bezier_spline = std::make_unique<BezierSpline>();
- bezier_spline->resize(points.size());
- bezier_spline->set_resolution(resolution[curve_index]);
- bezier_spline->handle_types_left().copy_from(handle_types_left.slice(points));
- bezier_spline->handle_types_right().copy_from(handle_types_right.slice(points));
-
- spline = std::move(bezier_spline);
- break;
- }
- case CURVE_TYPE_NURBS: {
- std::unique_ptr<NURBSpline> nurb_spline = std::make_unique<NURBSpline>();
- nurb_spline->resize(points.size());
- nurb_spline->set_resolution(resolution[curve_index]);
- nurb_spline->weights().copy_from(nurbs_weights.slice(points));
- nurb_spline->set_order(nurbs_orders[curve_index]);
- nurb_spline->knots_mode = static_cast<KnotsMode>(nurbs_knots_modes[curve_index]);
-
- spline = std::move(nurb_spline);
- break;
- }
- case CURVE_TYPE_CATMULL_ROM:
- /* Not supported yet. */
- BLI_assert_unreachable();
- continue;
- }
- spline->positions().fill(float3(0));
- spline->tilts().fill(0.0f);
- spline->radii().fill(1.0f);
- spline->normal_mode = static_cast<NormalMode>(normal_mode[curve_index]);
- curve_eval->add_spline(std::move(spline));
- }
-
- curve_eval->attributes.reallocate(curve_eval->splines().size());
-
- CurveComponentLegacy dst_component;
- dst_component.replace(curve_eval.get(), GeometryOwnershipType::Editable);
- blender::bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
-
- copy_attributes_between_components(src_attributes,
- dst_attributes,
- {"curve_type",
- "resolution",
- "normal_mode",
- "nurbs_weight",
- "nurbs_order",
- "knots_mode",
- "handle_type_right",
- "handle_type_left"});
-
- return curve_eval;
-}
-
-Curves *curve_eval_to_curves(const CurveEval &curve_eval)
-{
- Curves *curves_id = blender::bke::curves_new_nomain(curve_eval.total_control_point_num(),
- curve_eval.splines().size());
- CurveComponent dst_component;
- dst_component.replace(curves_id, GeometryOwnershipType::Editable);
- blender::bke::MutableAttributeAccessor dst_attributes = *dst_component.attributes_for_write();
-
- blender::bke::CurvesGeometry &curves = blender::bke::CurvesGeometry::wrap(curves_id->geometry);
- curves.offsets_for_write().copy_from(curve_eval.control_point_offsets());
- MutableSpan<int8_t> curve_types = curves.curve_types_for_write();
-
- blender::bke::SpanAttributeWriter<int8_t> normal_mode =
- dst_attributes.lookup_or_add_for_write_only_span<int8_t>("normal_mode", ATTR_DOMAIN_CURVE);
- blender::bke::SpanAttributeWriter<float> nurbs_weight;
- blender::bke::SpanAttributeWriter<int8_t> nurbs_order;
- blender::bke::SpanAttributeWriter<int8_t> nurbs_knots_mode;
- if (curve_eval.has_spline_with_type(CURVE_TYPE_NURBS)) {
- nurbs_weight = dst_attributes.lookup_or_add_for_write_only_span<float>("nurbs_weight",
- ATTR_DOMAIN_POINT);
- nurbs_order = dst_attributes.lookup_or_add_for_write_only_span<int8_t>("nurbs_order",
- ATTR_DOMAIN_CURVE);
- nurbs_knots_mode = dst_attributes.lookup_or_add_for_write_only_span<int8_t>("knots_mode",
- ATTR_DOMAIN_CURVE);
- }
- blender::bke::SpanAttributeWriter<int8_t> handle_type_right;
- blender::bke::SpanAttributeWriter<int8_t> handle_type_left;
- if (curve_eval.has_spline_with_type(CURVE_TYPE_BEZIER)) {
- handle_type_right = dst_attributes.lookup_or_add_for_write_only_span<int8_t>(
- "handle_type_right", ATTR_DOMAIN_POINT);
- handle_type_left = dst_attributes.lookup_or_add_for_write_only_span<int8_t>("handle_type_left",
- ATTR_DOMAIN_POINT);
- }
-
- for (const int curve_index : curve_eval.splines().index_range()) {
- const Spline &spline = *curve_eval.splines()[curve_index];
- curve_types[curve_index] = curve_eval.splines()[curve_index]->type();
- normal_mode.span[curve_index] = curve_eval.splines()[curve_index]->normal_mode;
- const IndexRange points = curves.points_for_curve(curve_index);
-
- switch (spline.type()) {
- case CURVE_TYPE_POLY:
- break;
- case CURVE_TYPE_BEZIER: {
- const BezierSpline &src = static_cast<const BezierSpline &>(spline);
- handle_type_right.span.slice(points).copy_from(src.handle_types_right());
- handle_type_left.span.slice(points).copy_from(src.handle_types_left());
- break;
- }
- case CURVE_TYPE_NURBS: {
- const NURBSpline &src = static_cast<const NURBSpline &>(spline);
- nurbs_knots_mode.span[curve_index] = static_cast<int8_t>(src.knots_mode);
- nurbs_order.span[curve_index] = src.order();
- nurbs_weight.span.slice(points).copy_from(src.weights());
- break;
- }
- case CURVE_TYPE_CATMULL_ROM: {
- BLI_assert_unreachable();
- break;
- }
- }
- }
-
- curves.update_curve_types();
-
- normal_mode.finish();
- nurbs_weight.finish();
- nurbs_order.finish();
- nurbs_knots_mode.finish();
- handle_type_right.finish();
- handle_type_left.finish();
-
- CurveComponentLegacy src_component;
- src_component.replace(&const_cast<CurveEval &>(curve_eval), GeometryOwnershipType::ReadOnly);
- const blender::bke::AttributeAccessor src_attributes = *src_component.attributes();
-
- copy_attributes_between_components(src_attributes, dst_attributes, {});
-
- return curves_id;
-}
-
-void CurveEval::assert_valid_point_attributes() const
-{
-#ifdef DEBUG
- if (splines_.size() == 0) {
- return;
- }
- const int layer_len = splines_.first()->attributes.data.totlayer;
-
- Array<AttributeIDRef> ids_in_order(layer_len);
- Array<AttributeMetaData> meta_data_in_order(layer_len);
-
- {
- int i = 0;
- splines_.first()->attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- ids_in_order[i] = attribute_id;
- meta_data_in_order[i] = meta_data;
- i++;
- return true;
- },
- ATTR_DOMAIN_POINT);
- }
-
- for (const SplinePtr &spline : splines_) {
- /* All splines should have the same number of attributes. */
- BLI_assert(spline->attributes.data.totlayer == layer_len);
-
- int i = 0;
- spline->attributes.foreach_attribute(
- [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
- /* Attribute names and IDs should have the same order and exist on all splines. */
- BLI_assert(attribute_id == ids_in_order[i]);
-
- /* Attributes with the same ID different splines should all have the same type. */
- BLI_assert(meta_data == meta_data_in_order[i]);
-
- i++;
- return true;
- },
- ATTR_DOMAIN_POINT);
- }
-
-#endif
-}
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index 06789e34ad4..86bf3115c36 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -1558,6 +1558,11 @@ GVArray CurvesGeometry::adapt_domain(const GVArray &varray,
if (from == to) {
return varray;
}
+ if (varray.is_single()) {
+ BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), value);
+ varray.get_internal_single(value);
+ return GVArray::ForSingle(varray.type(), this->attributes().domain_size(to), value);
+ }
if (from == ATTR_DOMAIN_POINT && to == ATTR_DOMAIN_CURVE) {
return adapt_curve_domain_point_to_curve(*this, varray);
diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc
index d98832e796c..f5a69a995a3 100644
--- a/source/blender/blenkernel/intern/curves_utils.cc
+++ b/source/blender/blenkernel/intern/curves_utils.cc
@@ -84,6 +84,21 @@ void fill_points(const CurvesGeometry &curves,
});
}
+void fill_points(const CurvesGeometry &curves,
+ Span<IndexRange> curve_ranges,
+ GPointer value,
+ GMutableSpan dst)
+{
+ BLI_assert(*value.type() == dst.type());
+ const CPPType &type = dst.type();
+ threading::parallel_for(curve_ranges.index_range(), 512, [&](IndexRange range) {
+ for (const IndexRange range : curve_ranges.slice(range)) {
+ const IndexRange points = curves.points_for_curves(range);
+ type.fill_assign_n(value.get(), dst.slice(points).data(), points.size());
+ }
+ });
+}
+
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
{
bke::CurvesGeometry dst_curves(0, src_curves.curves_num());
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 64e2d00dc1b..51c3b405ebc 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -1869,9 +1869,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 29: CD_BWEIGHT */
{sizeof(MFloatProperty), "MFloatProperty", 1, nullptr, nullptr, nullptr, layerInterp_bweight},
/* 30: CD_CREASE */
- /* NOTE: we do not interpolate crease data as it should be either inherited for subdivided
- * edges, or for vertex creases, only present on the original vertex. */
- {sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, nullptr},
+ {sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, layerInterp_propFloat},
/* 31: CD_ORIGSPACE_MLOOP */
{sizeof(OrigSpaceLoop),
"OrigSpaceLoop",
@@ -1967,7 +1965,7 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(short[4][3]), "", 0, nullptr, nullptr, nullptr, nullptr, layerSwap_flnor, nullptr},
/* 41: CD_CUSTOMLOOPNORMAL */
{sizeof(short[2]), "vec2s", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
- /* 42: CD_SCULPT_FACE_SETS */
+ /* 42: CD_SCULPT_FACE_SETS */ /* DEPRECATED */
{sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
/* 43: CD_LOCATION */
{sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr},
@@ -2124,11 +2122,11 @@ const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = {
const CustomData_MeshMasks CD_MASK_MESH = {
/* vmask */ (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK |
CD_MASK_PROP_ALL | CD_MASK_CREASE | CD_MASK_BWEIGHT),
- /* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_BWEIGHT),
+ /* emask */
+ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL | CD_MASK_BWEIGHT | CD_MASK_CREASE),
/* fmask */ 0,
/* pmask */
- (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL),
/* lmask */
(CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_CUSTOMLOOPNORMAL |
CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL),
@@ -2137,11 +2135,12 @@ const CustomData_MeshMasks CD_MASK_DERIVEDMESH = {
/* vmask */ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN |
CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL |
CD_MASK_CREASE | CD_MASK_BWEIGHT),
- /* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_BWEIGHT | CD_MASK_PROP_ALL),
+ /* emask */
+ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_BWEIGHT | CD_MASK_PROP_ALL |
+ CD_MASK_CREASE),
/* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT),
/* pmask */
- (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL |
- CD_MASK_SCULPT_FACE_SETS),
+ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL),
/* lmask */
(CD_MASK_MLOOPUV | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL |
CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */
@@ -2152,7 +2151,7 @@ const CustomData_MeshMasks CD_MASK_BMESH = {
/* emask */ (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL),
/* fmask */ 0,
/* pmask */
- (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL),
/* lmask */
(CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK |
CD_MASK_PROP_ALL),
@@ -2171,7 +2170,7 @@ const CustomData_MeshMasks CD_MASK_EVERYTHING = {
CD_MASK_PROP_ALL),
/* pmask */
(CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_FACEMAP |
- CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS),
+ CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL),
/* lmask */
(CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV |
CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL |
@@ -2373,7 +2372,14 @@ bool CustomData_merge(const CustomData *source,
static bool attribute_stored_in_bmesh_flag(const StringRef name)
{
- return ELEM(name, ".hide_vert", ".hide_edge", ".hide_poly", "material_index");
+ return ELEM(name,
+ ".hide_vert",
+ ".hide_edge",
+ ".hide_poly",
+ ".select_vert",
+ ".select_edge",
+ ".select_poly",
+ "material_index");
}
static CustomData shallow_copy_remove_non_bmesh_attributes(const CustomData &src)
@@ -5546,3 +5552,8 @@ eCustomDataType cpp_type_to_custom_data_type(const blender::CPPType &type)
/** \} */
} // namespace blender::bke
+
+size_t CustomData_get_elem_size(CustomDataLayer *layer)
+{
+ return LAYERTYPEINFO[layer->type].size;
+}
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index 6c7715c625e..36f038e68ab 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -199,7 +199,7 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
case DT_TYPE_SEAM:
return CD_FAKE_SEAM;
case DT_TYPE_CREASE:
- return CD_FAKE_CREASE;
+ return CD_CREASE;
case DT_TYPE_BWEIGHT_EDGE:
return CD_BWEIGHT;
case DT_TYPE_FREESTYLE_EDGE:
@@ -403,31 +403,6 @@ float data_transfer_interp_float_do(const int mix_mode,
return interpf(val_ret, val_dst, mix_factor);
}
-static void data_transfer_interp_char(const CustomDataTransferLayerMap *laymap,
- void *dest,
- const void **sources,
- const float *weights,
- const int count,
- const float mix_factor)
-{
- const char **data_src = (const char **)sources;
- char *data_dst = (char *)dest;
-
- const int mix_mode = laymap->mix_mode;
- float val_src = 0.0f;
- const float val_dst = (float)(*data_dst) / 255.0f;
-
- for (int i = count; i--;) {
- val_src += ((float)(*data_src[i]) / 255.0f) * weights[i];
- }
-
- val_src = data_transfer_interp_float_do(mix_mode, val_dst, val_src, mix_factor);
-
- CLAMP(val_src, 0.0f, 1.0f);
-
- *data_dst = (char)(val_src * 255.0f);
-}
-
/* Helpers to match sources and destinations data layers
* (also handles 'conversions' in CD_FAKE cases). */
@@ -981,39 +956,6 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
}
return true;
}
- if (cddata_type == CD_FAKE_CREASE) {
- const size_t elem_size = sizeof(*((MEdge *)NULL));
- const size_t data_size = sizeof(((MEdge *)NULL)->crease);
- const size_t data_offset = offsetof(MEdge, crease);
- const uint64_t data_flag = 0;
-
- if (!(me_src->cd_flag & ME_CDFLAG_EDGE_CREASE)) {
- if (use_delete) {
- me_dst->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
- }
- return true;
- }
- me_dst->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- if (r_map) {
- data_transfer_layersmapping_add_item(r_map,
- cddata_type,
- mix_mode,
- mix_factor,
- mix_weights,
- BKE_mesh_edges(me_src),
- BKE_mesh_edges_for_write(me_dst),
- me_src->totedge,
- me_dst->totedge,
- elem_size,
- data_size,
- data_offset,
- data_flag,
- data_transfer_interp_char,
- interp_data);
- }
- return true;
- }
-
if (r_map && ELEM(cddata_type, CD_FAKE_SHARP, CD_FAKE_SEAM)) {
const size_t elem_size = sizeof(*((MEdge *)NULL));
const size_t data_size = sizeof(((MEdge *)NULL)->flag);
diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc
index b87d675496c..279166297ec 100644
--- a/source/blender/blenkernel/intern/displist.cc
+++ b/source/blender/blenkernel/intern/displist.cc
@@ -634,7 +634,7 @@ void BKE_curve_calc_modifiers_pre(Depsgraph *depsgraph,
/**
* \return True if the deformed curve control point data should be implicitly
- * converted directly to a mesh, or false if it can be left as curve data via #CurveEval.
+ * converted directly to a mesh, or false if it can be left as curve data via the #Curves type.
*/
static bool do_curve_implicit_mesh_conversion(const Curve *curve,
ModifierData *first_modifier,
diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c
index 6e53254d162..349614b93dd 100644
--- a/source/blender/blenkernel/intern/fluid.c
+++ b/source/blender/blenkernel/intern/fluid.c
@@ -80,7 +80,7 @@
/** Max value for phi initialization */
#define PHI_MAX 9999.0f
-static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock);
+static void fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock);
#ifdef WITH_FLUID
// #define DEBUG_PRINT
@@ -482,7 +482,7 @@ static void update_final_gravity(FluidDomainSettings *fds, Scene *scene)
mul_v3_fl(fds->gravity_final, fds->effector_weights->global_gravity);
}
-static bool BKE_fluid_modifier_init(
+static bool fluid_modifier_init(
FluidModifierData *fmd, Depsgraph *depsgraph, Object *ob, Scene *scene, Mesh *me)
{
int scene_framenr = (int)DEG_get_ctime(depsgraph);
@@ -998,7 +998,6 @@ static void obstacles_from_mesh(Object *coll_ob,
float dt)
{
if (fes->mesh) {
- Mesh *me = NULL;
const MLoopTri *looptri;
BVHTreeFromMesh tree_data = {NULL};
int numverts, i;
@@ -1006,13 +1005,11 @@ static void obstacles_from_mesh(Object *coll_ob,
float *vert_vel = NULL;
bool has_velocity = false;
- me = BKE_mesh_copy_for_eval(fes->mesh, true);
+ Mesh *me = BKE_mesh_copy_for_eval(fes->mesh, false);
+ MVert *verts = BKE_mesh_verts_for_write(me);
int min[3], max[3], res[3];
- /* Duplicate vertices to modify. */
- MVert *verts = MEM_dupallocN(BKE_mesh_verts(me));
-
const MLoop *mloop = BKE_mesh_loops(me);
looptri = BKE_mesh_runtime_looptri_ensure(me);
numverts = me->totvert;
@@ -1097,7 +1094,6 @@ static void obstacles_from_mesh(Object *coll_ob,
if (vert_vel) {
MEM_freeN(vert_vel);
}
- MEM_SAFE_FREE(verts);
BKE_id_free(NULL, me);
}
}
@@ -2074,10 +2070,8 @@ static void emit_from_mesh(
/* Copy mesh for thread safety as we modify it.
* Main issue is its VertArray being modified, then replaced and freed. */
- Mesh *me = BKE_mesh_copy_for_eval(ffs->mesh, true);
-
- /* Duplicate vertices to modify. */
- MVert *verts = MEM_dupallocN(BKE_mesh_verts(me));
+ Mesh *me = BKE_mesh_copy_for_eval(ffs->mesh, false);
+ MVert *verts = BKE_mesh_verts_for_write(me);
const MLoop *mloop = BKE_mesh_loops(me);
const MLoopTri *mlooptri = BKE_mesh_runtime_looptri_ensure(me);
@@ -2102,7 +2096,8 @@ static void emit_from_mesh(
/* Transform mesh vertices to domain grid space for fast lookups.
* This is valid because the mesh is copied above. */
- float(*vert_normals)[3] = MEM_dupallocN(BKE_mesh_vertex_normals_ensure(me));
+ BKE_mesh_vertex_normals_ensure(me);
+ float(*vert_normals)[3] = BKE_mesh_vertex_normals_for_write(me);
for (i = 0; i < numverts; i++) {
/* Vertex position. */
mul_m4_v3(flow_ob->obmat, verts[i].co);
@@ -2178,8 +2173,6 @@ static void emit_from_mesh(
if (vert_vel) {
MEM_freeN(vert_vel);
}
- MEM_SAFE_FREE(verts);
- MEM_SAFE_FREE(vert_normals);
BKE_id_free(NULL, me);
}
}
@@ -3622,15 +3615,15 @@ static void manta_guiding(
BLI_mutex_unlock(&object_update_lock);
}
-static void BKE_fluid_modifier_processFlow(FluidModifierData *fmd,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- Mesh *me,
- const int scene_framenr)
+static void fluid_modifier_processFlow(FluidModifierData *fmd,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *me,
+ const int scene_framenr)
{
if (scene_framenr >= fmd->time) {
- BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me);
+ fluid_modifier_init(fmd, depsgraph, ob, scene, me);
}
if (fmd->flow) {
@@ -3645,19 +3638,19 @@ static void BKE_fluid_modifier_processFlow(FluidModifierData *fmd,
}
else if (scene_framenr < fmd->time) {
fmd->time = scene_framenr;
- BKE_fluid_modifier_reset_ex(fmd, false);
+ fluid_modifier_reset_ex(fmd, false);
}
}
-static void BKE_fluid_modifier_processEffector(FluidModifierData *fmd,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- Mesh *me,
- const int scene_framenr)
+static void fluid_modifier_processEffector(FluidModifierData *fmd,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *me,
+ const int scene_framenr)
{
if (scene_framenr >= fmd->time) {
- BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me);
+ fluid_modifier_init(fmd, depsgraph, ob, scene, me);
}
if (fmd->effector) {
@@ -3672,16 +3665,16 @@ static void BKE_fluid_modifier_processEffector(FluidModifierData *fmd,
}
else if (scene_framenr < fmd->time) {
fmd->time = scene_framenr;
- BKE_fluid_modifier_reset_ex(fmd, false);
+ fluid_modifier_reset_ex(fmd, false);
}
}
-static void BKE_fluid_modifier_processDomain(FluidModifierData *fmd,
- Depsgraph *depsgraph,
- Scene *scene,
- Object *ob,
- Mesh *me,
- const int scene_framenr)
+static void fluid_modifier_processDomain(FluidModifierData *fmd,
+ Depsgraph *depsgraph,
+ Scene *scene,
+ Object *ob,
+ Mesh *me,
+ const int scene_framenr)
{
FluidDomainSettings *fds = fmd->domain;
Object *guide_parent = NULL;
@@ -3727,7 +3720,7 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *fmd,
/* Reset fluid if no fluid present. Also resets active fields. */
if (!fds->fluid) {
- BKE_fluid_modifier_reset_ex(fmd, false);
+ fluid_modifier_reset_ex(fmd, false);
}
/* Ensure cache directory is not relative. */
@@ -3755,12 +3748,12 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *fmd,
if (pid.cache->flag & PTCACHE_OUTDATED) {
BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED);
BKE_fluid_cache_free_all(fds, ob);
- BKE_fluid_modifier_reset_ex(fmd, false);
+ fluid_modifier_reset_ex(fmd, false);
}
}
/* Fluid domain init must not fail in order to continue modifier evaluation. */
- if (!fds->fluid && !BKE_fluid_modifier_init(fmd, depsgraph, ob, scene, me)) {
+ if (!fds->fluid && !fluid_modifier_init(fmd, depsgraph, ob, scene, me)) {
CLOG_ERROR(&LOG, "Fluid initialization failed. Should not happen!");
return;
}
@@ -4088,19 +4081,19 @@ static void BKE_fluid_modifier_processDomain(FluidModifierData *fmd,
fmd->time = scene_framenr;
}
-static void BKE_fluid_modifier_process(
+static void fluid_modifier_process(
FluidModifierData *fmd, Depsgraph *depsgraph, Scene *scene, Object *ob, Mesh *me)
{
const int scene_framenr = (int)DEG_get_ctime(depsgraph);
if (fmd->type & MOD_FLUID_TYPE_FLOW) {
- BKE_fluid_modifier_processFlow(fmd, depsgraph, scene, ob, me, scene_framenr);
+ fluid_modifier_processFlow(fmd, depsgraph, scene, ob, me, scene_framenr);
}
else if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
- BKE_fluid_modifier_processEffector(fmd, depsgraph, scene, ob, me, scene_framenr);
+ fluid_modifier_processEffector(fmd, depsgraph, scene, ob, me, scene_framenr);
}
else if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
- BKE_fluid_modifier_processDomain(fmd, depsgraph, scene, ob, me, scene_framenr);
+ fluid_modifier_processDomain(fmd, depsgraph, scene, ob, me, scene_framenr);
}
}
@@ -4118,7 +4111,7 @@ struct Mesh *BKE_fluid_modifier_do(
BLI_rw_mutex_lock(fmd->domain->fluid_mutex, THREAD_LOCK_WRITE);
}
- BKE_fluid_modifier_process(fmd, depsgraph, scene, ob, me);
+ fluid_modifier_process(fmd, depsgraph, scene, ob, me);
if ((fmd->type & MOD_FLUID_TYPE_DOMAIN) && fmd->domain) {
BLI_rw_mutex_unlock(fmd->domain->fluid_mutex);
@@ -4693,7 +4686,7 @@ void BKE_fluid_fields_sanitize(FluidDomainSettings *settings)
* Use for versioning, even when fluids are disabled.
* \{ */
-static void BKE_fluid_modifier_freeDomain(FluidModifierData *fmd)
+static void fluid_modifier_freeDomain(FluidModifierData *fmd)
{
if (fmd->domain) {
if (fmd->domain->fluid) {
@@ -4722,7 +4715,7 @@ static void BKE_fluid_modifier_freeDomain(FluidModifierData *fmd)
}
}
-static void BKE_fluid_modifier_freeFlow(FluidModifierData *fmd)
+static void fluid_modifier_freeFlow(FluidModifierData *fmd)
{
if (fmd->flow) {
if (fmd->flow->mesh) {
@@ -4739,7 +4732,7 @@ static void BKE_fluid_modifier_freeFlow(FluidModifierData *fmd)
}
}
-static void BKE_fluid_modifier_freeEffector(FluidModifierData *fmd)
+static void fluid_modifier_freeEffector(FluidModifierData *fmd)
{
if (fmd->effector) {
if (fmd->effector->mesh) {
@@ -4756,7 +4749,7 @@ static void BKE_fluid_modifier_freeEffector(FluidModifierData *fmd)
}
}
-static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock)
+static void fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need_lock)
{
if (!fmd) {
return;
@@ -4796,7 +4789,7 @@ static void BKE_fluid_modifier_reset_ex(struct FluidModifierData *fmd, bool need
void BKE_fluid_modifier_reset(struct FluidModifierData *fmd)
{
- BKE_fluid_modifier_reset_ex(fmd, true);
+ fluid_modifier_reset_ex(fmd, true);
}
void BKE_fluid_modifier_free(FluidModifierData *fmd)
@@ -4805,9 +4798,9 @@ void BKE_fluid_modifier_free(FluidModifierData *fmd)
return;
}
- BKE_fluid_modifier_freeDomain(fmd);
- BKE_fluid_modifier_freeFlow(fmd);
- BKE_fluid_modifier_freeEffector(fmd);
+ fluid_modifier_freeDomain(fmd);
+ fluid_modifier_freeFlow(fmd);
+ fluid_modifier_freeEffector(fmd);
}
void BKE_fluid_modifier_create_type_data(struct FluidModifierData *fmd)
@@ -4818,7 +4811,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *fmd)
if (fmd->type & MOD_FLUID_TYPE_DOMAIN) {
if (fmd->domain) {
- BKE_fluid_modifier_freeDomain(fmd);
+ fluid_modifier_freeDomain(fmd);
}
fmd->domain = DNA_struct_default_alloc(FluidDomainSettings);
@@ -4850,7 +4843,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *fmd)
}
else if (fmd->type & MOD_FLUID_TYPE_FLOW) {
if (fmd->flow) {
- BKE_fluid_modifier_freeFlow(fmd);
+ fluid_modifier_freeFlow(fmd);
}
fmd->flow = DNA_struct_default_alloc(FluidFlowSettings);
@@ -4858,7 +4851,7 @@ void BKE_fluid_modifier_create_type_data(struct FluidModifierData *fmd)
}
else if (fmd->type & MOD_FLUID_TYPE_EFFEC) {
if (fmd->effector) {
- BKE_fluid_modifier_freeEffector(fmd);
+ fluid_modifier_freeEffector(fmd);
}
fmd->effector = DNA_struct_default_alloc(FluidEffectorSettings);
diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc
deleted file mode 100644
index 8e482e4c691..00000000000
--- a/source/blender/blenkernel/intern/geometry_component_curve.cc
+++ /dev/null
@@ -1,1464 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_task.hh"
-
-#include "DNA_ID_enums.h"
-#include "DNA_curve_types.h"
-
-#include "BKE_attribute_math.hh"
-#include "BKE_curve.h"
-#include "BKE_geometry_set.hh"
-#include "BKE_lib_id.h"
-#include "BKE_spline.hh"
-
-#include "attribute_access_intern.hh"
-
-using blender::GMutableSpan;
-using blender::GSpan;
-using blender::GVArray;
-using blender::GVArraySpan;
-
-/* -------------------------------------------------------------------- */
-/** \name Geometry Component Implementation
- * \{ */
-
-CurveComponentLegacy::CurveComponentLegacy() : GeometryComponent(GEO_COMPONENT_TYPE_CURVE)
-{
-}
-
-CurveComponentLegacy::~CurveComponentLegacy()
-{
- this->clear();
-}
-
-GeometryComponent *CurveComponentLegacy::copy() const
-{
- CurveComponentLegacy *new_component = new CurveComponentLegacy();
- if (curve_ != nullptr) {
- new_component->curve_ = new CurveEval(*curve_);
- new_component->ownership_ = GeometryOwnershipType::Owned;
- }
- return new_component;
-}
-
-void CurveComponentLegacy::clear()
-{
- BLI_assert(this->is_mutable());
- if (curve_ != nullptr) {
- if (ownership_ == GeometryOwnershipType::Owned) {
- delete curve_;
- }
- curve_ = nullptr;
- }
-}
-
-bool CurveComponentLegacy::has_curve() const
-{
- return curve_ != nullptr;
-}
-
-void CurveComponentLegacy::replace(CurveEval *curve, GeometryOwnershipType ownership)
-{
- BLI_assert(this->is_mutable());
- this->clear();
- curve_ = curve;
- ownership_ = ownership;
-}
-
-CurveEval *CurveComponentLegacy::release()
-{
- BLI_assert(this->is_mutable());
- CurveEval *curve = curve_;
- curve_ = nullptr;
- return curve;
-}
-
-const CurveEval *CurveComponentLegacy::get_for_read() const
-{
- return curve_;
-}
-
-CurveEval *CurveComponentLegacy::get_for_write()
-{
- BLI_assert(this->is_mutable());
- if (ownership_ == GeometryOwnershipType::ReadOnly) {
- curve_ = new CurveEval(*curve_);
- ownership_ = GeometryOwnershipType::Owned;
- }
- return curve_;
-}
-
-bool CurveComponentLegacy::is_empty() const
-{
- return curve_ == nullptr;
-}
-
-bool CurveComponentLegacy::owns_direct_data() const
-{
- return ownership_ == GeometryOwnershipType::Owned;
-}
-
-void CurveComponentLegacy::ensure_owns_direct_data()
-{
- BLI_assert(this->is_mutable());
- if (ownership_ != GeometryOwnershipType::Owned) {
- curve_ = new CurveEval(*curve_);
- ownership_ = GeometryOwnershipType::Owned;
- }
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Attribute Access Helper Functions
- * \{ */
-
-namespace blender::bke {
-
-namespace {
-struct PointIndices {
- int spline_index;
- int point_index;
-};
-} // namespace
-static PointIndices lookup_point_indices(Span<int> offsets, const int index)
-{
- const int spline_index = std::upper_bound(offsets.begin(), offsets.end(), index) -
- offsets.begin() - 1;
- const int index_in_spline = index - offsets[spline_index];
- return {spline_index, index_in_spline};
-}
-
-/**
- * Mix together all of a spline's control point values.
- *
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<typename T>
-static void adapt_curve_domain_point_to_spline_impl(const CurveEval &curve,
- const VArray<T> &old_values,
- MutableSpan<T> r_values)
-{
- const int splines_len = curve.splines().size();
- Array<int> offsets = curve.control_point_offsets();
- BLI_assert(r_values.size() == splines_len);
- attribute_math::DefaultMixer<T> mixer(r_values);
-
- for (const int i_spline : IndexRange(splines_len)) {
- const int spline_offset = offsets[i_spline];
- const int spline_point_len = offsets[i_spline + 1] - spline_offset;
- for (const int i_point : IndexRange(spline_point_len)) {
- const T value = old_values[spline_offset + i_point];
- mixer.mix_in(i_spline, value);
- }
- }
-
- mixer.finalize();
-}
-
-/**
- * A spline is selected if all of its control points were selected.
- *
- * \note Theoretically this interpolation does not need to compute all values at once.
- * However, doing that makes the implementation simpler, and this can be optimized in the future if
- * only some values are required.
- */
-template<>
-void adapt_curve_domain_point_to_spline_impl(const CurveEval &curve,
- const VArray<bool> &old_values,
- MutableSpan<bool> r_values)
-{
- const int splines_len = curve.splines().size();
- Array<int> offsets = curve.control_point_offsets();
- BLI_assert(r_values.size() == splines_len);
-
- r_values.fill(true);
-
- for (const int i_spline : IndexRange(splines_len)) {
- const int spline_offset = offsets[i_spline];
- const int spline_point_len = offsets[i_spline + 1] - spline_offset;
-
- for (const int i_point : IndexRange(spline_point_len)) {
- if (!old_values[spline_offset + i_point]) {
- r_values[i_spline] = false;
- break;
- }
- }
- }
-}
-
-static GVArray adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArray varray)
-{
- GVArray new_varray;
- attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
- using T = decltype(dummy);
- if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
- Array<T> values(curve.splines().size());
- adapt_curve_domain_point_to_spline_impl<T>(curve, varray.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
- }
- });
- return new_varray;
-}
-
-/**
- * A virtual array implementation for the conversion of spline attributes to control point
- * attributes. The goal is to avoid copying the spline value for every one of its control points
- * unless it is necessary (in that case the materialize functions will be called).
- */
-template<typename T> class VArray_For_SplineToPoint final : public VArrayImpl<T> {
- GVArray original_varray_;
- /* Store existing data materialized if it was not already a span. This is expected
- * to be worth it because a single spline's value will likely be accessed many times. */
- VArraySpan<T> original_data_;
- Array<int> offsets_;
-
- public:
- VArray_For_SplineToPoint(GVArray original_varray, Array<int> offsets)
- : VArrayImpl<T>(offsets.last()),
- original_varray_(std::move(original_varray)),
- original_data_(original_varray_.typed<T>()),
- offsets_(std::move(offsets))
- {
- }
-
- T get(const int64_t index) const final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- return original_data_[indices.spline_index];
- }
-
- void materialize(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- const int total_num = offsets_.last();
- if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
- for (const int spline_index : original_data_.index_range()) {
- const int offset = offsets_[spline_index];
- const int next_offset = offsets_[spline_index + 1];
- r_span.slice(offset, next_offset - offset).fill(original_data_[spline_index]);
- }
- }
- else {
- int spline_index = 0;
- for (const int dst_index : mask) {
- while (offsets_[spline_index] < dst_index) {
- spline_index++;
- }
- r_span[dst_index] = original_data_[spline_index];
- }
- }
- }
-
- void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- T *dst = r_span.data();
- const int total_num = offsets_.last();
- if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
- for (const int spline_index : original_data_.index_range()) {
- const int offset = offsets_[spline_index];
- const int next_offset = offsets_[spline_index + 1];
- uninitialized_fill_n(dst + offset, next_offset - offset, original_data_[spline_index]);
- }
- }
- else {
- int spline_index = 0;
- for (const int dst_index : mask) {
- while (offsets_[spline_index] < dst_index) {
- spline_index++;
- }
- new (dst + dst_index) T(original_data_[spline_index]);
- }
- }
- }
-};
-
-static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArray varray)
-{
- GVArray new_varray;
- attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
- using T = decltype(dummy);
-
- Array<int> offsets = curve.control_point_offsets();
- new_varray = VArray<T>::template For<VArray_For_SplineToPoint<T>>(std::move(varray),
- std::move(offsets));
- });
- return new_varray;
-}
-
-} // namespace blender::bke
-
-static GVArray adapt_curve_attribute_domain(const CurveEval &curve,
- const GVArray &varray,
- const eAttrDomain from_domain,
- const eAttrDomain to_domain)
-{
- if (!varray) {
- return {};
- }
- if (varray.is_empty()) {
- return {};
- }
- if (from_domain == to_domain) {
- return varray;
- }
-
- if (from_domain == ATTR_DOMAIN_POINT && to_domain == ATTR_DOMAIN_CURVE) {
- return blender::bke::adapt_curve_domain_point_to_spline(curve, std::move(varray));
- }
- if (from_domain == ATTR_DOMAIN_CURVE && to_domain == ATTR_DOMAIN_POINT) {
- return blender::bke::adapt_curve_domain_spline_to_point(curve, std::move(varray));
- }
-
- return {};
-}
-
-/** \} */
-
-namespace blender::bke {
-
-/* -------------------------------------------------------------------- */
-/** \name Builtin Spline Attributes
- *
- * Attributes with a value for every spline, stored contiguously or in every spline separately.
- * \{ */
-
-class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
- using AsReadAttribute = GVArray (*)(const CurveEval &data);
- using AsWriteAttribute = GVMutableArray (*)(CurveEval &data);
- const AsReadAttribute as_read_attribute_;
- const AsWriteAttribute as_write_attribute_;
-
- public:
- BuiltinSplineAttributeProvider(std::string attribute_name,
- const eCustomDataType attribute_type,
- const WritableEnum writable,
- const AsReadAttribute as_read_attribute,
- const AsWriteAttribute as_write_attribute)
- : BuiltinAttributeProvider(std::move(attribute_name),
- ATTR_DOMAIN_CURVE,
- attribute_type,
- BuiltinAttributeProvider::NonCreatable,
- writable,
- BuiltinAttributeProvider::NonDeletable),
- as_read_attribute_(as_read_attribute),
- as_write_attribute_(as_write_attribute)
- {
- }
-
- GVArray try_get_for_read(const void *owner) const final
- {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- if (curve == nullptr) {
- return {};
- }
- return as_read_attribute_(*curve);
- }
-
- GAttributeWriter try_get_for_write(void *owner) const final
- {
- if (writable_ != Writable) {
- return {};
- }
- CurveEval *curve = static_cast<CurveEval *>(owner);
- if (curve == nullptr) {
- return {};
- }
- return {as_write_attribute_(*curve), domain_};
- }
-
- bool try_delete(void *UNUSED(owner)) const final
- {
- return false;
- }
-
- bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
- {
- return false;
- }
-
- bool exists(const void *owner) const final
- {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- return !curve->splines().is_empty();
- }
-};
-
-static int get_spline_resolution(const SplinePtr &spline)
-{
- if (const BezierSpline *bezier_spline = dynamic_cast<const BezierSpline *>(spline.get())) {
- return bezier_spline->resolution();
- }
- if (const NURBSpline *nurb_spline = dynamic_cast<const NURBSpline *>(spline.get())) {
- return nurb_spline->resolution();
- }
- return 1;
-}
-
-static void set_spline_resolution(SplinePtr &spline, const int resolution)
-{
- if (BezierSpline *bezier_spline = dynamic_cast<BezierSpline *>(spline.get())) {
- bezier_spline->set_resolution(std::max(resolution, 1));
- }
- if (NURBSpline *nurb_spline = dynamic_cast<NURBSpline *>(spline.get())) {
- nurb_spline->set_resolution(std::max(resolution, 1));
- }
-}
-
-static GVArray make_resolution_read_attribute(const CurveEval &curve)
-{
- return VArray<int>::ForDerivedSpan<SplinePtr, get_spline_resolution>(curve.splines());
-}
-
-static GVMutableArray make_resolution_write_attribute(CurveEval &curve)
-{
- return VMutableArray<int>::
- ForDerivedSpan<SplinePtr, get_spline_resolution, set_spline_resolution>(curve.splines());
-}
-
-static bool get_cyclic_value(const SplinePtr &spline)
-{
- return spline->is_cyclic();
-}
-
-static void set_cyclic_value(SplinePtr &spline, const bool value)
-{
- if (spline->is_cyclic() != value) {
- spline->set_cyclic(value);
- spline->mark_cache_invalid();
- }
-}
-
-static GVArray make_cyclic_read_attribute(const CurveEval &curve)
-{
- return VArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value>(curve.splines());
-}
-
-static GVMutableArray make_cyclic_write_attribute(CurveEval &curve)
-{
- return VMutableArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value, set_cyclic_value>(
- curve.splines());
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Builtin Control Point Attributes
- *
- * Attributes with a value for every control point. Most of the complexity here is due to the fact
- * that we must provide access to the attribute data as if it was a contiguous array when it is
- * really stored separately on each spline. That will be inherently rather slow, but these virtual
- * array implementations try to make it workable in common situations.
- * \{ */
-
-/**
- * Individual spans in \a data may be empty if that spline contains no data for the attribute.
- */
-template<typename T>
-static void point_attribute_materialize(Span<Span<T>> data,
- Span<int> offsets,
- const IndexMask mask,
- MutableSpan<T> r_span)
-{
- const int total_num = offsets.last();
- if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
- for (const int spline_index : data.index_range()) {
- const int offset = offsets[spline_index];
- const int next_offset = offsets[spline_index + 1];
-
- Span<T> src = data[spline_index];
- MutableSpan<T> dst = r_span.slice(offset, next_offset - offset);
- if (src.is_empty()) {
- dst.fill(T());
- }
- else {
- dst.copy_from(src);
- }
- }
- }
- else {
- int spline_index = 0;
- for (const int dst_index : mask) {
- /* Skip splines that don't have any control points in the mask. */
- while (dst_index >= offsets[spline_index + 1]) {
- spline_index++;
- }
-
- const int index_in_spline = dst_index - offsets[spline_index];
- Span<T> src = data[spline_index];
- if (src.is_empty()) {
- r_span[dst_index] = T();
- }
- else {
- r_span[dst_index] = src[index_in_spline];
- }
- }
- }
-}
-
-/**
- * Individual spans in \a data may be empty if that spline contains no data for the attribute.
- */
-template<typename T>
-static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data,
- Span<int> offsets,
- const IndexMask mask,
- MutableSpan<T> r_span)
-{
- T *dst = r_span.data();
- const int total_num = offsets.last();
- if (mask.is_range() && mask.as_range() == IndexRange(total_num)) {
- for (const int spline_index : data.index_range()) {
- const int offset = offsets[spline_index];
- const int next_offset = offsets[spline_index + 1];
-
- Span<T> src = data[spline_index];
- if (src.is_empty()) {
- uninitialized_fill_n(dst + offset, next_offset - offset, T());
- }
- else {
- uninitialized_copy_n(src.data(), next_offset - offset, dst + offset);
- }
- }
- }
- else {
- int spline_index = 0;
- for (const int dst_index : mask) {
- /* Skip splines that don't have any control points in the mask. */
- while (dst_index >= offsets[spline_index + 1]) {
- spline_index++;
- }
-
- const int index_in_spline = dst_index - offsets[spline_index];
- Span<T> src = data[spline_index];
- if (src.is_empty()) {
- new (dst + dst_index) T();
- }
- else {
- new (dst + dst_index) T(src[index_in_spline]);
- }
- }
- }
-}
-
-static GVArray varray_from_initializer(const AttributeInit &initializer,
- const eCustomDataType data_type,
- const Span<SplinePtr> splines)
-{
- switch (initializer.type) {
- 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();
- return {};
- case AttributeInit::Type::VArray:
- return static_cast<const AttributeInitVArray &>(initializer).varray;
- case AttributeInit::Type::MoveArray:
- int total_num = 0;
- for (const SplinePtr &spline : splines) {
- total_num += spline->size();
- }
- return GVArray::ForSpan(GSpan(*bke::custom_data_type_to_cpp_type(data_type),
- static_cast<const AttributeInitMoveArray &>(initializer).data,
- total_num));
- }
- BLI_assert_unreachable();
- return {};
-}
-
-static bool create_point_attribute(CurveEval *curve,
- const AttributeIDRef &attribute_id,
- const AttributeInit &initializer,
- const eCustomDataType data_type)
-{
- if (curve == nullptr || curve->splines().size() == 0) {
- return false;
- }
-
- MutableSpan<SplinePtr> splines = curve->splines();
-
- /* 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 AttributeInitMoveArray &>(initializer).data;
- if (!splines.first()->attributes.create_by_move(attribute_id, data_type, source_data)) {
- MEM_freeN(source_data);
- return false;
- }
- return true;
- }
-
- /* Otherwise just create a custom data layer on each of the splines. */
- for (const int i : splines.index_range()) {
- if (!splines[i]->attributes.create(attribute_id, data_type)) {
- /* If attribute creation fails on one of the splines, we cannot leave the custom data
- * layers in the previous splines around, so delete them before returning. However,
- * this is not an expected case. */
- BLI_assert_unreachable();
- return false;
- }
- }
-
- /* With a default initializer type, we can keep the values at their initial values. */
- if (ELEM(initializer.type, AttributeInit::Type::DefaultValue, AttributeInit::Type::Construct)) {
- return true;
- }
-
- GAttributeWriter write_attribute = curve->attributes_for_write().lookup_for_write(attribute_id);
- /* We just created the attribute, it should exist. */
- BLI_assert(write_attribute);
-
- GVArray source_varray = varray_from_initializer(initializer, data_type, splines);
- /* TODO: When we can call a variant of #set_all with a virtual array argument,
- * this theoretically unnecessary materialize step could be removed. */
- GVArraySpan source_VArraySpan{source_varray};
- write_attribute.varray.set_all(source_VArraySpan.data());
- write_attribute.finish();
-
- if (initializer.type == AttributeInit::Type::MoveArray) {
- MEM_freeN(static_cast<const AttributeInitMoveArray &>(initializer).data);
- }
-
- return true;
-}
-
-static bool remove_point_attribute(CurveEval *curve, const AttributeIDRef &attribute_id)
-{
- if (curve == nullptr) {
- return false;
- }
-
- /* Reuse the boolean for all splines; we expect all splines to have the same attributes. */
- bool layer_freed = false;
- for (SplinePtr &spline : curve->splines()) {
- layer_freed = spline->attributes.remove(attribute_id);
- }
- return layer_freed;
-}
-
-/**
- * Mutable virtual array for any control point data accessed with spans and an offset array.
- */
-template<typename T> class VArrayImpl_For_SplinePoints final : public VMutableArrayImpl<T> {
- private:
- Array<MutableSpan<T>> data_;
- Array<int> offsets_;
-
- public:
- VArrayImpl_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets)
- : VMutableArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets))
- {
- }
-
- T get(const int64_t index) const final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- return data_[indices.spline_index][indices.point_index];
- }
-
- void set(const int64_t index, T value) final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- data_[indices.spline_index][indices.point_index] = value;
- }
-
- void set_all(Span<T> src) final
- {
- for (const int spline_index : data_.index_range()) {
- const int offset = offsets_[spline_index];
- const int next_offsets = offsets_[spline_index + 1];
- data_[spline_index].copy_from(src.slice(offset, next_offsets - offset));
- }
- }
-
- void materialize(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- point_attribute_materialize({(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span);
- }
-
- void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final
- {
- point_attribute_materialize_to_uninitialized(
- {(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span);
- }
-};
-
-template<typename T> VArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets)
-{
- return VArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
- std::move(offsets));
-}
-
-template<typename T>
-VMutableArray<T> point_data_varray_mutable(Array<MutableSpan<T>> spans, Array<int> offsets)
-{
- return VMutableArray<T>::template For<VArrayImpl_For_SplinePoints<T>>(std::move(spans),
- std::move(offsets));
-}
-
-/**
- * Virtual array implementation specifically for control point positions. This is only needed for
- * Bezier splines, where adjusting the position also requires adjusting handle positions depending
- * on handle types. We pay a small price for this when other spline types are mixed with Bezier.
- *
- * \note There is no need to check the handle type to avoid changing auto handles, since
- * retrieving write access to the position data will mark them for recomputation anyway.
- */
-class VArrayImpl_For_SplinePosition final : public VMutableArrayImpl<float3> {
- private:
- MutableSpan<SplinePtr> splines_;
- Array<int> offsets_;
-
- public:
- VArrayImpl_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets)
- : VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets))
- {
- }
-
- float3 get(const int64_t index) const final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- return splines_[indices.spline_index]->positions()[indices.point_index];
- }
-
- void set(const int64_t index, float3 value) final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- Spline &spline = *splines_[indices.spline_index];
- spline.positions()[indices.point_index] = value;
- }
-
- void set_all(Span<float3> src) final
- {
- for (const int spline_index : splines_.index_range()) {
- Spline &spline = *splines_[spline_index];
- const int offset = offsets_[spline_index];
- const int next_offset = offsets_[spline_index + 1];
- spline.positions().copy_from(src.slice(offset, next_offset - offset));
- }
- }
-
- /** Utility so we can pass positions to the materialize functions above. */
- Array<Span<float3>> get_position_spans() const
- {
- Array<Span<float3>> spans(splines_.size());
- for (const int i : spans.index_range()) {
- spans[i] = splines_[i]->positions();
- }
- return spans;
- }
-
- void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
- {
- Array<Span<float3>> spans = this->get_position_spans();
- point_attribute_materialize(spans.as_span(), offsets_, mask, r_span);
- }
-
- void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final
- {
- Array<Span<float3>> spans = this->get_position_spans();
- point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span);
- }
-};
-
-class VArrayImpl_For_BezierHandles final : public VMutableArrayImpl<float3> {
- private:
- MutableSpan<SplinePtr> splines_;
- Array<int> offsets_;
- bool is_right_;
-
- public:
- VArrayImpl_For_BezierHandles(MutableSpan<SplinePtr> splines,
- Array<int> offsets,
- const bool is_right)
- : VMutableArrayImpl<float3>(offsets.last()),
- splines_(splines),
- offsets_(std::move(offsets)),
- is_right_(is_right)
- {
- }
-
- float3 get(const int64_t index) const final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- const Spline &spline = *splines_[indices.spline_index];
- if (spline.type() == CURVE_TYPE_BEZIER) {
- const BezierSpline &bezier_spline = static_cast<const BezierSpline &>(spline);
- return is_right_ ? bezier_spline.handle_positions_right()[indices.point_index] :
- bezier_spline.handle_positions_left()[indices.point_index];
- }
- return float3(0);
- }
-
- void set(const int64_t index, float3 value) final
- {
- const PointIndices indices = lookup_point_indices(offsets_, index);
- Spline &spline = *splines_[indices.spline_index];
- if (spline.type() == CURVE_TYPE_BEZIER) {
- BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
- if (is_right_) {
- bezier_spline.handle_positions_right()[indices.point_index] = value;
- }
- else {
- bezier_spline.handle_positions_left()[indices.point_index] = value;
- }
- bezier_spline.mark_cache_invalid();
- }
- }
-
- void set_all(Span<float3> src) final
- {
- for (const int spline_index : splines_.index_range()) {
- Spline &spline = *splines_[spline_index];
- if (spline.type() == CURVE_TYPE_BEZIER) {
- const int offset = offsets_[spline_index];
-
- BezierSpline &bezier_spline = static_cast<BezierSpline &>(spline);
- if (is_right_) {
- for (const int i : IndexRange(bezier_spline.size())) {
- bezier_spline.handle_positions_right()[i] = src[offset + i];
- }
- }
- else {
- for (const int i : IndexRange(bezier_spline.size())) {
- bezier_spline.handle_positions_left()[i] = src[offset + i];
- }
- }
- bezier_spline.mark_cache_invalid();
- }
- }
- }
-
- void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final
- {
- Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
- point_attribute_materialize(spans.as_span(), offsets_, mask, r_span);
- }
-
- void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final
- {
- Array<Span<float3>> spans = get_handle_spans(splines_, is_right_);
- point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span);
- }
-
- /**
- * Utility so we can pass handle positions to the materialize functions above.
- *
- * \note This relies on the ability of the materialize implementations to
- * handle empty spans, since only Bezier splines have handles.
- */
- static Array<Span<float3>> get_handle_spans(Span<SplinePtr> splines, const bool is_right)
- {
- Array<Span<float3>> spans(splines.size());
- for (const int i : spans.index_range()) {
- if (splines[i]->type() == CURVE_TYPE_BEZIER) {
- BezierSpline &bezier_spline = static_cast<BezierSpline &>(*splines[i]);
- spans[i] = is_right ? bezier_spline.handle_positions_right() :
- bezier_spline.handle_positions_left();
- }
- else {
- spans[i] = {};
- }
- }
- return spans;
- }
-};
-
-/**
- * Provider for any builtin control point attribute that doesn't need
- * special handling like access to other arrays in the spline.
- */
-template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttributeProvider {
- protected:
- using GetSpan = Span<T> (*)(const Spline &spline);
- using GetMutableSpan = MutableSpan<T> (*)(Spline &spline);
- using UpdateOnWrite = void (*)(Spline &spline);
- const GetSpan get_span_;
- const GetMutableSpan get_mutable_span_;
- const UpdateOnWrite update_on_write_;
- bool stored_in_custom_data_;
-
- public:
- BuiltinPointAttributeProvider(std::string attribute_name,
- const CreatableEnum creatable,
- const DeletableEnum deletable,
- const GetSpan get_span,
- const GetMutableSpan get_mutable_span,
- const UpdateOnWrite update_on_write,
- const bool stored_in_custom_data)
- : BuiltinAttributeProvider(std::move(attribute_name),
- ATTR_DOMAIN_POINT,
- bke::cpp_type_to_custom_data_type(CPPType::get<T>()),
- creatable,
- WritableEnum::Writable,
- deletable),
- get_span_(get_span),
- get_mutable_span_(get_mutable_span),
- update_on_write_(update_on_write),
- stored_in_custom_data_(stored_in_custom_data)
- {
- }
-
- GVArray try_get_for_read(const void *owner) const override
- {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- if (curve == nullptr) {
- return {};
- }
-
- if (!this->exists(owner)) {
- return {};
- }
-
- Span<SplinePtr> splines = curve->splines();
- if (splines.size() == 1) {
- return GVArray::ForSpan(get_span_(*splines.first()));
- }
-
- Array<int> offsets = curve->control_point_offsets();
- Array<MutableSpan<T>> spans(splines.size());
- for (const int i : splines.index_range()) {
- Span<T> span = get_span_(*splines[i]);
- /* Use const-cast because the underlying virtual array implementation is shared between const
- * and non const data. */
- spans[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
- }
-
- return point_data_varray(spans, offsets);
- }
-
- GAttributeWriter try_get_for_write(void *owner) const override
- {
- CurveEval *curve = static_cast<CurveEval *>(owner);
- if (curve == nullptr) {
- return {};
- }
-
- if (!this->exists(owner)) {
- return {};
- }
-
- std::function<void()> tag_modified_fn;
- if (update_on_write_ != nullptr) {
- tag_modified_fn = [curve, update = update_on_write_]() {
- for (SplinePtr &spline : curve->splines()) {
- update(*spline);
- }
- };
- }
-
- MutableSpan<SplinePtr> splines = curve->splines();
- if (splines.size() == 1) {
- return {GVMutableArray::ForSpan(get_mutable_span_(*splines.first())),
- domain_,
- std::move(tag_modified_fn)};
- }
-
- Array<int> offsets = curve->control_point_offsets();
- Array<MutableSpan<T>> spans(splines.size());
- for (const int i : splines.index_range()) {
- spans[i] = get_mutable_span_(*splines[i]);
- }
-
- return {point_data_varray_mutable(spans, offsets), domain_, tag_modified_fn};
- }
-
- bool try_delete(void *owner) const final
- {
- if (deletable_ == DeletableEnum::NonDeletable) {
- return false;
- }
- CurveEval *curve = static_cast<CurveEval *>(owner);
- return remove_point_attribute(curve, name_);
- }
-
- bool try_create(void *owner, const AttributeInit &initializer) const final
- {
- if (createable_ == CreatableEnum::NonCreatable) {
- return false;
- }
- CurveEval *curve = static_cast<CurveEval *>(owner);
- return create_point_attribute(curve, name_, initializer, CD_PROP_INT32);
- }
-
- bool exists(const void *owner) const final
- {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- if (curve == nullptr) {
- return false;
- }
-
- Span<SplinePtr> splines = curve->splines();
- if (splines.size() == 0) {
- return false;
- }
-
- if (stored_in_custom_data_) {
- if (!curve->splines().first()->attributes.get_for_read(name_)) {
- return false;
- }
- }
-
- bool has_point = false;
- for (const SplinePtr &spline : curve->splines()) {
- if (spline->size() != 0) {
- has_point = true;
- break;
- }
- }
-
- if (!has_point) {
- return false;
- }
-
- return true;
- }
-};
-
-/**
- * Special attribute provider for the position attribute. Keeping this separate means we don't
- * need to make #BuiltinPointAttributeProvider overly generic, and the special handling for the
- * positions is more clear.
- */
-class PositionAttributeProvider final : public BuiltinPointAttributeProvider<float3> {
- public:
- PositionAttributeProvider()
- : BuiltinPointAttributeProvider(
- "position",
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::NonDeletable,
- [](const Spline &spline) { return spline.positions(); },
- [](Spline &spline) { return spline.positions(); },
- [](Spline &spline) { spline.mark_cache_invalid(); },
- false)
- {
- }
-
- GAttributeWriter try_get_for_write(void *owner) const final
- {
- CurveEval *curve = static_cast<CurveEval *>(owner);
- if (curve == nullptr) {
- return {};
- }
-
- /* Use the regular position virtual array when there aren't any Bezier splines
- * to avoid the overhead of checking the spline type for every point. */
- if (!curve->has_spline_with_type(CURVE_TYPE_BEZIER)) {
- return BuiltinPointAttributeProvider<float3>::try_get_for_write(owner);
- }
-
- auto tag_modified_fn = [curve]() {
- /* Changing the positions requires recalculation of cached evaluated data in many cases.
- * This could set more specific flags in the future to avoid unnecessary recomputation. */
- curve->mark_cache_invalid();
- };
-
- Array<int> offsets = curve->control_point_offsets();
- return {VMutableArray<float3>::For<VArrayImpl_For_SplinePosition>(curve->splines(),
- std::move(offsets)),
- domain_,
- tag_modified_fn};
- }
-};
-
-class BezierHandleAttributeProvider : public BuiltinAttributeProvider {
- private:
- bool is_right_;
-
- public:
- BezierHandleAttributeProvider(const bool is_right)
- : BuiltinAttributeProvider(is_right ? "handle_right" : "handle_left",
- ATTR_DOMAIN_POINT,
- CD_PROP_FLOAT3,
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable),
- is_right_(is_right)
- {
- }
-
- GVArray try_get_for_read(const void *owner) const override
- {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- if (curve == nullptr) {
- return {};
- }
-
- if (!curve->has_spline_with_type(CURVE_TYPE_BEZIER)) {
- return {};
- }
-
- Array<int> offsets = curve->control_point_offsets();
- /* Use const-cast because the underlying virtual array implementation is shared between const
- * and non const data. */
- return VArray<float3>::For<VArrayImpl_For_BezierHandles>(
- const_cast<CurveEval *>(curve)->splines(), std::move(offsets), is_right_);
- }
-
- GAttributeWriter try_get_for_write(void *owner) const override
- {
- CurveEval *curve = static_cast<CurveEval *>(owner);
- if (curve == nullptr) {
- return {};
- }
-
- if (!curve->has_spline_with_type(CURVE_TYPE_BEZIER)) {
- return {};
- }
-
- auto tag_modified_fn = [curve]() { curve->mark_cache_invalid(); };
-
- Array<int> offsets = curve->control_point_offsets();
- return {VMutableArray<float3>::For<VArrayImpl_For_BezierHandles>(
- curve->splines(), std::move(offsets), is_right_),
- domain_,
- tag_modified_fn};
- }
-
- bool try_delete(void *UNUSED(owner)) const final
- {
- return false;
- }
-
- bool try_create(void *UNUSED(owner), const AttributeInit &UNUSED(initializer)) const final
- {
- return false;
- }
-
- bool exists(const void *owner) const final
- {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- if (curve == nullptr) {
- return false;
- }
-
- CurveComponentLegacy component;
- component.replace(const_cast<CurveEval *>(curve), GeometryOwnershipType::ReadOnly);
-
- return curve->has_spline_with_type(CURVE_TYPE_BEZIER) && !curve->splines().is_empty();
- }
-};
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Dynamic Control Point Attributes
- *
- * The dynamic control point attribute implementation is very similar to the builtin attribute
- * implementation-- it uses the same virtual array types. In order to work, this code depends on
- * the fact that all a curve's splines will have the same attributes and they all have the same
- * type.
- * \{ */
-
-class DynamicPointAttributeProvider final : public DynamicAttributesProvider {
- private:
- static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 |
- CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 |
- CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL |
- CD_MASK_PROP_INT8;
-
- public:
- GAttributeReader try_get_for_read(const void *owner,
- const AttributeIDRef &attribute_id) const final
- {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- if (curve == nullptr || curve->splines().size() == 0) {
- return {};
- }
-
- Span<SplinePtr> splines = curve->splines();
- Vector<GSpan> spans; /* GSpan has no default constructor. */
- spans.reserve(splines.size());
- std::optional<GSpan> first_span = splines[0]->attributes.get_for_read(attribute_id);
- if (!first_span) {
- return {};
- }
- spans.append(*first_span);
- for (const int i : IndexRange(1, splines.size() - 1)) {
- std::optional<GSpan> span = splines[i]->attributes.get_for_read(attribute_id);
- if (!span) {
- /* All splines should have the same set of data layers. It would be possible to recover
- * here and return partial data instead, but that would add a lot of complexity for a
- * situation we don't even expect to encounter. */
- BLI_assert_unreachable();
- return {};
- }
- if (span->type() != spans.last().type()) {
- /* Data layer types on separate splines do not match. */
- BLI_assert_unreachable();
- return {};
- }
- spans.append(*span);
- }
-
- /* First check for the simpler situation when we can return a simpler span virtual array. */
- if (spans.size() == 1) {
- return {GVArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
- }
-
- GAttributeReader attribute = {};
- Array<int> offsets = curve->control_point_offsets();
- attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
- using T = decltype(dummy);
- Array<MutableSpan<T>> data(splines.size());
- for (const int i : splines.index_range()) {
- Span<T> span = spans[i].typed<T>();
- /* Use const-cast because the underlying virtual array implementation is shared between
- * const and non const data. */
- data[i] = MutableSpan<T>(const_cast<T *>(span.data()), span.size());
- BLI_assert(data[i].data() != nullptr);
- }
- attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT};
- });
- return attribute;
- }
-
- /* This function is almost the same as #try_get_for_read, but without const. */
- GAttributeWriter try_get_for_write(void *owner, const AttributeIDRef &attribute_id) const final
- {
- CurveEval *curve = static_cast<CurveEval *>(owner);
- if (curve == nullptr || curve->splines().size() == 0) {
- return {};
- }
-
- MutableSpan<SplinePtr> splines = curve->splines();
- Vector<GMutableSpan> spans; /* GMutableSpan has no default constructor. */
- spans.reserve(splines.size());
- std::optional<GMutableSpan> first_span = splines[0]->attributes.get_for_write(attribute_id);
- if (!first_span) {
- return {};
- }
- spans.append(*first_span);
- for (const int i : IndexRange(1, splines.size() - 1)) {
- std::optional<GMutableSpan> span = splines[i]->attributes.get_for_write(attribute_id);
- if (!span) {
- /* All splines should have the same set of data layers. It would be possible to recover
- * here and return partial data instead, but that would add a lot of complexity for a
- * situation we don't even expect to encounter. */
- BLI_assert_unreachable();
- return {};
- }
- if (span->type() != spans.last().type()) {
- /* Data layer types on separate splines do not match. */
- BLI_assert_unreachable();
- return {};
- }
- spans.append(*span);
- }
-
- /* First check for the simpler situation when we can return a simpler span virtual array. */
- if (spans.size() == 1) {
- return {GVMutableArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT};
- }
-
- GAttributeWriter attribute = {};
- Array<int> offsets = curve->control_point_offsets();
- attribute_math::convert_to_static_type(spans[0].type(), [&](auto dummy) {
- using T = decltype(dummy);
- Array<MutableSpan<T>> data(splines.size());
- for (const int i : splines.index_range()) {
- data[i] = spans[i].typed<T>();
- BLI_assert(data[i].data() != nullptr);
- }
- attribute = {point_data_varray_mutable(data, offsets), ATTR_DOMAIN_POINT};
- });
- return attribute;
- }
-
- bool try_delete(void *owner, const AttributeIDRef &attribute_id) const final
- {
- CurveEval *curve = static_cast<CurveEval *>(owner);
- return remove_point_attribute(curve, attribute_id);
- }
-
- bool try_create(void *owner,
- const AttributeIDRef &attribute_id,
- const eAttrDomain domain,
- const eCustomDataType data_type,
- const AttributeInit &initializer) const final
- {
- BLI_assert(this->type_is_supported(data_type));
- if (domain != ATTR_DOMAIN_POINT) {
- return false;
- }
- CurveEval *curve = static_cast<CurveEval *>(owner);
- return create_point_attribute(curve, attribute_id, initializer, data_type);
- }
-
- bool foreach_attribute(const void *owner, const AttributeForeachCallback callback) const final
- {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- if (curve == nullptr || curve->splines().size() == 0) {
- return false;
- }
-
- Span<SplinePtr> splines = curve->splines();
-
- /* In a debug build, check that all corresponding custom data layers have the same type. */
- curve->assert_valid_point_attributes();
-
- /* Use the first spline as a representative for all the others. */
- splines.first()->attributes.foreach_attribute(callback, ATTR_DOMAIN_POINT);
-
- return true;
- }
-
- void foreach_domain(const FunctionRef<void(eAttrDomain)> callback) const final
- {
- callback(ATTR_DOMAIN_POINT);
- }
-
- bool type_is_supported(eCustomDataType data_type) const
- {
- return ((1ULL << data_type) & supported_types_mask) != 0;
- }
-};
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Attribute Provider Declaration
- * \{ */
-
-/**
- * In this function all the attribute providers for a curve component are created.
- * Most data in this function is statically allocated, because it does not change over time.
- */
-static ComponentAttributeProviders create_attribute_providers_for_curve()
-{
- static BuiltinSplineAttributeProvider resolution("resolution",
- CD_PROP_INT32,
- BuiltinAttributeProvider::Writable,
- make_resolution_read_attribute,
- make_resolution_write_attribute);
-
- static BuiltinSplineAttributeProvider cyclic("cyclic",
- CD_PROP_BOOL,
- BuiltinAttributeProvider::Writable,
- make_cyclic_read_attribute,
- make_cyclic_write_attribute);
-
- static CustomDataAccessInfo spline_custom_data_access = {
- [](void *owner) -> CustomData * {
- CurveEval *curve = static_cast<CurveEval *>(owner);
- return curve ? &curve->attributes.data : nullptr;
- },
- [](const void *owner) -> const CustomData * {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- return curve ? &curve->attributes.data : nullptr;
- },
- [](const void *owner) -> int {
- const CurveEval *curve = static_cast<const CurveEval *>(owner);
- return curve->splines().size();
- }};
-
- static CustomDataAttributeProvider spline_custom_data(ATTR_DOMAIN_CURVE,
- spline_custom_data_access);
-
- static PositionAttributeProvider position;
- static BezierHandleAttributeProvider handles_start(false);
- static BezierHandleAttributeProvider handles_end(true);
-
- static BuiltinPointAttributeProvider<int> id(
- "id",
- BuiltinAttributeProvider::Creatable,
- BuiltinAttributeProvider::Deletable,
- [](const Spline &spline) {
- std::optional<GSpan> span = spline.attributes.get_for_read("id");
- return span ? span->typed<int>() : Span<int>();
- },
- [](Spline &spline) {
- std::optional<GMutableSpan> span = spline.attributes.get_for_write("id");
- return span ? span->typed<int>() : MutableSpan<int>();
- },
- {},
- true);
-
- static BuiltinPointAttributeProvider<float> radius(
- "radius",
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::NonDeletable,
- [](const Spline &spline) { return spline.radii(); },
- [](Spline &spline) { return spline.radii(); },
- nullptr,
- false);
-
- static BuiltinPointAttributeProvider<float> tilt(
- "tilt",
- BuiltinAttributeProvider::NonCreatable,
- BuiltinAttributeProvider::NonDeletable,
- [](const Spline &spline) { return spline.tilts(); },
- [](Spline &spline) { return spline.tilts(); },
- [](Spline &spline) { spline.mark_cache_invalid(); },
- false);
-
- static DynamicPointAttributeProvider point_custom_data;
-
- return ComponentAttributeProviders(
- {&position, &id, &radius, &tilt, &handles_start, &handles_end, &resolution, &cyclic},
- {&spline_custom_data, &point_custom_data});
-}
-
-/** \} */
-
-static AttributeAccessorFunctions get_curve_accessor_functions()
-{
- static const ComponentAttributeProviders providers = create_attribute_providers_for_curve();
- AttributeAccessorFunctions fn =
- attribute_accessor_functions::accessor_functions_for_providers<providers>();
- fn.domain_size = [](const void *owner, const eAttrDomain domain) -> int {
- if (owner == nullptr) {
- return 0;
- }
- const CurveEval &curve_eval = *static_cast<const CurveEval *>(owner);
- switch (domain) {
- case ATTR_DOMAIN_POINT:
- return curve_eval.total_control_point_num();
- case ATTR_DOMAIN_CURVE:
- return curve_eval.splines().size();
- default:
- return 0;
- }
- };
- fn.domain_supported = [](const void *UNUSED(owner), const eAttrDomain domain) {
- return ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
- };
- fn.adapt_domain = [](const void *owner,
- const blender::GVArray &varray,
- const eAttrDomain from_domain,
- const eAttrDomain to_domain) -> GVArray {
- if (owner == nullptr) {
- return {};
- }
- const CurveEval &curve_eval = *static_cast<const CurveEval *>(owner);
- return adapt_curve_attribute_domain(curve_eval, varray, from_domain, to_domain);
- };
- return fn;
-}
-
-static const AttributeAccessorFunctions &get_curve_accessor_functions_ref()
-{
- static const AttributeAccessorFunctions fn = get_curve_accessor_functions();
- return fn;
-}
-
-} // namespace blender::bke
-
-std::optional<blender::bke::AttributeAccessor> CurveComponentLegacy::attributes() const
-{
- return blender::bke::AttributeAccessor(curve_, blender::bke::get_curve_accessor_functions_ref());
-}
-
-std::optional<blender::bke::MutableAttributeAccessor> CurveComponentLegacy::attributes_for_write()
-{
- CurveEval *curve = this->get_for_write();
- return blender::bke::MutableAttributeAccessor(curve,
- blender::bke::get_curve_accessor_functions_ref());
-}
-
-blender::bke::MutableAttributeAccessor CurveEval::attributes_for_write()
-{
- return blender::bke::MutableAttributeAccessor(this,
- blender::bke::get_curve_accessor_functions_ref());
-}
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index 83a35534c01..4ace68546ac 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -12,6 +12,8 @@
#include "BKE_geometry_set.hh"
#include "BKE_lib_id.h"
+#include "FN_multi_function_builder.hh"
+
#include "attribute_access_intern.hh"
using blender::GVArray;
@@ -426,6 +428,12 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
make_array_write_attribute<float3>,
tag_component_positions_changed);
+ static const fn::CustomMF_SI_SO<int8_t, int8_t> handle_type_clamp{
+ "Handle Type Validate",
+ [](int8_t value) {
+ return std::clamp<int8_t>(value, BEZIER_HANDLE_FREE, BEZIER_HANDLE_ALIGN);
+ },
+ fn::CustomMF_presets::AllSpanOrSingle()};
static BuiltinCustomDataLayerProvider handle_type_right("handle_type_right",
ATTR_DOMAIN_POINT,
CD_PROP_INT8,
@@ -436,7 +444,8 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
point_access,
make_array_read_attribute<int8_t>,
make_array_write_attribute<int8_t>,
- tag_component_topology_changed);
+ tag_component_topology_changed,
+ AttributeValidator{&handle_type_clamp});
static BuiltinCustomDataLayerProvider handle_type_left("handle_type_left",
ATTR_DOMAIN_POINT,
@@ -448,7 +457,8 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
point_access,
make_array_read_attribute<int8_t>,
make_array_write_attribute<int8_t>,
- tag_component_topology_changed);
+ tag_component_topology_changed,
+ AttributeValidator{&handle_type_clamp});
static BuiltinCustomDataLayerProvider nurbs_weight("nurbs_weight",
ATTR_DOMAIN_POINT,
@@ -462,6 +472,10 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
make_array_write_attribute<float>,
tag_component_positions_changed);
+ static const fn::CustomMF_SI_SO<int8_t, int8_t> nurbs_order_clamp{
+ "NURBS Order Validate",
+ [](int8_t value) { return std::max<int8_t>(value, 0); },
+ fn::CustomMF_presets::AllSpanOrSingle()};
static BuiltinCustomDataLayerProvider nurbs_order("nurbs_order",
ATTR_DOMAIN_CURVE,
CD_PROP_INT8,
@@ -472,8 +486,15 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
curve_access,
make_array_read_attribute<int8_t>,
make_array_write_attribute<int8_t>,
- tag_component_topology_changed);
+ tag_component_topology_changed,
+ AttributeValidator{&nurbs_order_clamp});
+ static const fn::CustomMF_SI_SO<int8_t, int8_t> normal_mode_clamp{
+ "Normal Mode Validate",
+ [](int8_t value) {
+ return std::clamp<int8_t>(value, NORMAL_MODE_MINIMUM_TWIST, NORMAL_MODE_Z_UP);
+ },
+ fn::CustomMF_presets::AllSpanOrSingle()};
static BuiltinCustomDataLayerProvider normal_mode("normal_mode",
ATTR_DOMAIN_CURVE,
CD_PROP_INT8,
@@ -484,8 +505,15 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
curve_access,
make_array_read_attribute<int8_t>,
make_array_write_attribute<int8_t>,
- tag_component_normals_changed);
+ tag_component_normals_changed,
+ AttributeValidator{&normal_mode_clamp});
+ static const fn::CustomMF_SI_SO<int8_t, int8_t> knots_mode_clamp{
+ "Knots Mode Validate",
+ [](int8_t value) {
+ return std::clamp<int8_t>(value, NURBS_KNOT_MODE_NORMAL, NURBS_KNOT_MODE_ENDPOINT_BEZIER);
+ },
+ fn::CustomMF_presets::AllSpanOrSingle()};
static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode",
ATTR_DOMAIN_CURVE,
CD_PROP_INT8,
@@ -496,8 +524,15 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
curve_access,
make_array_read_attribute<int8_t>,
make_array_write_attribute<int8_t>,
- tag_component_topology_changed);
+ tag_component_topology_changed,
+ AttributeValidator{&knots_mode_clamp});
+ static const fn::CustomMF_SI_SO<int8_t, int8_t> curve_type_clamp{
+ "Curve Type Validate",
+ [](int8_t value) {
+ return std::clamp<int8_t>(value, CURVE_TYPE_CATMULL_ROM, CURVE_TYPES_NUM);
+ },
+ fn::CustomMF_presets::AllSpanOrSingle()};
static BuiltinCustomDataLayerProvider curve_type("curve_type",
ATTR_DOMAIN_CURVE,
CD_PROP_INT8,
@@ -508,8 +543,13 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
curve_access,
make_array_read_attribute<int8_t>,
make_array_write_attribute<int8_t>,
- tag_component_curve_types_changed);
+ tag_component_curve_types_changed,
+ AttributeValidator{&curve_type_clamp});
+ static const fn::CustomMF_SI_SO<int, int> resolution_clamp{
+ "Resolution Validate",
+ [](int value) { return std::max<int>(value, 1); },
+ fn::CustomMF_presets::AllSpanOrSingle()};
static BuiltinCustomDataLayerProvider resolution("resolution",
ATTR_DOMAIN_CURVE,
CD_PROP_INT32,
@@ -520,7 +560,8 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
curve_access,
make_array_read_attribute<int>,
make_array_write_attribute<int>,
- tag_component_topology_changed);
+ tag_component_topology_changed,
+ AttributeValidator{&resolution_clamp});
static BuiltinCustomDataLayerProvider cyclic("cyclic",
ATTR_DOMAIN_CURVE,
diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc
index 715c7d6c743..bf1dc1453c2 100644
--- a/source/blender/blenkernel/intern/geometry_component_mesh.cc
+++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc
@@ -14,6 +14,8 @@
#include "BKE_lib_id.h"
#include "BKE_mesh.h"
+#include "FN_multi_function_builder.hh"
+
#include "attribute_access_intern.hh"
extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id);
@@ -902,14 +904,14 @@ static void set_loop_uv(MLoopUV &uv, float2 co)
copy_v2_v2(uv.uv, co);
}
-static float get_crease(const MEdge &edge)
+static float get_crease(const float &crease)
{
- return edge.crease / 255.0f;
+ return crease;
}
-static void set_crease(MEdge &edge, float value)
+static void set_crease(float &crease, const float value)
{
- edge.crease = round_fl_to_uchar_clamp(value * 255.0f);
+ crease = std::clamp(value, 0.0f, 1.0f);
}
class VArrayImpl_For_VertexWeights final : public VMutableArrayImpl<float> {
@@ -1217,6 +1219,13 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
make_array_write_attribute<int>,
nullptr);
+ static const fn::CustomMF_SI_SO<int, int> material_index_clamp{
+ "Material Index Validate",
+ [](int value) {
+ /* Use #short for the maximum since many areas still use that type for indices. */
+ return std::clamp<int>(value, 0, std::numeric_limits<short>::max());
+ },
+ fn::CustomMF_presets::AllSpanOrSingle()};
static BuiltinCustomDataLayerProvider material_index("material_index",
ATTR_DOMAIN_FACE,
CD_PROP_INT32,
@@ -1227,7 +1236,8 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
face_access,
make_array_read_attribute<int>,
make_array_write_attribute<int>,
- nullptr);
+ nullptr,
+ AttributeValidator{&material_index_clamp});
static BuiltinCustomDataLayerProvider shade_smooth(
"shade_smooth",
@@ -1246,13 +1256,13 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
"crease",
ATTR_DOMAIN_EDGE,
CD_PROP_FLOAT,
- CD_MEDGE,
- BuiltinAttributeProvider::NonCreatable,
+ CD_CREASE,
+ BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable,
- BuiltinAttributeProvider::NonDeletable,
+ BuiltinAttributeProvider::Deletable,
edge_access,
- make_derived_read_attribute<MEdge, float, get_crease>,
- make_derived_write_attribute<MEdge, float, get_crease, set_crease>,
+ make_array_read_attribute<float>,
+ make_derived_write_attribute<float, float, get_crease, set_crease>,
nullptr);
static NamedLegacyCustomDataProvider uvs(
diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier.c
index 33f84aff545..8361d8e1849 100644
--- a/source/blender/blenkernel/intern/gpencil_modifier.c
+++ b/source/blender/blenkernel/intern/gpencil_modifier.c
@@ -677,7 +677,7 @@ static void copy_frame_to_eval_cb(bGPDlayer *gpl,
* - When the frame is the layer's active frame (already handled in
* gpencil_copy_visible_frames_to_eval).
*/
- if (gpf == NULL || gpf == gpl->actframe) {
+ if (ELEM(gpf, NULL, gpl->actframe)) {
return;
}
diff --git a/source/blender/blenkernel/intern/idprop_create.cc b/source/blender/blenkernel/intern/idprop_create.cc
index 24f59d5e49e..8a6e5cdcc50 100644
--- a/source/blender/blenkernel/intern/idprop_create.cc
+++ b/source/blender/blenkernel/intern/idprop_create.cc
@@ -79,7 +79,7 @@ static void array_values_set(IDProperty *property,
template<
/** C-Primitive type of the array. Can be int32_t, float, double. */
typename PrimitiveType,
- /** Subtype of the ID_ARRAY. Must match PrimitiveType. */
+ /** Sub-type of the #ID_ARRAY. Must match #PrimitiveType. */
eIDPropertyType id_property_subtype>
std::unique_ptr<IDProperty, IDPropertyDeleter> create_array(StringRefNull prop_name,
Span<PrimitiveType> values)
diff --git a/source/blender/blenkernel/intern/image.cc b/source/blender/blenkernel/intern/image.cc
index 75cf10f88aa..3cc0727a94a 100644
--- a/source/blender/blenkernel/intern/image.cc
+++ b/source/blender/blenkernel/intern/image.cc
@@ -1999,7 +1999,7 @@ void BKE_image_stamp_buf(Scene *scene,
}
/* set before return */
- BLF_size(mono, scene->r.stamp_font_id, 72);
+ BLF_size(mono, scene->r.stamp_font_id);
BLF_wordwrap(mono, width - (BUFF_MARGIN_X * 2));
BLF_buffer(mono, rectf, rect, width, height, channels, display);
@@ -2662,7 +2662,7 @@ Image *BKE_image_ensure_viewer(Main *bmain, int type, const char *name)
ima = image_alloc(bmain, name, IMA_SRC_VIEWER, type);
}
- /* Happens on reload, imagewindow cannot be image user when hidden. */
+ /* Happens on reload, image-window cannot be image user when hidden. */
if (ima->id.us == 0) {
id_us_ensure_real(&ima->id);
}
@@ -5148,7 +5148,7 @@ bool BKE_image_has_alpha(Image *image)
const int planes = (ibuf ? ibuf->planes : 0);
BKE_image_release_ibuf(image, ibuf, lock);
- if (planes == 32 || planes == 16) {
+ if (ELEM(planes, 32, 16)) {
return true;
}
@@ -5567,15 +5567,14 @@ bool BKE_image_remove_renderslot(Image *ima, ImageUser *iuser, int slot)
next_last_slot = current_slot;
}
- if (!iuser) {
+ if (iuser == nullptr || iuser->scene == nullptr) {
return false;
}
Render *re = RE_GetSceneRender(iuser->scene);
- if (!re) {
- return false;
+ if (re != nullptr) {
+ RE_SwapResult(re, &current_last_slot->render);
+ RE_SwapResult(re, &next_last_slot->render);
}
- RE_SwapResult(re, &current_last_slot->render);
- RE_SwapResult(re, &next_last_slot->render);
current_last_slot = next_last_slot;
}
diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c
index 5a299582890..32795baaa37 100644
--- a/source/blender/blenkernel/intern/image_gen.c
+++ b/source/blender/blenkernel/intern/image_gen.c
@@ -355,7 +355,7 @@ static void checker_board_text(
char text[3] = {'A', '1', '\0'};
const int mono = blf_mono_font_render;
- BLF_size(mono, 54.0f, 72); /* hard coded size! */
+ BLF_size(mono, 54.0f); /* hard coded size! */
/* OCIO_TODO: using NULL as display will assume using sRGB display
* this is correct since currently generated images are assumed to be in sRGB space,
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 22c0007cbc0..40a5c08a068 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -2142,7 +2142,7 @@ void do_versions_ipos_to_animato(Main *bmain)
if (ob->action) {
action_to_animdata(id, ob->action);
- /* only decrease usercount if this Action isn't now being used by AnimData */
+ /* Only decrease user-count if this Action isn't now being used by AnimData. */
if (ob->action != adt->action) {
id_us_min(&ob->action->id);
ob->action = NULL;
@@ -2246,7 +2246,7 @@ void do_versions_ipos_to_animato(Main *bmain)
/* Add AnimData block */
AnimData *adt = BKE_animdata_ensure_id(id);
- /* Convert Shapekey data... */
+ /* Convert Shape-key data... */
ipo_to_animdata(bmain, id, key->ipo, NULL, NULL, NULL);
if (adt->action) {
diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c
index 8faa260ab8b..158aaa961ce 100644
--- a/source/blender/blenkernel/intern/lib_id.c
+++ b/source/blender/blenkernel/intern/lib_id.c
@@ -416,7 +416,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data)
/* Can happen that we get un-linkable ID here, e.g. with shape-key referring to itself
* (through drivers)...
* Just skip it, shape key can only be either indirectly linked, or fully local, period.
- * And let's curse one more time that stupid useless shapekey ID type! */
+ * And let's curse one more time that stupid useless shape-key ID type! */
if (*id_pointer && *id_pointer != id_self &&
BKE_idtype_idcode_is_linkable(GS((*id_pointer)->name))) {
id_lib_extern(*id_pointer);
@@ -566,7 +566,7 @@ struct IDCopyLibManagementData {
int flag;
};
-/* Increases usercount as required, and remap self ID pointers. */
+/** Increases user-count as required, and remap self ID pointers. */
static int id_copy_libmanagement_cb(LibraryIDLinkCallbackData *cb_data)
{
ID **id_pointer = cb_data->id_pointer;
@@ -1289,7 +1289,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
new_id->flag = (new_id->flag & ~copy_idflag_mask) | (id->flag & copy_idflag_mask);
- /* We do not want any handling of usercount in code duplicating the data here, we do that all
+ /* We do not want any handling of user-count in code duplicating the data here, we do that all
* at once in id_copy_libmanagement_cb() at the end. */
const int copy_data_flag = orig_flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
@@ -1566,7 +1566,7 @@ void BKE_main_id_refcount_recompute(struct Main *bmain, const bool do_linked_onl
}
FOREACH_MAIN_ID_END;
- /* Go over whole Main database to re-generate proper usercounts... */
+ /* Go over whole Main database to re-generate proper user-counts. */
FOREACH_MAIN_ID_BEGIN (bmain, id) {
BKE_library_foreach_ID_link(bmain,
id,
diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c
index 8d5699d7d49..f4f5ca7a1d7 100644
--- a/source/blender/blenkernel/intern/lib_id_delete.c
+++ b/source/blender/blenkernel/intern/lib_id_delete.c
@@ -280,8 +280,8 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
}
/* Now we can safely mark that ID as not being in Main database anymore. */
- /* NOTE: This needs to be done in a separate loop than above, otherwise some usercounts of
- * deleted IDs may not be properly decreased by the remappings (since `NO_MAIN` ID usercounts
+ /* NOTE: This needs to be done in a separate loop than above, otherwise some user-counts of
+ * deleted IDs may not be properly decreased by the remappings (since `NO_MAIN` ID user-counts
* is never affected). */
for (ID *id = tagged_deleted_ids.first; id; id = id->next) {
id->tag |= LIB_TAG_NO_MAIN;
diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc
index b05ae775be6..3f1b80014ac 100644
--- a/source/blender/blenkernel/intern/lib_override.cc
+++ b/source/blender/blenkernel/intern/lib_override.cc
@@ -1846,8 +1846,8 @@ static bool lib_override_library_resync(Main *bmain,
}
}
if (reference_id == nullptr) {
- /* Can happen e.g. when there is a local override of a shapekey, but the matching linked
- * obdata (mesh etc.) does not have any shapekey anymore. */
+ /* Can happen e.g. when there is a local override of a shape-key, but the matching linked
+ * obdata (mesh etc.) does not have any shape-key anymore. */
continue;
}
BLI_assert(GS(reference_id->name) == GS(id->name));
@@ -3951,7 +3951,7 @@ void BKE_lib_override_library_operations_store_end(
void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage)
{
/* We cannot just call BKE_main_free(override_storage), not until we have option to make
- * 'ghost' copies of IDs without increasing usercount of used data-blocks. */
+ * 'ghost' copies of IDs without increasing user-count of used data-blocks. */
ID *id;
FOREACH_MAIN_ID_BEGIN (override_storage, id) {
diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c
index 28b0337d9a2..2ebdc6788d9 100644
--- a/source/blender/blenkernel/intern/lib_remap.c
+++ b/source/blender/blenkernel/intern/lib_remap.c
@@ -817,7 +817,7 @@ void BKE_libblock_relink_ex(
Main *bmain, void *idv, void *old_idv, void *new_idv, const short remap_flags)
{
- /* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */
+ /* Should be able to replace all _relink() functions (constraints, rigidbody, etc.) ? */
ID *id = idv;
ID *old_id = old_idv;
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 25268785d42..0b8351efdf4 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -1579,7 +1579,7 @@ void BKE_mask_parent_init(MaskParent *parent)
parent->id_type = ID_MC;
}
-/* *** own animation/shapekey implementation ***
+/* *** own animation/shape-key implementation ***
* BKE_mask_layer_shape_XXX */
int BKE_mask_layer_shape_totvert(MaskLayer *masklay)
diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c
index 49963c333ec..48fadd2e9b8 100644
--- a/source/blender/blenkernel/intern/mball_tessellate.c
+++ b/source/blender/blenkernel/intern/mball_tessellate.c
@@ -1447,7 +1447,6 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob)
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->flag = 0;
}
MEM_freeN(process.co);
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 7da9acc3cf6..6df6cd31cf4 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -68,6 +68,7 @@ using blender::BitVector;
using blender::float3;
using blender::MutableSpan;
using blender::Span;
+using blender::StringRef;
using blender::VArray;
using blender::Vector;
@@ -148,8 +149,6 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
mesh_tessface_clear_intern(mesh_dst, false);
}
- mesh_dst->cd_flag = mesh_src->cd_flag;
-
mesh_dst->edit_mesh = nullptr;
mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect);
@@ -250,10 +249,19 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
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_selection_layers_to_flags(mesh);
BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh);
BKE_mesh_legacy_bevel_weight_from_layers(mesh);
+ BKE_mesh_legacy_face_set_from_generic(mesh);
+ BKE_mesh_legacy_edge_crease_from_layers(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", "material_index"});
+ names_to_skip.add_multiple_new({".hide_vert",
+ ".hide_edge",
+ ".hide_poly",
+ "material_index",
+ ".select_vert",
+ ".select_edge",
+ ".select_poly"});
/* Set deprecated mesh data pointers for forward compatibility. */
mesh->mvert = const_cast<MVert *>(mesh->verts().data());
@@ -689,7 +697,6 @@ static int customdata_compare(
case CD_PROP_BOOL: {
const bool *l1_data = (bool *)l1->data;
const bool *l2_data = (bool *)l2->data;
-
for (int i = 0; i < total_length; i++) {
if (l1_data[i] != l2_data[i]) {
return MESHCMP_ATTRIBUTE_VALUE_MISMATCH;
@@ -1017,7 +1024,6 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src,
me_dst->totloop = loops_len;
me_dst->totpoly = polys_len;
- 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_SET_DEFAULT, verts_len);
@@ -1619,7 +1625,7 @@ void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh)
break;
}
}
- if (edge.crease != 0) {
+ if (edge.crease_legacy != 0) {
mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) {
break;
@@ -1639,39 +1645,46 @@ void BKE_mesh_mselect_clear(Mesh *me)
void BKE_mesh_mselect_validate(Mesh *me)
{
+ using namespace blender;
+ using namespace blender::bke;
MSelect *mselect_src, *mselect_dst;
int i_src, i_dst;
if (me->totselect == 0) {
return;
}
- const Span<MVert> verts = me->verts();
- const Span<MEdge> edges = me->edges();
- const Span<MPoly> polys = me->polys();
mselect_src = me->mselect;
mselect_dst = (MSelect *)MEM_malloc_arrayN(
(me->totselect), sizeof(MSelect), "Mesh selection history");
+ const AttributeAccessor attributes = me->attributes();
+ const VArray<bool> select_vert = attributes.lookup_or_default<bool>(
+ ".select_vert", ATTR_DOMAIN_POINT, false);
+ const VArray<bool> select_edge = attributes.lookup_or_default<bool>(
+ ".select_edge", ATTR_DOMAIN_EDGE, false);
+ const VArray<bool> select_poly = attributes.lookup_or_default<bool>(
+ ".select_poly", ATTR_DOMAIN_FACE, false);
+
for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) {
int index = mselect_src[i_src].index;
switch (mselect_src[i_src].type) {
case ME_VSEL: {
- if (verts[index].flag & SELECT) {
+ if (select_vert[index]) {
mselect_dst[i_dst] = mselect_src[i_src];
i_dst++;
}
break;
}
case ME_ESEL: {
- if (edges[index].flag & SELECT) {
+ if (select_edge[index]) {
mselect_dst[i_dst] = mselect_src[i_src];
i_dst++;
}
break;
}
case ME_FSEL: {
- if (polys[index].flag & SELECT) {
+ if (select_poly[index]) {
mselect_dst[i_dst] = mselect_src[i_src];
i_dst++;
}
diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
index 7a04e45fe00..be6c27ee6f9 100644
--- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc
@@ -375,14 +375,10 @@ static IMesh meshes_to_imesh(Span<const Mesh *> meshes,
* `mv` is in `dest_mesh` with index `mv_index`.
* The `orig_mv` vertex came from Mesh `orig_me` and had index `index_in_orig_me` there. */
static void copy_vert_attributes(Mesh *dest_mesh,
- MVert *mv,
- const MVert *orig_mv,
const Mesh *orig_me,
int mv_index,
int index_in_orig_me)
{
- mv->flag = orig_mv->flag;
-
/* For all layers in the orig mesh, copy the layer information. */
CustomData *target_cd = &dest_mesh->vdata;
const CustomData *source_cd = &orig_me->vdata;
@@ -449,7 +445,6 @@ static void copy_edge_attributes(Mesh *dest_mesh,
int medge_index,
int index_in_orig_me)
{
- medge->crease = orig_medge->crease;
medge->flag = orig_medge->flag;
CustomData *target_cd = &dest_mesh->edata;
const CustomData *source_cd = &orig_me->edata;
@@ -724,14 +719,14 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim)
MutableSpan<MVert> verts = result->verts_for_write();
for (int vi : im->vert_index_range()) {
const Vert *v = im->vert(vi);
- MVert *mv = &verts[vi];
- copy_v3fl_v3db(mv->co, v->co);
if (v->orig != NO_INDEX) {
const Mesh *orig_me;
int index_in_orig_me;
- const MVert *orig_mv = mim.input_mvert_for_orig_index(v->orig, &orig_me, &index_in_orig_me);
- copy_vert_attributes(result, mv, orig_mv, orig_me, vi, index_in_orig_me);
+ mim.input_mvert_for_orig_index(v->orig, &orig_me, &index_in_orig_me);
+ copy_vert_attributes(result, orig_me, vi, index_in_orig_me);
}
+ MVert *mv = &verts[vi];
+ copy_v3fl_v3db(mv->co, v->co);
}
/* Set the loopstart and totloop for each output poly,
diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc
index cc315130ad1..038133c33ae 100644
--- a/source/blender/blenkernel/intern/mesh_calc_edges.cc
+++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc
@@ -13,6 +13,7 @@
#include "BLI_threads.h"
#include "BLI_timeit.hh"
+#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
@@ -120,8 +121,7 @@ static void add_polygon_edges_to_hash_maps(Mesh *mesh,
}
static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edge_maps,
- MutableSpan<MEdge> new_edges,
- short new_edge_flag)
+ MutableSpan<MEdge> new_edges)
{
/* All edges are distributed in the hash tables now. They have to be serialized into a single
* array below. To be able to parallelize this, we have to compute edge index offsets for each
@@ -147,7 +147,7 @@ static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edg
/* Initialize new edge. */
new_edge.v1 = item.key.v_low;
new_edge.v2 = item.key.v_high;
- new_edge.flag = new_edge_flag;
+ new_edge.flag = ME_EDGEDRAW | ME_EDGERENDER;
}
item.value.index = new_edge_index;
new_edge_index++;
@@ -236,8 +236,7 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select
/* Create new edges. */
MutableSpan<MEdge> new_edges{
static_cast<MEdge *>(MEM_calloc_arrayN(new_totedge, sizeof(MEdge), __func__)), new_totedge};
- const short new_edge_flag = (ME_EDGEDRAW | ME_EDGERENDER) | (select_new_edges ? SELECT : 0);
- calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges, new_edge_flag);
+ calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges);
calc_edges::update_edge_indices_in_poly_loops(mesh, edge_maps, parallel_mask);
/* Free old CustomData and assign new one. */
@@ -246,6 +245,24 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select
CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_ASSIGN, new_edges.data(), new_totedge);
mesh->totedge = new_totedge;
+ if (select_new_edges) {
+ MutableAttributeAccessor attributes = mesh->attributes_for_write();
+ SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_span<bool>(
+ ".select_edge", ATTR_DOMAIN_EDGE);
+ if (select_edge) {
+ int new_edge_index = 0;
+ for (const EdgeMap &edge_map : edge_maps) {
+ for (EdgeMap::Item item : edge_map.items()) {
+ if (item.value.original_edge == nullptr) {
+ select_edge.span[new_edge_index] = true;
+ }
+ new_edge_index++;
+ }
+ }
+ select_edge.finish();
+ }
+ }
+
/* Explicitly clear edge maps, because that way it can be parallelized. */
clear_hash_tables(edge_maps);
}
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index e56df0e3fe3..1ad74ef693a 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -119,7 +119,6 @@ static void make_edges_mdata_extend(Mesh &mesh)
BLI_edgehashIterator_getKey(ehi, &medge->v1, &medge->v2);
BLI_edgehashIterator_setValue(ehi, POINTER_FROM_UINT(e_index));
- medge->crease = 0;
medge->flag = ME_EDGEDRAW | ME_EDGERENDER;
}
BLI_edgehashIterator_free(ehi);
@@ -1328,7 +1327,6 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, Mesh *mesh_dst, Object *ob)
BLI_listbase_clear(&mesh_src->vertex_group_names);
BKE_mesh_copy_parameters(mesh_dst, mesh_src);
- mesh_dst->cd_flag = mesh_src->cd_flag;
/* For original meshes, shape key data is stored in the #Key data-block, so it
* must be moved from the storage in #CustomData layers used for evaluation. */
diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc
index 8a9ce901923..ba4f25c74ee 100644
--- a/source/blender/blenkernel/intern/mesh_debug.cc
+++ b/source/blender/blenkernel/intern/mesh_debug.cc
@@ -27,21 +27,11 @@
# include "BLI_dynstr.h"
-static void mesh_debug_info_from_cd_flag(const Mesh *me, DynStr *dynstr)
-{
- BLI_dynstr_append(dynstr, "'cd_flag': {");
- if (me->cd_flag & ME_CDFLAG_EDGE_CREASE) {
- BLI_dynstr_append(dynstr, "'EDGE_CREASE', ");
- }
- BLI_dynstr_append(dynstr, "},\n");
-}
-
char *BKE_mesh_debug_info(const Mesh *me)
{
DynStr *dynstr = BLI_dynstr_new();
char *ret;
- const char *indent4 = " ";
const char *indent8 = " ";
BLI_dynstr_append(dynstr, "{\n");
@@ -75,9 +65,6 @@ char *BKE_mesh_debug_info(const Mesh *me)
CustomData_debug_info_from_layers(&me->fdata, indent8, dynstr);
BLI_dynstr_append(dynstr, " ),\n");
- BLI_dynstr_append(dynstr, indent4);
- mesh_debug_info_from_cd_flag(me, dynstr);
-
BLI_dynstr_append(dynstr, "}\n");
ret = BLI_dynstr_get_cstring(dynstr);
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc
index 938d7e42aa3..4f8391263a1 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.cc
+++ b/source/blender/blenkernel/intern/mesh_evaluate.cc
@@ -818,103 +818,88 @@ void BKE_mesh_flush_hidden_from_polys(Mesh *me)
hide_edge.finish();
}
-void BKE_mesh_flush_select_from_polys_ex(MVert *mvert,
- const int totvert,
- const MLoop *mloop,
- MEdge *medge,
- const int totedge,
- const MPoly *mpoly,
- const int totpoly)
+void BKE_mesh_flush_select_from_polys(Mesh *me)
{
- MVert *mv;
- MEdge *med;
- const MPoly *mp;
-
- int i = totvert;
- for (mv = mvert; i--; mv++) {
- mv->flag &= (char)~SELECT;
+ using namespace blender::bke;
+ MutableAttributeAccessor attributes = me->attributes_for_write();
+ const VArray<bool> select_poly = attributes.lookup_or_default<bool>(
+ ".select_poly", ATTR_DOMAIN_FACE, false);
+ if (select_poly.is_single() && !select_poly.get_internal_single()) {
+ attributes.remove(".select_vert");
+ attributes.remove(".select_edge");
+ return;
}
+ SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_only_span<bool>(
+ ".select_vert", ATTR_DOMAIN_POINT);
+ SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_only_span<bool>(
+ ".select_edge", ATTR_DOMAIN_EDGE);
- i = totedge;
- for (med = medge; i--; med++) {
- med->flag &= ~SELECT;
- }
+ /* Use generic domain interpolation to read the polygon attribute on the other domains.
+ * Assume selected faces are not hidden and none of their vertices/edges are hidden. */
+ attributes.lookup_or_default<bool>(".select_poly", ATTR_DOMAIN_POINT, false)
+ .materialize(select_vert.span);
+ attributes.lookup_or_default<bool>(".select_poly", ATTR_DOMAIN_EDGE, false)
+ .materialize(select_edge.span);
- i = totpoly;
- for (mp = mpoly; i--; mp++) {
- /* Assume if its selected its not hidden and none of its verts/edges are hidden
- * (a common assumption). */
- if (mp->flag & ME_FACE_SEL) {
- const MLoop *ml;
- int j;
- j = mp->totloop;
- for (ml = &mloop[mp->loopstart]; j--; ml++) {
- mvert[ml->v].flag |= SELECT;
- medge[ml->e].flag |= SELECT;
- }
- }
- }
-}
-void BKE_mesh_flush_select_from_polys(Mesh *me)
-{
- BKE_mesh_flush_select_from_polys_ex(me->verts_for_write().data(),
- me->totvert,
- me->loops().data(),
- me->edges_for_write().data(),
- me->totedge,
- me->polys().data(),
- me->totpoly);
+ select_vert.finish();
+ select_edge.finish();
}
-static void mesh_flush_select_from_verts(const Span<MVert> verts,
+static void mesh_flush_select_from_verts(const Span<MEdge> edges,
+ const Span<MPoly> polys,
const Span<MLoop> loops,
const VArray<bool> &hide_edge,
const VArray<bool> &hide_poly,
- MutableSpan<MEdge> edges,
- MutableSpan<MPoly> polys)
+ const VArray<bool> &select_vert,
+ MutableSpan<bool> select_edge,
+ MutableSpan<bool> select_poly)
{
+ /* Select visible edges that have both of their vertices selected. */
for (const int i : edges.index_range()) {
if (!hide_edge[i]) {
- MEdge &edge = edges[i];
- if ((verts[edge.v1].flag & SELECT) && (verts[edge.v2].flag & SELECT)) {
- edge.flag |= SELECT;
- }
- else {
- edge.flag &= ~SELECT;
- }
+ const MEdge &edge = edges[i];
+ select_edge[i] = select_vert[edge.v1] && select_vert[edge.v2];
}
}
+ /* Select visible faces that have all of their vertices selected. */
for (const int i : polys.index_range()) {
- if (hide_poly[i]) {
- continue;
- }
- MPoly &poly = polys[i];
- bool all_verts_selected = true;
- for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
- if (!(verts[loop.v].flag & SELECT)) {
- all_verts_selected = false;
- }
- }
- if (all_verts_selected) {
- poly.flag |= ME_FACE_SEL;
- }
- else {
- poly.flag &= (char)~ME_FACE_SEL;
+ if (!hide_poly[i]) {
+ const MPoly &poly = polys[i];
+ const Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop);
+ select_poly[i] = std::all_of(poly_loops.begin(), poly_loops.end(), [&](const MLoop &loop) {
+ return select_vert[loop.v];
+ });
}
}
}
void BKE_mesh_flush_select_from_verts(Mesh *me)
{
- const blender::bke::AttributeAccessor attributes = me->attributes();
+ using namespace blender::bke;
+ MutableAttributeAccessor attributes = me->attributes_for_write();
+ const VArray<bool> select_vert = attributes.lookup_or_default<bool>(
+ ".select_vert", ATTR_DOMAIN_POINT, false);
+ if (select_vert.is_single() && !select_vert.get_internal_single()) {
+ attributes.remove(".select_edge");
+ attributes.remove(".select_poly");
+ return;
+ }
+ SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_only_span<bool>(
+ ".select_edge", ATTR_DOMAIN_EDGE);
+ SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_only_span<bool>(
+ ".select_poly", ATTR_DOMAIN_FACE);
mesh_flush_select_from_verts(
- me->verts(),
+ me->edges(),
+ me->polys(),
me->loops(),
attributes.lookup_or_default<bool>(".hide_edge", ATTR_DOMAIN_EDGE, false),
attributes.lookup_or_default<bool>(".hide_poly", ATTR_DOMAIN_FACE, false),
- me->edges_for_write(),
- me->polys_for_write());
+ select_vert,
+ select_edge.span,
+ select_poly.span);
+ select_edge.finish();
+ select_poly.finish();
}
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc
index 627c0057a28..2c75c477b9a 100644
--- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc
@@ -13,6 +13,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
#include "BLI_edgehash.h"
#include "BLI_math.h"
@@ -918,6 +919,35 @@ void BKE_mesh_add_mface_layers(CustomData *fdata, CustomData *ldata, int total)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Face Set Conversion
+ * \{ */
+
+void BKE_mesh_legacy_face_set_from_generic(Mesh *mesh)
+{
+ using namespace blender;
+ for (CustomDataLayer &layer : MutableSpan(mesh->pdata.layers, mesh->pdata.totlayer)) {
+ if (StringRef(layer.name) == ".sculpt_face_set") {
+ layer.type = CD_SCULPT_FACE_SETS;
+ }
+ }
+ CustomData_update_typemap(&mesh->pdata);
+}
+
+void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh)
+{
+ using namespace blender;
+ for (CustomDataLayer &layer : MutableSpan(mesh->pdata.layers, mesh->pdata.totlayer)) {
+ if (layer.type == CD_SCULPT_FACE_SETS) {
+ BLI_strncpy(layer.name, ".sculpt_face_set", sizeof(layer.name));
+ layer.type = CD_PROP_INT32;
+ }
+ }
+ CustomData_update_typemap(&mesh->pdata);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Bevel Weight Conversion
* \{ */
@@ -979,6 +1009,44 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Edge Crease Conversion
+ * \{ */
+
+void BKE_mesh_legacy_edge_crease_from_layers(Mesh *mesh)
+{
+ using namespace blender;
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
+ if (const float *creases = static_cast<const float *>(
+ CustomData_get_layer(&mesh->edata, CD_CREASE))) {
+ mesh->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+ for (const int i : edges.index_range()) {
+ edges[i].crease_legacy = std::clamp(creases[i], 0.0f, 1.0f) * 255.0f;
+ }
+ }
+ else {
+ mesh->cd_flag &= ~ME_CDFLAG_EDGE_CREASE;
+ for (const int i : edges.index_range()) {
+ edges[i].crease_legacy = 0;
+ }
+ }
+}
+
+void BKE_mesh_legacy_edge_crease_to_layers(Mesh *mesh)
+{
+ using namespace blender;
+ const Span<MEdge> edges = mesh->edges();
+ if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) {
+ float *creases = static_cast<float *>(
+ CustomData_add_layer(&mesh->edata, CD_CREASE, CD_CONSTRUCT, nullptr, edges.size()));
+ for (const int i : edges.index_range()) {
+ creases[i] = edges[i].crease_legacy / 255.0f;
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Hide Attribute and Legacy Flag Conversion
* \{ */
@@ -993,7 +1061,7 @@ void BKE_mesh_legacy_convert_hide_layers_to_flags(Mesh *mesh)
".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);
+ SET_FLAG_FROM_TEST(verts[i].flag_legacy, hide_vert[i], ME_HIDE);
}
});
@@ -1023,13 +1091,14 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh)
MutableAttributeAccessor attributes = mesh->attributes_for_write();
const Span<MVert> verts = mesh->verts();
- if (std::any_of(
- verts.begin(), verts.end(), [](const MVert &vert) { return vert.flag & ME_HIDE; })) {
+ if (std::any_of(verts.begin(), verts.end(), [](const MVert &vert) {
+ return vert.flag_legacy & 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.span[i] = verts[i].flag_legacy & ME_HIDE;
}
});
hide_vert.finish();
@@ -1063,6 +1132,7 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh)
}
/** \} */
+
/* -------------------------------------------------------------------- */
/** \name Material Index Conversion
* \{ */
@@ -1102,3 +1172,90 @@ void BKE_mesh_legacy_convert_mpoly_to_material_indices(Mesh *mesh)
}
/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Selection Attribute and Legacy Flag Conversion
+ * \{ */
+
+void BKE_mesh_legacy_convert_selection_layers_to_flags(Mesh *mesh)
+{
+ using namespace blender;
+ using namespace blender::bke;
+ const AttributeAccessor attributes = mesh->attributes();
+
+ MutableSpan<MVert> verts = mesh->verts_for_write();
+ const VArray<bool> select_vert = attributes.lookup_or_default<bool>(
+ ".select_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_legacy, select_vert[i], SELECT);
+ }
+ });
+
+ MutableSpan<MEdge> edges = mesh->edges_for_write();
+ const VArray<bool> select_edge = attributes.lookup_or_default<bool>(
+ ".select_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, select_edge[i], SELECT);
+ }
+ });
+
+ MutableSpan<MPoly> polys = mesh->polys_for_write();
+ const VArray<bool> select_poly = attributes.lookup_or_default<bool>(
+ ".select_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, select_poly[i], ME_FACE_SEL);
+ }
+ });
+}
+
+void BKE_mesh_legacy_convert_flags_to_selection_layers(Mesh *mesh)
+{
+ using namespace blender;
+ using namespace blender::bke;
+ MutableAttributeAccessor attributes = mesh->attributes_for_write();
+
+ const Span<MVert> verts = mesh->verts();
+ if (std::any_of(verts.begin(), verts.end(), [](const MVert &vert) {
+ return vert.flag_legacy & SELECT;
+ })) {
+ SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_only_span<bool>(
+ ".select_vert", ATTR_DOMAIN_POINT);
+ threading::parallel_for(verts.index_range(), 4096, [&](IndexRange range) {
+ for (const int i : range) {
+ select_vert.span[i] = (verts[i].flag_legacy & SELECT) != 0;
+ }
+ });
+ select_vert.finish();
+ }
+
+ const Span<MEdge> edges = mesh->edges();
+ if (std::any_of(
+ edges.begin(), edges.end(), [](const MEdge &edge) { return edge.flag & SELECT; })) {
+ SpanAttributeWriter<bool> select_edge = attributes.lookup_or_add_for_write_only_span<bool>(
+ ".select_edge", ATTR_DOMAIN_EDGE);
+ threading::parallel_for(edges.index_range(), 4096, [&](IndexRange range) {
+ for (const int i : range) {
+ select_edge.span[i] = (edges[i].flag & SELECT) != 0;
+ }
+ });
+ select_edge.finish();
+ }
+
+ const Span<MPoly> polys = mesh->polys();
+ if (std::any_of(
+ polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_FACE_SEL; })) {
+ SpanAttributeWriter<bool> select_poly = attributes.lookup_or_add_for_write_only_span<bool>(
+ ".select_poly", ATTR_DOMAIN_FACE);
+ threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
+ for (const int i : range) {
+ select_poly.span[i] = (polys[i].flag & ME_FACE_SEL) != 0;
+ }
+ });
+ select_poly.finish();
+ }
+}
+
+/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.cc
index f57effd49f4..b612564ef09 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.cc
@@ -12,6 +12,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_vec_types.h"
+#include "BLI_array.hh"
#include "BLI_bitmap.h"
#include "BLI_buffer.h"
#include "BLI_math.h"
@@ -30,6 +31,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 bool *select_poly,
const MLoop *mloop,
const MLoopUV *mloopuv,
uint totpoly,
@@ -52,7 +54,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 || (!(hide_poly && hide_poly[a]) && (mp->flag & ME_FACE_SEL))) {
+ if (!selected || (!(hide_poly && hide_poly[a]) && (select_poly && select_poly[a]))) {
totuv += mp->totloop;
}
}
@@ -65,7 +67,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * (size_t)totuv, "UvMapVert");
vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totvert, "UvMapVert*");
if (use_winding) {
- winding = MEM_callocN(sizeof(*winding) * totpoly, "winding");
+ winding = static_cast<bool *>(MEM_callocN(sizeof(*winding) * totpoly, "winding"));
}
if (!vmap->vert || !vmap->buf) {
@@ -75,7 +77,7 @@ UvVertMap *BKE_mesh_uv_vert_map_create(const MPoly *mpoly,
mp = mpoly;
for (a = 0; a < totpoly; a++, mp++) {
- if (!selected || (!(hide_poly && hide_poly[a]) && (mp->flag & ME_FACE_SEL))) {
+ if (!selected || (!(hide_poly && hide_poly[a]) && (select_poly && select_poly[a]))) {
float(*tf_uv)[2] = NULL;
if (use_winding) {
@@ -194,11 +196,12 @@ static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map,
int totloop,
const bool do_loops)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
+ MeshElemMap *map = MEM_cnew_array<MeshElemMap>((size_t)totvert, __func__);
int *indices, *index_iter;
int i, j;
- indices = index_iter = MEM_mallocN(sizeof(int) * (size_t)totloop, __func__);
+ indices = static_cast<int *>(MEM_mallocN(sizeof(int) * (size_t)totloop, __func__));
+ index_iter = indices;
/* Count number of polys for each vertex */
for (i = 0; i < totpoly; i++) {
@@ -265,8 +268,8 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
const MLoop *mloop,
const int UNUSED(totloop))
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, __func__);
- int *indices = MEM_mallocN(sizeof(int) * (size_t)totlooptri * 3, __func__);
+ MeshElemMap *map = MEM_cnew_array<MeshElemMap>((size_t)totvert, __func__);
+ int *indices = static_cast<int *>(MEM_mallocN(sizeof(int) * (size_t)totlooptri * 3, __func__));
int *index_step;
const MLoopTri *mlt;
int i;
@@ -303,8 +306,8 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map,
void BKE_mesh_vert_edge_map_create(
MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
- int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
+ MeshElemMap *map = MEM_cnew_array<MeshElemMap>((size_t)totvert, __func__);
+ int *indices = static_cast<int *>(MEM_mallocN(sizeof(int[2]) * (size_t)totedge, __func__));
int *i_pt = indices;
int i;
@@ -342,8 +345,8 @@ void BKE_mesh_vert_edge_map_create(
void BKE_mesh_vert_edge_vert_map_create(
MeshElemMap **r_map, int **r_mem, const MEdge *medge, int totvert, int totedge)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totvert, "vert-edge map");
- int *indices = MEM_mallocN(sizeof(int[2]) * (size_t)totedge, "vert-edge map mem");
+ MeshElemMap *map = MEM_cnew_array<MeshElemMap>((size_t)totvert, __func__);
+ int *indices = static_cast<int *>(MEM_mallocN(sizeof(int[2]) * (size_t)totedge, __func__));
int *i_pt = indices;
int i;
@@ -387,8 +390,8 @@ void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map,
const MLoop *mloop,
const int totloop)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
- int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop * 2, "edge-poly map mem");
+ MeshElemMap *map = MEM_cnew_array<MeshElemMap>((size_t)totedge, __func__);
+ int *indices = static_cast<int *>(MEM_mallocN(sizeof(int) * (size_t)totloop * 2, __func__));
int *index_step;
const MPoly *mp;
int i;
@@ -440,8 +443,8 @@ void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map,
const MLoop *mloop,
const int totloop)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totedge, "edge-poly map");
- int *indices = MEM_mallocN(sizeof(int) * (size_t)totloop, "edge-poly map mem");
+ MeshElemMap *map = MEM_cnew_array<MeshElemMap>((size_t)totedge, __func__);
+ int *indices = static_cast<int *>(MEM_mallocN(sizeof(int) * (size_t)totloop, __func__));
int *index_step;
const MPoly *mp;
int i;
@@ -485,8 +488,8 @@ void BKE_mesh_origindex_map_create(MeshElemMap **r_map,
const int *final_origindex,
const int totfinal)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)totsource, "poly-tessface map");
- int *indices = MEM_mallocN(sizeof(int) * (size_t)totfinal, "poly-tessface map mem");
+ MeshElemMap *map = MEM_cnew_array<MeshElemMap>((size_t)totsource, __func__);
+ int *indices = static_cast<int *>(MEM_mallocN(sizeof(int) * (size_t)totfinal, __func__));
int *index_step;
int i;
@@ -527,8 +530,8 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
const MLoopTri *looptri,
const int looptri_num)
{
- MeshElemMap *map = MEM_callocN(sizeof(MeshElemMap) * (size_t)mpoly_num, "poly-tessface map");
- int *indices = MEM_mallocN(sizeof(int) * (size_t)looptri_num, "poly-tessface map mem");
+ MeshElemMap *map = MEM_cnew_array<MeshElemMap>((size_t)mpoly_num, __func__);
+ int *indices = static_cast<int *>(MEM_mallocN(sizeof(int) * (size_t)looptri_num, __func__));
int *index_step;
int i;
@@ -559,13 +562,13 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
/**
* Callback deciding whether the given poly/loop/edge define an island boundary or not.
*/
-typedef bool (*MeshRemap_CheckIslandBoundary)(const struct MPoly *mpoly,
- const struct MLoop *mloop,
- const struct MEdge *medge,
- const int edge_user_count,
- const struct MPoly *mpoly_array,
- const struct MeshElemMap *edge_poly_map,
- void *user_data);
+using MeshRemap_CheckIslandBoundary = bool (*)(const MPoly *mpoly,
+ const MLoop *mloop,
+ const MEdge *medge,
+ const int edge_user_count,
+ const MPoly *mpoly_array,
+ const MeshElemMap *edge_poly_map,
+ void *user_data);
static void poly_edge_loop_islands_calc(const MEdge *medge,
const int totedge,
@@ -620,8 +623,8 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
&edge_poly_map, &edge_poly_mem, medge, totedge, mpoly, totpoly, mloop, totloop);
}
- poly_groups = MEM_callocN(sizeof(int) * (size_t)totpoly, __func__);
- poly_stack = MEM_mallocN(sizeof(int) * (size_t)totpoly, __func__);
+ poly_groups = static_cast<int *>(MEM_callocN(sizeof(int) * (size_t)totpoly, __func__));
+ poly_stack = static_cast<int *>(MEM_mallocN(sizeof(int) * (size_t)totpoly, __func__));
while (true) {
int poly;
@@ -834,17 +837,17 @@ void BKE_mesh_loop_islands_init(MeshIslandStore *island_store,
island_store->item_type = item_type;
island_store->items_to_islands_num = items_num;
- island_store->items_to_islands = BLI_memarena_alloc(
- mem, sizeof(*island_store->items_to_islands) * (size_t)items_num);
+ island_store->items_to_islands = static_cast<int *>(
+ BLI_memarena_alloc(mem, sizeof(*island_store->items_to_islands) * (size_t)items_num));
island_store->island_type = island_type;
island_store->islands_num_alloc = MISLAND_DEFAULT_BUFSIZE;
- island_store->islands = BLI_memarena_alloc(
- mem, sizeof(*island_store->islands) * island_store->islands_num_alloc);
+ island_store->islands = static_cast<MeshElemMap **>(
+ BLI_memarena_alloc(mem, sizeof(*island_store->islands) * island_store->islands_num_alloc));
island_store->innercut_type = innercut_type;
- island_store->innercuts = BLI_memarena_alloc(
- mem, sizeof(*island_store->innercuts) * island_store->islands_num_alloc);
+ island_store->innercuts = static_cast<MeshElemMap **>(
+ BLI_memarena_alloc(mem, sizeof(*island_store->innercuts) * island_store->islands_num_alloc));
}
void BKE_mesh_loop_islands_clear(MeshIslandStore *island_store)
@@ -898,24 +901,29 @@ void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
MeshElemMap **islds, **innrcuts;
island_store->islands_num_alloc *= 2;
- islds = BLI_memarena_alloc(mem, sizeof(*islds) * island_store->islands_num_alloc);
+ islds = static_cast<MeshElemMap **>(
+ BLI_memarena_alloc(mem, sizeof(*islds) * island_store->islands_num_alloc));
memcpy(islds, island_store->islands, sizeof(*islds) * (curr_num_islands - 1));
island_store->islands = islds;
- innrcuts = BLI_memarena_alloc(mem, sizeof(*innrcuts) * island_store->islands_num_alloc);
+ innrcuts = static_cast<MeshElemMap **>(
+ BLI_memarena_alloc(mem, sizeof(*innrcuts) * island_store->islands_num_alloc));
memcpy(innrcuts, island_store->innercuts, sizeof(*innrcuts) * (curr_num_islands - 1));
island_store->innercuts = innrcuts;
}
- island_store->islands[curr_island_idx] = isld = BLI_memarena_alloc(mem, sizeof(*isld));
+ island_store->islands[curr_island_idx] = isld = static_cast<MeshElemMap *>(
+ BLI_memarena_alloc(mem, sizeof(*isld)));
isld->count = num_island_items;
- isld->indices = BLI_memarena_alloc(mem, sizeof(*isld->indices) * (size_t)num_island_items);
+ isld->indices = static_cast<int *>(
+ BLI_memarena_alloc(mem, sizeof(*isld->indices) * (size_t)num_island_items));
memcpy(isld->indices, island_item_indices, sizeof(*isld->indices) * (size_t)num_island_items);
- island_store->innercuts[curr_island_idx] = innrcut = BLI_memarena_alloc(mem, sizeof(*innrcut));
+ island_store->innercuts[curr_island_idx] = innrcut = static_cast<MeshElemMap *>(
+ BLI_memarena_alloc(mem, sizeof(*innrcut)));
innrcut->count = num_innercut_items;
- innrcut->indices = BLI_memarena_alloc(mem,
- sizeof(*innrcut->indices) * (size_t)num_innercut_items);
+ innrcut->indices = static_cast<int *>(
+ BLI_memarena_alloc(mem, sizeof(*innrcut->indices) * (size_t)num_innercut_items));
memcpy(innrcut->indices,
innercut_item_indices,
sizeof(*innrcut->indices) * (size_t)num_innercut_items);
@@ -927,11 +935,11 @@ void BKE_mesh_loop_islands_add(MeshIslandStore *island_store,
* Would make things much more complex though,
* and each UVMap would then need its own mesh mapping, not sure we want that at all!
*/
-typedef struct MeshCheckIslandBoundaryUv {
+struct MeshCheckIslandBoundaryUv {
const MLoop *loops;
const MLoopUV *luvs;
const MeshElemMap *edge_loop_map;
-} MeshCheckIslandBoundaryUv;
+};
static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp),
const MLoop *ml,
@@ -942,7 +950,8 @@ static bool mesh_check_island_boundary_uv(const MPoly *UNUSED(mp),
void *user_data)
{
if (user_data) {
- const MeshCheckIslandBoundaryUv *data = user_data;
+ const MeshCheckIslandBoundaryUv *data = static_cast<const MeshCheckIslandBoundaryUv *>(
+ user_data);
const MLoop *loops = data->loops;
const MLoopUV *luvs = data->luvs;
const MeshElemMap *edge_to_loops = &data->edge_loop_map[ml->e];
@@ -1056,13 +1065,16 @@ static bool mesh_calc_islands_loop_poly_uv(const MVert *UNUSED(verts),
}
if (num_edge_borders) {
- edge_border_count = MEM_mallocN(sizeof(*edge_border_count) * (size_t)totedge, __func__);
- edge_innercut_indices = MEM_mallocN(sizeof(*edge_innercut_indices) * (size_t)num_edge_borders,
- __func__);
+ edge_border_count = static_cast<char *>(
+ MEM_mallocN(sizeof(*edge_border_count) * (size_t)totedge, __func__));
+ edge_innercut_indices = static_cast<int *>(
+ MEM_mallocN(sizeof(*edge_innercut_indices) * (size_t)num_edge_borders, __func__));
}
- poly_indices = MEM_mallocN(sizeof(*poly_indices) * (size_t)totpoly, __func__);
- loop_indices = MEM_mallocN(sizeof(*loop_indices) * (size_t)totloop, __func__);
+ poly_indices = static_cast<int *>(
+ MEM_mallocN(sizeof(*poly_indices) * (size_t)totpoly, __func__));
+ loop_indices = static_cast<int *>(
+ MEM_mallocN(sizeof(*loop_indices) * (size_t)totloop, __func__));
/* NOTE: here we ignore '0' invalid group - this should *never* happen in this case anyway? */
for (grp_idx = 1; grp_idx <= num_poly_groups; grp_idx++) {
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index a77879fb573..3c492e2e167 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
@@ -24,6 +24,7 @@
#include "DNA_meshdata_types.h"
#include "BKE_attribute.h"
+#include "BKE_attribute.hh"
#include "BKE_bvhutils.h"
#include "BKE_customdata.h"
#include "BKE_editmesh.h"
@@ -193,8 +194,7 @@ static openvdb::FloatGrid::Ptr remesh_voxel_level_set_create(const Mesh *mesh,
{
const Span<MVert> verts = mesh->verts();
const Span<MLoop> loops = mesh->loops();
- Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh),
- BKE_mesh_runtime_looptri_len(mesh)};
+ const Span<MLoopTri> looptris = mesh->looptris();
std::vector<openvdb::Vec3s> points(mesh->totvert);
std::vector<openvdb::Vec3I> triangles(looptris.size());
@@ -318,24 +318,28 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, const Mesh *source)
void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source)
{
+ using namespace blender;
+ using namespace blender::bke;
+ const AttributeAccessor src_attributes = source->attributes();
+ MutableAttributeAccessor dst_attributes = target->attributes_for_write();
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)) {
- target_face_sets = (int *)CustomData_get_layer(&target->pdata, CD_SCULPT_FACE_SETS);
+ const VArray<int> src_face_sets = src_attributes.lookup<int>(".sculpt_face_set",
+ ATTR_DOMAIN_FACE);
+ if (!src_face_sets) {
+ return;
}
- else {
- target_face_sets = (int *)CustomData_add_layer(
- &target->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, target->totpoly);
+ SpanAttributeWriter<int> dst_face_sets = dst_attributes.lookup_or_add_for_write_only_span<int>(
+ ".sculpt_face_set", ATTR_DOMAIN_FACE);
+ if (!dst_face_sets) {
+ return;
}
+ const VArraySpan<int> src(src_face_sets);
+ MutableSpan<int> dst = dst_face_sets.span;
+
const MLoopTri *looptri = BKE_mesh_runtime_looptri_ensure(source);
BVHTreeFromMesh bvhtree = {nullptr};
BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_LOOPTRI, 2);
@@ -349,13 +353,14 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source)
BKE_mesh_calc_poly_center(mpoly, &target_loops[mpoly->loopstart], target_verts, from_co);
BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
if (nearest.index != -1) {
- target_face_sets[i] = source_face_sets[looptri[nearest.index].poly];
+ dst[i] = src[looptri[nearest.index].poly];
}
else {
- target_face_sets[i] = 1;
+ dst[i] = 1;
}
}
free_bvhtree_from_mesh(&bvhtree);
+ dst_face_sets.finish();
}
void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source)
diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc
index a66f2a714e7..062d6cdb952 100644
--- a/source/blender/blenkernel/intern/mesh_runtime.cc
+++ b/source/blender/blenkernel/intern/mesh_runtime.cc
@@ -112,6 +112,13 @@ void BKE_mesh_runtime_clear_cache(Mesh *mesh)
BKE_mesh_clear_derived_normals(mesh);
}
+blender::Span<MLoopTri> Mesh::looptris() const
+{
+ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(this);
+ const int num_looptris = BKE_mesh_runtime_looptri_len(this);
+ return {looptris, num_looptris};
+}
+
/**
* Ensure the array is large enough
*
@@ -154,12 +161,23 @@ void BKE_mesh_runtime_looptri_recalc(Mesh *mesh)
const Span<MPoly> polys = mesh->polys();
const Span<MLoop> loops = mesh->loops();
- BKE_mesh_recalc_looptri(loops.data(),
- polys.data(),
- verts.data(),
- mesh->totloop,
- mesh->totpoly,
- mesh->runtime.looptris.array_wip);
+ if (!BKE_mesh_poly_normals_are_dirty(mesh)) {
+ BKE_mesh_recalc_looptri_with_normals(loops.data(),
+ polys.data(),
+ verts.data(),
+ mesh->totloop,
+ mesh->totpoly,
+ mesh->runtime.looptris.array_wip,
+ BKE_mesh_poly_normals_ensure(mesh));
+ }
+ else {
+ BKE_mesh_recalc_looptri(loops.data(),
+ polys.data(),
+ verts.data(),
+ mesh->totloop,
+ mesh->totpoly,
+ mesh->runtime.looptris.array_wip);
+ }
BLI_assert(mesh->runtime.looptris.array == nullptr);
atomic_cas_ptr((void **)&mesh->runtime.looptris.array,
@@ -280,10 +298,10 @@ void BKE_mesh_tag_coords_changed_uniformly(Mesh *mesh)
BKE_mesh_tag_coords_changed(mesh);
/* The normals didn't change, since all verts moved by the same amount. */
if (!vert_normals_were_dirty) {
- BKE_mesh_poly_normals_clear_dirty(mesh);
+ BKE_mesh_vertex_normals_clear_dirty(mesh);
}
if (!poly_normals_were_dirty) {
- BKE_mesh_vertex_normals_clear_dirty(mesh);
+ BKE_mesh_poly_normals_clear_dirty(mesh);
}
}
diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc
index 1ddac19304d..ed7ae8113a7 100644
--- a/source/blender/blenkernel/intern/mesh_sample.cc
+++ b/source/blender/blenkernel/intern/mesh_sample.cc
@@ -22,8 +22,7 @@ BLI_NOINLINE static void sample_point_attribute(const Mesh &mesh,
const MutableSpan<T> dst)
{
const Span<MLoop> loops = mesh.loops();
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
+ const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : mask) {
const int looptri_index = looptri_indices[i];
@@ -69,8 +68,7 @@ BLI_NOINLINE static void sample_corner_attribute(const Mesh &mesh,
const IndexMask mask,
const MutableSpan<T> dst)
{
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
+ const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : mask) {
const int looptri_index = looptri_indices[i];
@@ -115,8 +113,7 @@ void sample_face_attribute(const Mesh &mesh,
const IndexMask mask,
const MutableSpan<T> dst)
{
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
+ const Span<MLoopTri> looptris = mesh.looptris();
for (const int i : mask) {
const int looptri_index = looptri_indices[i];
@@ -161,8 +158,7 @@ Span<float3> MeshAttributeInterpolator::ensure_barycentric_coords()
const Span<MVert> verts = mesh_->verts();
const Span<MLoop> loops = mesh_->loops();
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_),
- BKE_mesh_runtime_looptri_len(mesh_)};
+ const Span<MLoopTri> looptris = mesh_->looptris();
for (const int i : mask_) {
const int looptri_index = looptri_indices_[i];
@@ -191,8 +187,7 @@ Span<float3> MeshAttributeInterpolator::ensure_nearest_weights()
const Span<MVert> verts = mesh_->verts();
const Span<MLoop> loops = mesh_->loops();
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(mesh_),
- BKE_mesh_runtime_looptri_len(mesh_)};
+ const Span<MLoopTri> looptris = mesh_->looptris();
for (const int i : mask_) {
const int looptri_index = looptri_indices_[i];
@@ -265,8 +260,7 @@ int sample_surface_points_spherical(RandomNumberGenerator &rng,
{
const Span<MVert> verts = mesh.verts();
const Span<MLoop> loops = mesh.loops();
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
+ const Span<MLoopTri> looptris = mesh.looptris();
const float sample_radius_sq = pow2f(sample_radius);
const float sample_plane_area = M_PI * sample_radius_sq;
@@ -363,8 +357,7 @@ int sample_surface_points_projected(
{
const Span<MVert> verts = mesh.verts();
const Span<MLoop> loops = mesh.loops();
- const Span<MLoopTri> looptris{BKE_mesh_runtime_looptri_ensure(&mesh),
- BKE_mesh_runtime_looptri_len(&mesh)};
+ const Span<MLoopTri> looptris = mesh.looptris();
int point_count = 0;
for ([[maybe_unused]] const int _ : IndexRange(tries_num)) {
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 7dc7e6009d9..ce61ca483e9 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -62,7 +62,7 @@ typedef enum {
static void multiresModifier_disp_run(
DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl);
-/** Customdata */
+/** Custom-data. */
void multires_customdata_delete(Mesh *me)
{
diff --git a/source/blender/blenkernel/intern/multires_reshape.h b/source/blender/blenkernel/intern/multires_reshape.h
index 5e2822ad5df..f27618b2145 100644
--- a/source/blender/blenkernel/intern/multires_reshape.h
+++ b/source/blender/blenkernel/intern/multires_reshape.h
@@ -101,6 +101,8 @@ typedef struct MultiresReshapeContext {
/* Vertex crease custom data layer, null if none is present. */
const float *cd_vertex_crease;
+ /* Edge crease custom data layer, null if none is present. */
+ const float *cd_edge_crease;
} MultiresReshapeContext;
/**
diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c
index e887f543dc5..1463404069f 100644
--- a/source/blender/blenkernel/intern/multires_reshape_smooth.c
+++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c
@@ -482,13 +482,14 @@ static bool is_crease_supported(const MultiresReshapeSmoothContext *reshape_smoo
/* Get crease which will be used for communication to OpenSubdiv topology.
* Note that simple subdivision treats all base edges as infinitely sharp. */
-static char get_effective_crease_char(const MultiresReshapeSmoothContext *reshape_smooth_context,
- const MEdge *base_edge)
+static float get_effective_crease(const MultiresReshapeSmoothContext *reshape_smooth_context,
+ const int base_edge_index)
{
if (!is_crease_supported(reshape_smooth_context)) {
return 255;
}
- return base_edge->crease;
+ const float *creases = reshape_smooth_context->reshape_context->cd_vertex_crease;
+ return creases ? creases[base_edge_index] : 0.0f;
}
static float get_effective_crease_float(const MultiresReshapeSmoothContext *reshape_smooth_context,
@@ -812,7 +813,6 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
const int subdiv_v2)
{
MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data;
- const MultiresReshapeContext *reshape_context = reshape_smooth_context->reshape_context;
if (reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR) {
if (!is_loose) {
@@ -832,8 +832,7 @@ static void foreach_edge(const struct SubdivForeachContext *foreach_context,
return;
}
/* Edges without crease are to be ignored as well. */
- const MEdge *base_edge = &reshape_context->base_edges[coarse_edge_index];
- const char crease = get_effective_crease_char(reshape_smooth_context, base_edge);
+ const char crease = get_effective_crease(reshape_smooth_context, coarse_edge_index);
if (crease == 0) {
return;
}
@@ -846,7 +845,6 @@ static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshap
const Mesh *base_mesh = reshape_context->base_mesh;
const MPoly *base_mpoly = reshape_context->base_polys;
const MLoop *base_mloop = reshape_context->base_loops;
- const MEdge *base_edge = reshape_context->base_edges;
reshape_smooth_context->non_loose_base_edge_map = BLI_BITMAP_NEW(base_mesh->totedge,
"non_loose_base_edge_map");
@@ -859,8 +857,8 @@ static void geometry_init_loose_information(MultiresReshapeSmoothContext *reshap
if (!BLI_BITMAP_TEST_BOOL(reshape_smooth_context->non_loose_base_edge_map, loop->e)) {
BLI_BITMAP_ENABLE(reshape_smooth_context->non_loose_base_edge_map, loop->e);
- const char crease = get_effective_crease_char(reshape_smooth_context, &base_edge[loop->e]);
- if (crease != 0) {
+ const float crease = get_effective_crease(reshape_smooth_context, loop->e);
+ if (crease > 0.0f) {
++num_used_edges;
}
}
diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c
index 5b60394feda..4fc1217158c 100644
--- a/source/blender/blenkernel/intern/multires_reshape_util.c
+++ b/source/blender/blenkernel/intern/multires_reshape_util.c
@@ -206,6 +206,7 @@ bool multires_reshape_context_create_from_object(MultiresReshapeContext *reshape
reshape_context->top.grid_size = BKE_subdiv_grid_size_from_level(reshape_context->top.level);
reshape_context->cd_vertex_crease = CustomData_get_layer(&base_mesh->vdata, CD_CREASE);
+ reshape_context->cd_edge_crease = CustomData_get_layer(&base_mesh->edata, CD_CREASE);
context_init_commoon(reshape_context);
@@ -271,6 +272,8 @@ bool multires_reshape_context_create_from_subdiv(MultiresReshapeContext *reshape
reshape_context->base_edges = BKE_mesh_edges(base_mesh);
reshape_context->base_polys = BKE_mesh_polys(base_mesh);
reshape_context->base_loops = BKE_mesh_loops(base_mesh);
+ reshape_context->cd_vertex_crease = (const float *)CustomData_get_layer(&base_mesh->edata,
+ CD_CREASE);
reshape_context->subdiv = subdiv;
reshape_context->need_free_subdiv = false;
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index da508ff865c..c0315dcc848 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -2072,7 +2072,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
/* handle AnimData level changes:
* - 'real' active action to temp storage (no need to change user-counts).
- * - Action of active strip set to be the 'active action', and have its usercount incremented.
+ * - Action of active strip set to be the 'active action', and have its user-count incremented.
* - Editing-flag for this AnimData block should also get turned on
* (for more efficient restoring).
* - Take note of the active strip for mapping-correction of keyframes
@@ -2136,7 +2136,8 @@ void BKE_nla_tweakmode_exit(AnimData *adt)
}
/* handle AnimData level changes:
- * - 'temporary' active action needs its usercount decreased, since we're removing this reference
+ * - 'temporary' active action needs its user-count decreased,
+ * since we're removing this reference
* - 'real' active action is restored from storage
* - storage pointer gets cleared (to avoid having bad notes hanging around)
* - editing-flag for this AnimData block should also get turned off
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index b82cf30416a..1c7b1b9fa3e 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -47,6 +47,7 @@
#include "BKE_anim_data.h"
#include "BKE_animsys.h"
+#include "BKE_asset.h"
#include "BKE_bpath.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
@@ -54,6 +55,7 @@
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
+#include "BKE_idprop.hh"
#include "BKE_idtype.h"
#include "BKE_image_format.h"
#include "BKE_lib_id.h"
@@ -132,7 +134,7 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c
bNodeTree *ntree_dst = (bNodeTree *)id_dst;
const bNodeTree *ntree_src = (const bNodeTree *)id_src;
- /* We never handle usercount here for own data. */
+ /* We never handle user-count here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
ntree_dst->runtime = MEM_new<bNodeTreeRuntime>(__func__);
@@ -1026,6 +1028,33 @@ static void ntree_blend_read_expand(BlendExpander *expander, ID *id)
ntreeBlendReadExpand(expander, ntree);
}
+namespace blender::bke {
+
+static void node_tree_asset_pre_save(void *asset_ptr, struct AssetMetaData *asset_data)
+{
+ bNodeTree &node_tree = *static_cast<bNodeTree *>(asset_ptr);
+
+ BKE_asset_metadata_idprop_ensure(asset_data, idprop::create("type", node_tree.type).release());
+ auto inputs = idprop::create_group("inputs");
+ auto outputs = idprop::create_group("outputs");
+ LISTBASE_FOREACH (const bNodeSocket *, socket, &node_tree.inputs) {
+ auto property = idprop::create(socket->name, socket->typeinfo->idname);
+ IDP_AddToGroup(inputs.get(), property.release());
+ }
+ LISTBASE_FOREACH (const bNodeSocket *, socket, &node_tree.outputs) {
+ auto property = idprop::create(socket->name, socket->typeinfo->idname);
+ IDP_AddToGroup(outputs.get(), property.release());
+ }
+ BKE_asset_metadata_idprop_ensure(asset_data, inputs.release());
+ BKE_asset_metadata_idprop_ensure(asset_data, outputs.release());
+}
+
+} // namespace blender::bke
+
+static AssetTypeInfo AssetType_NT = {
+ /* pre_save_fn */ blender::bke::node_tree_asset_pre_save,
+};
+
IDTypeInfo IDType_ID_NT = {
/* id_code */ ID_NT,
/* id_filter */ FILTER_ID_NT,
@@ -1035,7 +1064,7 @@ IDTypeInfo IDType_ID_NT = {
/* name_plural */ "node_groups",
/* translation_context */ BLT_I18NCONTEXT_ID_NODETREE,
/* flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE,
- /* asset_type_info */ nullptr,
+ /* asset_type_info */ &AssetType_NT,
/* init_data */ ntree_init_data,
/* copy_data */ ntree_copy_data,
@@ -2149,7 +2178,7 @@ bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idnam
BKE_ntree_update_tag_node_new(ntree, node);
- if (node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ if (ELEM(node->type, GEO_NODE_INPUT_SCENE_TIME, GEO_NODE_SELF_OBJECT)) {
DEG_relations_tag_update(CTX_data_main(C));
}
@@ -2992,7 +3021,7 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user)
/* Also update relations for the scene time node, which causes a dependency
* on time that users expect to be removed when the node is removed. */
- if (node_has_id || node->type == GEO_NODE_INPUT_SCENE_TIME) {
+ if (node_has_id || ELEM(node->type, GEO_NODE_INPUT_SCENE_TIME, GEO_NODE_SELF_OBJECT)) {
if (bmain != nullptr) {
DEG_relations_tag_update(bmain);
}
@@ -4702,6 +4731,7 @@ static void registerGeometryNodes()
register_node_type_geo_curve_trim();
register_node_type_geo_deform_curves_on_surface();
register_node_type_geo_delete_geometry();
+ register_node_type_geo_distribute_points_in_volume();
register_node_type_geo_distribute_points_on_faces();
register_node_type_geo_dual_mesh();
register_node_type_geo_duplicate_elements();
@@ -4748,6 +4778,7 @@ static void registerGeometryNodes()
register_node_type_geo_material_replace();
register_node_type_geo_material_selection();
register_node_type_geo_merge_by_distance();
+ register_node_type_geo_mesh_face_set_boundaries();
register_node_type_geo_mesh_primitive_circle();
register_node_type_geo_mesh_primitive_cone();
register_node_type_geo_mesh_primitive_cube();
@@ -4769,10 +4800,14 @@ static void registerGeometryNodes()
register_node_type_geo_realize_instances();
register_node_type_geo_remove_attribute();
register_node_type_geo_rotate_instances();
+ register_node_type_geo_sample_index();
+ register_node_type_geo_sample_nearest_surface();
+ register_node_type_geo_sample_nearest();
register_node_type_geo_scale_elements();
register_node_type_geo_scale_instances();
register_node_type_geo_separate_components();
register_node_type_geo_separate_geometry();
+ register_node_type_geo_self_object();
register_node_type_geo_set_curve_handles();
register_node_type_geo_set_curve_radius();
register_node_type_geo_set_curve_tilt();
@@ -4789,7 +4824,6 @@ static void registerGeometryNodes()
register_node_type_geo_string_to_curves();
register_node_type_geo_subdivision_surface();
register_node_type_geo_switch();
- register_node_type_geo_transfer_attribute();
register_node_type_geo_transform();
register_node_type_geo_translate_instances();
register_node_type_geo_triangulate();
diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc
index 00b78284791..4fb0e423a33 100644
--- a/source/blender/blenkernel/intern/node_runtime.cc
+++ b/source/blender/blenkernel/intern/node_runtime.cc
@@ -14,16 +14,12 @@
namespace blender::bke::node_tree_runtime {
-void handle_node_tree_output_changed(bNodeTree &tree_cow)
+void preprocess_geometry_node_tree_for_evaluation(bNodeTree &tree_cow)
{
- if (tree_cow.type == NTREE_GEOMETRY) {
- /* Rebuild geometry nodes lazy function graph. */
- {
- std::lock_guard lock{tree_cow.runtime->geometry_nodes_lazy_function_graph_info_mutex};
- tree_cow.runtime->geometry_nodes_lazy_function_graph_info.reset();
- }
- blender::nodes::ensure_geometry_nodes_lazy_function_graph(tree_cow);
- }
+ BLI_assert(tree_cow.type == NTREE_GEOMETRY);
+ /* Rebuild geometry nodes lazy function graph. */
+ tree_cow.runtime->geometry_nodes_lazy_function_graph_info.reset();
+ blender::nodes::ensure_geometry_nodes_lazy_function_graph(tree_cow);
}
static void double_checked_lock(std::mutex &mutex, bool &data_is_dirty, FunctionRef<void()> fn)
@@ -127,15 +123,17 @@ static void update_directly_linked_links_and_sockets(const bNodeTree &ntree)
socket->runtime->directly_linked_links.clear();
socket->runtime->directly_linked_sockets.clear();
}
- node->runtime->has_linked_inputs = false;
- node->runtime->has_linked_outputs = false;
+ node->runtime->has_available_linked_inputs = false;
+ node->runtime->has_available_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;
+ if (link->is_available()) {
+ link->fromnode->runtime->has_available_linked_outputs = true;
+ link->tonode->runtime->has_available_linked_inputs = true;
+ }
}
for (bNodeSocket *socket : tree_runtime.input_sockets) {
if (socket->flag & SOCK_MULTI_INPUT) {
@@ -172,7 +170,10 @@ static void find_logical_origins_for_socket_recursive(
links_to_check = links_to_check.take_front(1);
}
for (bNodeLink *link : links_to_check) {
- if (link->flag & NODE_LINK_MUTED) {
+ if (link->is_muted()) {
+ continue;
+ }
+ if (!link->is_available()) {
continue;
}
bNodeSocket &origin_socket = *link->fromsock;
@@ -289,14 +290,20 @@ static void toposort_from_start_node(const ToposortDirection direction,
break;
}
bNodeSocket &socket = *sockets[item.socket_index];
- const Span<bNodeSocket *> linked_sockets = socket.runtime->directly_linked_sockets;
- if (item.link_index == linked_sockets.size()) {
+ const Span<bNodeLink *> linked_links = socket.runtime->directly_linked_links;
+ if (item.link_index == linked_links.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];
+ bNodeLink &link = *linked_links[item.link_index];
+ if (!link.is_available()) {
+ /* Ignore unavailable links. */
+ item.link_index++;
+ continue;
+ }
+ bNodeSocket &linked_socket = *socket.runtime->directly_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) {
@@ -341,8 +348,9 @@ static void update_toposort(const bNodeTree &ntree,
/* Ignore nodes that are done already. */
continue;
}
- if ((direction == ToposortDirection::LeftToRight) ? node->runtime->has_linked_outputs :
- node->runtime->has_linked_inputs) {
+ if ((direction == ToposortDirection::LeftToRight) ?
+ node->runtime->has_available_linked_outputs :
+ node->runtime->has_available_linked_inputs) {
/* Ignore non-start nodes. */
continue;
}
@@ -402,7 +410,7 @@ static void ensure_topology_cache(const bNodeTree &ntree)
update_toposort(ntree,
ToposortDirection::LeftToRight,
tree_runtime.toposort_left_to_right,
- tree_runtime.has_link_cycle);
+ tree_runtime.has_available_link_cycle);
},
[&]() {
bool dummy;
diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc
index b2caaa912d7..f9bab0959c9 100644
--- a/source/blender/blenkernel/intern/node_tree_update.cc
+++ b/source/blender/blenkernel/intern/node_tree_update.cc
@@ -1047,6 +1047,7 @@ class NodeTreeMainUpdater {
void update_individual_nodes(bNodeTree &ntree)
{
+ Vector<bNode *> group_inout_nodes;
LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
nodeDeclarationEnsure(&ntree, node);
if (this->should_update_individual_node(ntree, *node)) {
@@ -1058,6 +1059,18 @@ class NodeTreeMainUpdater {
ntype.updatefunc(&ntree, node);
}
}
+ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) {
+ group_inout_nodes.append(node);
+ }
+ }
+ /* The update function of group input/output nodes may add new interface sockets. When that
+ * happens, all the input/output nodes have to be updated again. In the future it would be
+ * better to move this functionality out of the node update function into the operator that's
+ * supposed to create the new interface socket. */
+ if (ntree.runtime->changed_flag & NTREE_CHANGED_INTERFACE) {
+ for (bNode *node : group_inout_nodes) {
+ node->typeinfo->updatefunc(&ntree, node);
+ }
}
}
@@ -1375,7 +1388,7 @@ class NodeTreeMainUpdater {
uint32_t get_combined_socket_topology_hash(const bNodeTree &tree,
Span<const bNodeSocket *> sockets)
{
- if (tree.has_link_cycle()) {
+ if (tree.has_available_link_cycle()) {
/* Return dummy value when the link has any cycles. The algorithm below could be improved to
* handle cycles more gracefully. */
return 0;
@@ -1391,7 +1404,7 @@ class NodeTreeMainUpdater {
Array<uint32_t> get_socket_topology_hashes(const bNodeTree &tree,
Span<const bNodeSocket *> sockets)
{
- BLI_assert(!tree.has_link_cycle());
+ BLI_assert(!tree.has_available_link_cycle());
Array<std::optional<uint32_t>> hash_by_socket_id(tree.all_sockets().size());
Stack<const bNodeSocket *> sockets_to_check = sockets;
diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc
index cbe5ea425fb..7ea6a4c597e 100644
--- a/source/blender/blenkernel/intern/object.cc
+++ b/source/blender/blenkernel/intern/object.cc
@@ -188,7 +188,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
/* Do not copy runtime data. */
BKE_object_runtime_reset_on_copy(ob_dst, flag);
- /* We never handle usercount here for own data. */
+ /* We never handle user-count here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
if (ob_src->totcol) {
@@ -245,7 +245,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in
BLI_listbase_clear(&ob_dst->modifiers);
BLI_listbase_clear(&ob_dst->greasepencil_modifiers);
- /* NOTE: Also takes care of softbody and particle systems copying. */
+ /* NOTE: Also takes care of soft-body and particle systems copying. */
BKE_object_modifier_stack_copy(ob_dst, ob_src, true, flag_subdata);
BLI_listbase_clear((ListBase *)&ob_dst->drawdata);
@@ -396,7 +396,7 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data)
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->mat[i], IDWALK_CB_USER);
}
- /* Note that ob->gpd is deprecated, so no need to handle it here. */
+ /* Note that `ob->gpd` is deprecated, so no need to handle it here. */
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, object->instance_collection, IDWALK_CB_USER);
if (object->pd) {
@@ -736,9 +736,9 @@ static void object_blend_read_data(BlendDataReader *reader, ID *id)
BLO_read_data_address(reader, &sb->shared);
if (sb->shared == nullptr) {
/* Link deprecated caches if they exist, so we can use them for versioning.
- * We should only do this when sb->shared == nullptr, because those pointers
+ * We should only do this when `sb->shared == nullptr`, because those pointers
* are always set (for compatibility with older Blenders). We mustn't link
- * the same pointcache twice. */
+ * the same point-cache twice. */
BKE_ptcache_blend_read_data(reader, &sb->ptcaches, &sb->pointcache, false);
}
else {
@@ -1141,7 +1141,7 @@ static void object_lib_override_apply_post(ID *id_dst, ID *id_src)
* This code is a workaround this to check all point-caches from both source and destination
* objects in parallel, and transfer those flags when it makes sense.
*
- * This allows to keep baked caches across liboverrides applies.
+ * This allows to keep baked caches across lib-overrides applies.
*
* NOTE: This is fairly hackish and weak, but so is the point-cache system as its whole. A more
* robust solution would be e.g. to have a specific RNA entry point to deal with such cases
@@ -1170,7 +1170,7 @@ static void object_lib_override_apply_post(ID *id_dst, ID *id_src)
point_cache_dst != nullptr;
point_cache_dst = point_cache_dst->next,
point_cache_src = (point_cache_src != nullptr) ? point_cache_src->next : nullptr) {
- /* Always force updating info about caches of applied liboverrides. */
+ /* Always force updating info about caches of applied lib-overrides. */
point_cache_dst->flag |= PTCACHE_FLAG_INFO_DIRTY;
if (point_cache_src == nullptr || !STREQ(point_cache_dst->name, point_cache_src->name)) {
continue;
@@ -1300,10 +1300,10 @@ void BKE_object_free_modifiers(Object *ob, const int flag)
while ((gp_md = (GpencilModifierData *)BLI_pophead(&ob->greasepencil_modifiers))) {
BKE_gpencil_modifier_free_ex(gp_md, flag);
}
- /* particle modifiers were freed, so free the particlesystems as well */
+ /* Particle modifiers were freed, so free the particle-systems as well. */
BKE_object_free_particlesystems(ob);
- /* same for softbody */
+ /* Same for soft-body */
BKE_object_free_softbody(ob);
/* modifiers may have stored data in the DM cache */
@@ -1448,11 +1448,11 @@ static bool object_modifier_type_copy_check(ModifierType md_type)
}
/**
- * Find a `psys` matching given `psys_src` in `ob_dst` (i.e. sharing the same ParticleSettings ID),
- * or add one, and return valid `psys` from `ob_dst`.
+ * Find a `psys` matching given `psys_src` in `ob_dst`
+ * (i.e. sharing the same #ParticleSettings ID), or add one, and return valid `psys` from `ob_dst`.
*
* \note Order handling is fairly weak here. This code assumes that it is called **before** the
- * modifier using the psys is actually copied, and that this copied modifier will be added at the
+ * modifier using the `psys` is actually copied, and that this copied modifier will be added at the
* end of the stack. That way we can be sure that the particle modifier will be before the one
* using its particle system in the stack.
*/
@@ -2484,8 +2484,8 @@ void BKE_object_copy_particlesystems(Object *ob_dst, const Object *ob_src, const
static void copy_object_pose(Object *obn, const Object *ob, const int flag)
{
- /* NOTE: need to clear obn->pose pointer first,
- * so that BKE_pose_copy_data works (otherwise there's a crash) */
+ /* NOTE: need to clear `obn->pose` pointer first,
+ * so that #BKE_pose_copy_data works (otherwise there's a crash) */
obn->pose = nullptr;
BKE_pose_copy_data_ex(&obn->pose, ob->pose, flag, true); /* true = copy constraints */
@@ -2916,7 +2916,7 @@ void BKE_object_rot_to_mat3(const Object *ob, float mat[3][3], bool use_drot)
axis_angle_to_mat3(dmat, ob->drotAxis, ob->drotAngle);
}
else {
- /* quats are normalized before use to eliminate scaling issues */
+ /* Quaternions are normalized before use to eliminate scaling issues. */
float tquat[4];
normalize_qt_qt(tquat, ob->quat);
@@ -2952,7 +2952,7 @@ void BKE_object_mat3_to_rot(Object *ob, float mat[3][3], bool use_compat)
float quat[4];
float dquat[4];
- /* without drot we could apply 'mat' directly */
+ /* Without `drot` we could apply 'mat' directly. */
mat3_normalized_to_quat(quat, mat);
axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle);
invert_qt_normalized(dquat);
@@ -2965,12 +2965,12 @@ void BKE_object_mat3_to_rot(Object *ob, float mat[3][3], bool use_compat)
float quat[4];
float dquat[4];
- /* without drot we could apply 'mat' directly */
+ /* Without `drot` we could apply 'mat' directly. */
mat3_normalized_to_quat(quat, mat);
eulO_to_quat(dquat, ob->drot, ob->rotmode);
invert_qt_normalized(dquat);
mul_qt_qtqt(quat, dquat, quat);
- /* end drot correction */
+ /* End `drot` correction. */
if (use_compat) {
quat_to_compatible_eulO(ob->rot, ob->rot, ob->rotmode, quat);
@@ -3131,12 +3131,11 @@ static bool ob_parcurve(Object *ob, Object *par, float r_mat[4][4])
return false;
}
- /* ctime is now a proper var setting of Curve which gets set by Animato like any other var
+ /* `ctime` is now a proper var setting of Curve which gets set by Animato like any other var
* that's animated, but this will only work if it actually is animated.
*
* We divide the curve-time calculated in the previous step by the length of the path,
- * to get a time factor, which then gets clamped to lie within 0.0 - 1.0 range.
- */
+ * to get a time factor, which then gets clamped to lie within 0.0 - 1.0 range. */
if (cu->pathlen) {
ctime = cu->ctime / cu->pathlen;
}
@@ -3415,7 +3414,7 @@ static void solve_parenting(
mul_m4_m4m4(r_obmat, tmat, locmat);
if (r_originmat) {
- /* usable originmat */
+ /* Usable `r_originmat`. */
copy_m3_m4(r_originmat, tmat);
}
@@ -4096,7 +4095,7 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
}
else {
Object temp_ob = blender::dna::shallow_copy(*dob->ob);
- /* Do not modify the original boundbox. */
+ /* Do not modify the original bounding-box. */
temp_ob.runtime.bb = nullptr;
BKE_object_replace_data_on_shallow_copy(&temp_ob, dob->ob_data);
const BoundBox *bb = BKE_object_boundbox_get(&temp_ob);
@@ -4149,7 +4148,7 @@ void BKE_object_foreach_display_point(Object *ob,
void (*func_cb)(const float[3], void *),
void *user_data)
{
- /* TODO: pointcloud and curves object support */
+ /* TODO: point-cloud and curves object support. */
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
float3 co;
@@ -4188,10 +4187,11 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph,
void (*func_cb)(const float[3], void *),
void *user_data)
{
- DEG_OBJECT_ITER_BEGIN (depsgraph,
- ob,
- DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
- DEG_ITER_OBJECT_FLAG_DUPLI) {
+ DEGObjectIterSettings deg_iter_settings{};
+ deg_iter_settings.depsgraph = depsgraph;
+ deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI;
+ DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
if ((ob->base_flag & BASE_SELECTED) != 0) {
BKE_object_foreach_display_point(ob, ob->obmat, func_cb, user_data);
}
@@ -4298,7 +4298,7 @@ void BKE_object_handle_update_ex(Depsgraph *depsgraph,
* is evaluated on the rebuilt pose, otherwise we get incorrect poses
* on file load */
if (ob->pose == nullptr || (ob->pose->flag & POSE_RECALC)) {
- /* No need to pass bmain here, we assume we do not need to rebuild DEG from here... */
+ /* No need to pass `bmain` here, we assume we do not need to rebuild DEG from here. */
BKE_pose_rebuild(nullptr, ob, (bArmature *)ob->data, true);
}
}
@@ -5449,8 +5449,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
depsgraph, scene, ob->track, false, recursion, frame, type);
}
- /* skip subframe if object is parented
- * to vertex of a dynamic paint canvas */
+ /* Skip sub-frame if object is parented to vertex of a dynamic paint canvas. */
if (no_update && (ELEM(ob->partype, PARVERT1, PARVERT3))) {
return false;
}
@@ -5481,8 +5480,7 @@ bool BKE_object_modifier_update_subframe(Depsgraph *depsgraph,
if (update_mesh) {
BKE_animsys_evaluate_animdata(
&ob->id, ob->adt, &anim_eval_context, ADT_RECALC_ANIM, flush_to_original);
- /* ignore cache clear during subframe updates
- * to not mess up cache validity */
+ /* Ignore cache clear during sub-frame updates to not mess up cache validity. */
object_cacheIgnoreClear(ob, 1);
BKE_object_handle_update(depsgraph, scene, ob);
object_cacheIgnoreClear(ob, 0);
diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c
index 1fe5d7aa0e7..a72d68710ed 100644
--- a/source/blender/blenkernel/intern/object_deform.c
+++ b/source/blender/blenkernel/intern/object_deform.c
@@ -163,14 +163,14 @@ bool BKE_object_defgroup_clear(Object *ob, bDeformGroup *dg, const bool use_sele
}
else {
if (BKE_mesh_deform_verts(me)) {
- const MVert *mv;
+ const bool *select_vert = (const bool *)CustomData_get_layer_named(
+ &me->vdata, CD_PROP_BOOL, ".select_vert");
int i;
- mv = BKE_mesh_verts(me);
dv = BKE_mesh_deform_verts_for_write(me);
- for (i = 0; i < me->totvert; i++, mv++, dv++) {
- if (dv->dw && (!use_selection || (mv->flag & SELECT))) {
+ for (i = 0; i < me->totvert; i++, dv++) {
+ if (dv->dw && (!use_selection || (select_vert && select_vert[i]))) {
MDeformWeight *dw = BKE_defvert_find_index(dv, def_nr);
BKE_defvert_remove_group(dv, dw); /* dw can be NULL */
changed = true;
diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc
index 6db1c864918..dde3130a5b0 100644
--- a/source/blender/blenkernel/intern/object_dupli.cc
+++ b/source/blender/blenkernel/intern/object_dupli.cc
@@ -311,12 +311,13 @@ static void make_child_duplis(const DupliContext *ctx,
/* FIXME: using a mere counter to generate a 'persistent' dupli id is very weak. One possible
* better solution could be to use `session_uuid` of ID's instead? */
int persistent_dupli_id = 0;
+ DEGObjectIterSettings deg_iter_settings{};
+ deg_iter_settings.depsgraph = ctx->depsgraph;
/* NOTE: this set of flags ensure we only iterate over objects that have a base in either the
* current scene, or the set (background) scene. */
- int deg_objects_visibility_flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
- DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
-
- DEG_OBJECT_ITER_BEGIN (ctx->depsgraph, ob, deg_objects_visibility_flags) {
+ deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
+ DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, ob) {
if ((ob != ctx->obedit) && is_child(ob, parent)) {
DupliContext pctx;
if (copy_dupli_context(&pctx, ctx, ctx->object, nullptr, persistent_dupli_id)) {
diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc
index ea1bd3c1cc3..171a7b41373 100644
--- a/source/blender/blenkernel/intern/paint.cc
+++ b/source/blender/blenkernel/intern/paint.cc
@@ -25,6 +25,7 @@
#include "BLI_hash.h"
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
+#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
@@ -65,6 +66,16 @@
#include "bmesh.h"
+static void sculpt_attribute_update_refs(Object *ob);
+static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name,
+ const SculptAttributeParams *params,
+ PBVHType pbvhtype,
+ bool flat_array_for_bmesh);
+void sculptsession_bmesh_add_layers(Object *ob);
+
using blender::MutableSpan;
using blender::Span;
@@ -1304,13 +1315,22 @@ void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, f
}
}
+static bool paint_rake_rotation_active(const MTex &mtex)
+{
+ return mtex.tex && mtex.brush_angle_mode & MTEX_ANGLE_RAKE;
+}
+
+static bool paint_rake_rotation_active(const Brush &brush)
+{
+ return paint_rake_rotation_active(brush.mtex) || paint_rake_rotation_active(brush.mask_mtex);
+}
+
bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups,
Brush *brush,
const float mouse_pos[2])
{
bool ok = false;
- if ((brush->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) ||
- (brush->mask_mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
+ if (paint_rake_rotation_active(*brush)) {
const float r = RAKE_THRESHHOLD;
float rotation;
@@ -1430,13 +1450,9 @@ static void sculptsession_free_pbvh(Object *object)
MEM_SAFE_FREE(ss->vemap);
MEM_SAFE_FREE(ss->vemap_mem);
- MEM_SAFE_FREE(ss->persistent_base);
-
MEM_SAFE_FREE(ss->preview_vert_list);
ss->preview_vert_count = 0;
- MEM_SAFE_FREE(ss->preview_vert_list);
-
MEM_SAFE_FREE(ss->vertex_info.connected_component);
MEM_SAFE_FREE(ss->vertex_info.boundary);
@@ -1470,6 +1486,8 @@ void BKE_sculptsession_free(Object *ob)
if (ob && ob->sculpt) {
SculptSession *ss = ob->sculpt;
+ BKE_sculpt_attribute_destroy_temporary_all(ob);
+
if (ss->bm) {
BKE_sculptsession_bm_to_me(ob, true);
BM_mesh_free(ss->bm);
@@ -1628,6 +1646,21 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
return false;
}
+/* Helper function to keep persistent base attribute references up to
+ * date. This is a bit more tricky since they persist across strokes.
+ */
+static void sculpt_update_persistent_base(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+
+ ss->attrs.persistent_co = BKE_sculpt_attribute_get(
+ ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, SCULPT_ATTRIBUTE_NAME(persistent_co));
+ ss->attrs.persistent_no = BKE_sculpt_attribute_get(
+ ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, SCULPT_ATTRIBUTE_NAME(persistent_no));
+ ss->attrs.persistent_disp = BKE_sculpt_attribute_get(
+ ob, ATTR_DOMAIN_POINT, CD_PROP_FLOAT, SCULPT_ATTRIBUTE_NAME(persistent_disp));
+}
+
static void sculpt_update_object(
Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool need_pmap, bool is_paint_tool)
{
@@ -1706,7 +1739,8 @@ static void sculpt_update_object(
/* Sculpt Face Sets. */
if (use_face_sets) {
- ss->face_sets = static_cast<int *>(CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS));
+ ss->face_sets = static_cast<int *>(
+ CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, ".sculpt_face_set"));
}
else {
ss->face_sets = nullptr;
@@ -1726,6 +1760,9 @@ static void sculpt_update_object(
BKE_pbvh_face_sets_color_set(ss->pbvh, me->face_sets_color_seed, me->face_sets_color_default);
+ sculpt_attribute_update_refs(ob);
+ sculpt_update_persistent_base(ob);
+
if (need_pmap && ob->type == OB_MESH && !ss->pmap) {
BKE_mesh_vert_poly_map_create(&ss->pmap,
&ss->pmap_mem,
@@ -1930,22 +1967,17 @@ int *BKE_sculpt_face_sets_ensure(Mesh *mesh)
{
using namespace blender;
using namespace blender::bke;
- if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) {
- return static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS));
+ MutableAttributeAccessor attributes = mesh->attributes_for_write();
+ if (!attributes.contains(".sculpt_face_set")) {
+ SpanAttributeWriter<int> face_sets = attributes.lookup_or_add_for_write_only_span<int>(
+ ".sculpt_face_set", ATTR_DOMAIN_FACE);
+ face_sets.span.fill(1);
+ mesh->face_sets_color_default = 1;
+ face_sets.finish();
}
- const AttributeAccessor attributes = mesh->attributes_for_write();
- const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
- ".hide_poly", ATTR_DOMAIN_FACE, false);
-
- MutableSpan<int> face_sets = {
- static_cast<int *>(CustomData_add_layer(
- &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly)),
- mesh->totpoly};
-
- face_sets.fill(1);
- mesh->face_sets_color_default = 1;
- return face_sets.data();
+ return static_cast<int *>(
+ CustomData_get_layer_named(&mesh->pdata, CD_PROP_INT32, ".sculpt_face_set"));
}
bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh)
@@ -2015,6 +2047,8 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
}
}
}
+ /* The evaluated multires CCG must be updated to contain the new data. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
ret |= SCULPT_MASK_LAYER_CALC_LOOP;
}
@@ -2022,6 +2056,8 @@ 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_SET_DEFAULT, nullptr, me->totvert);
+ /* The evaluated mesh must be updated to contain the new data. */
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
ret |= SCULPT_MASK_LAYER_CALC_VERT;
}
@@ -2119,13 +2155,16 @@ void BKE_sculpt_sync_face_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg)
static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
{
- PBVH *pbvh = BKE_pbvh_new();
+ PBVH *pbvh = ob->sculpt->pbvh = BKE_pbvh_new(PBVH_BMESH);
+
+ sculptsession_bmesh_add_layers(ob);
+
BKE_pbvh_build_bmesh(pbvh,
ob->sculpt->bm,
ob->sculpt->bm_smooth_shading,
ob->sculpt->bm_log,
- ob->sculpt->cd_vert_node_offset,
- ob->sculpt->cd_face_node_offset);
+ ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset,
+ ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset);
pbvh_show_mask_set(pbvh, ob->sculpt->show_mask);
pbvh_show_face_sets_set(pbvh, false);
return pbvh;
@@ -2135,7 +2174,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool
{
Mesh *me = BKE_object_get_original_mesh(ob);
const int looptris_num = poly_to_tri_count(me->totpoly, me->totloop);
- PBVH *pbvh = BKE_pbvh_new();
+ PBVH *pbvh = BKE_pbvh_new(PBVH_FACES);
BKE_pbvh_respect_hide_set(pbvh, respect_hide);
MutableSpan<MVert> verts = me->verts_for_write();
@@ -2178,7 +2217,7 @@ static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg, bool respect
{
CCGKey key;
BKE_subdiv_ccg_key_top_level(&key, subdiv_ccg);
- PBVH *pbvh = BKE_pbvh_new();
+ PBVH *pbvh = BKE_pbvh_new(PBVH_GRIDS);
BKE_pbvh_respect_hide_set(pbvh, respect_hide);
Mesh *base_mesh = BKE_mesh_from_object(ob);
@@ -2288,3 +2327,558 @@ void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uc
&rgba[2]);
rgba_float_to_uchar(r_color, rgba);
}
+
+int BKE_sculptsession_vertex_count(const SculptSession *ss)
+{
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_FACES:
+ return ss->totvert;
+ case PBVH_BMESH:
+ return BM_mesh_elem_count(ss->bm, BM_VERT);
+ case PBVH_GRIDS:
+ return BKE_pbvh_get_grid_num_verts(ss->pbvh);
+ }
+
+ return 0;
+}
+
+/** Returns pointer to a CustomData associated with a given domain, if
+ * one exists. If not nullptr is returned (this may happen with e.g.
+ * multires and ATTR_DOMAIN_POINT).
+ */
+static CustomData *sculpt_get_cdata(Object *ob, eAttrDomain domain)
+{
+ SculptSession *ss = ob->sculpt;
+
+ if (ss->bm) {
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return &ss->bm->vdata;
+ case ATTR_DOMAIN_FACE:
+ return &ss->bm->pdata;
+ default:
+ BLI_assert_unreachable();
+ return NULL;
+ }
+ }
+ else {
+ Mesh *me = BKE_object_get_original_mesh(ob);
+
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ /* Cannot get vertex domain for multires grids. */
+ if (ss->pbvh && BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) {
+ return nullptr;
+ }
+
+ return &me->vdata;
+ case ATTR_DOMAIN_FACE:
+ return &me->pdata;
+ default:
+ BLI_assert_unreachable();
+ return NULL;
+ }
+ }
+}
+
+static int sculpt_attr_elem_count_get(Object *ob, eAttrDomain domain)
+{
+ SculptSession *ss = ob->sculpt;
+
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ return BKE_sculptsession_vertex_count(ss);
+ break;
+ case ATTR_DOMAIN_FACE:
+ return ss->totfaces;
+ break;
+ default:
+ BLI_assert_unreachable();
+ return 0;
+ }
+}
+
+static bool sculpt_attribute_create(SculptSession *ss,
+ Object *ob,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name,
+ SculptAttribute *out,
+ const SculptAttributeParams *params,
+ PBVHType pbvhtype,
+ bool flat_array_for_bmesh)
+{
+ Mesh *me = BKE_object_get_original_mesh(ob);
+
+ bool simple_array = params->simple_array;
+ bool permanent = params->permanent;
+
+ out->params = *params;
+ out->proptype = proptype;
+ out->domain = domain;
+ BLI_strncpy_utf8(out->name, name, sizeof(out->name));
+
+ /* Force non-CustomData simple_array mode if not PBVH_FACES. */
+ if (pbvhtype == PBVH_GRIDS || (pbvhtype == PBVH_BMESH && flat_array_for_bmesh)) {
+ if (permanent) {
+ printf(
+ "%s: error: tried to make permanent customdata in multires or bmesh mode; will make "
+ "local "
+ "array "
+ "instead.\n",
+ __func__);
+ permanent = (out->params.permanent = false);
+ }
+
+ simple_array = (out->params.simple_array = true);
+ }
+
+ BLI_assert(!(simple_array && permanent));
+
+ int totelem = sculpt_attr_elem_count_get(ob, domain);
+
+ if (simple_array) {
+ int elemsize = CustomData_sizeof(proptype);
+
+ out->data = MEM_calloc_arrayN(totelem, elemsize, __func__);
+
+ out->data_for_bmesh = ss->bm != NULL;
+ out->bmesh_cd_offset = -1;
+ out->layer = NULL;
+ out->elem_size = elemsize;
+ out->used = true;
+ out->elem_num = totelem;
+
+ return true;
+ }
+
+ switch (BKE_pbvh_type(ss->pbvh)) {
+ case PBVH_BMESH: {
+ CustomData *cdata = NULL;
+ out->data_for_bmesh = true;
+
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ cdata = &ss->bm->vdata;
+ break;
+ case ATTR_DOMAIN_FACE:
+ cdata = &ss->bm->pdata;
+ break;
+ default:
+ out->used = false;
+ return false;
+ }
+
+ BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1);
+
+ BM_data_layer_add_named(ss->bm, cdata, proptype, name);
+ int index = CustomData_get_named_layer_index(cdata, proptype, name);
+
+ if (!permanent) {
+ cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY;
+ }
+
+ out->data = NULL;
+ out->layer = cdata->layers + index;
+ out->bmesh_cd_offset = out->layer->offset;
+ out->elem_size = CustomData_sizeof(proptype);
+ break;
+ }
+ case PBVH_FACES: {
+ CustomData *cdata = NULL;
+
+ out->data_for_bmesh = false;
+
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ cdata = &me->vdata;
+ break;
+ case ATTR_DOMAIN_FACE:
+ cdata = &me->pdata;
+ break;
+ default:
+ out->used = false;
+ return false;
+ }
+
+ BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1);
+
+ CustomData_add_layer_named(cdata, proptype, CD_SET_DEFAULT, NULL, totelem, name);
+ int index = CustomData_get_named_layer_index(cdata, proptype, name);
+
+ if (!permanent) {
+ cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY;
+ }
+
+ out->data = NULL;
+ out->layer = cdata->layers + index;
+ out->bmesh_cd_offset = -1;
+ out->data = out->layer->data;
+ out->elem_size = CustomData_get_elem_size(out->layer);
+
+ break;
+ }
+ case PBVH_GRIDS: {
+ /* GRIDS should have been handled as simple arrays. */
+ BLI_assert_unreachable();
+ break;
+ }
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ out->used = true;
+ out->elem_num = totelem;
+
+ return true;
+}
+
+static bool sculpt_attr_update(Object *ob, SculptAttribute *attr)
+{
+ SculptSession *ss = ob->sculpt;
+ int elem_num = sculpt_attr_elem_count_get(ob, attr->domain);
+
+ bool bad = false;
+
+ if (attr->params.simple_array) {
+ bad = attr->elem_num != elem_num;
+
+ if (bad) {
+ MEM_SAFE_FREE(attr->data);
+ }
+ }
+ else {
+ CustomData *cdata = sculpt_get_cdata(ob, attr->domain);
+
+ if (cdata) {
+ int layer_index = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name);
+ bad = layer_index == -1;
+
+ if (ss->bm) {
+ attr->bmesh_cd_offset = cdata->layers[layer_index].offset;
+ }
+ }
+ }
+
+ if (bad) {
+ sculpt_attribute_create(ss,
+ ob,
+ attr->domain,
+ attr->proptype,
+ attr->name,
+ attr,
+ &attr->params,
+ BKE_pbvh_type(ss->pbvh),
+ true);
+ }
+
+ return bad;
+}
+
+static SculptAttribute *sculpt_get_cached_layer(SculptSession *ss,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name)
+{
+ for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) {
+ SculptAttribute *attr = ss->temp_attributes + i;
+
+ if (attr->used && STREQ(attr->name, name) && attr->proptype == proptype &&
+ attr->domain == domain) {
+
+ return attr;
+ }
+ }
+
+ return NULL;
+}
+
+bool BKE_sculpt_attribute_exists(Object *ob,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name)
+{
+ SculptSession *ss = ob->sculpt;
+ SculptAttribute *attr = sculpt_get_cached_layer(ss, domain, proptype, name);
+
+ if (attr) {
+ return true;
+ }
+
+ CustomData *cdata = sculpt_get_cdata(ob, domain);
+ return CustomData_get_named_layer_index(cdata, proptype, name) != -1;
+
+ return false;
+}
+
+static SculptAttribute *sculpt_alloc_attr(SculptSession *ss)
+{
+ for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) {
+ if (!ss->temp_attributes[i].used) {
+ memset((void *)(ss->temp_attributes + i), 0, sizeof(SculptAttribute));
+ ss->temp_attributes[i].used = true;
+
+ return ss->temp_attributes + i;
+ }
+ }
+
+ BLI_assert_unreachable();
+ return NULL;
+}
+
+SculptAttribute *BKE_sculpt_attribute_get(struct Object *ob,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name)
+{
+ SculptSession *ss = ob->sculpt;
+
+ /* See if attribute is cached in ss->temp_attributes. */
+ SculptAttribute *attr = sculpt_get_cached_layer(ss, domain, proptype, name);
+
+ if (attr) {
+ if (sculpt_attr_update(ob, attr)) {
+ sculpt_attribute_update_refs(ob);
+ }
+
+ return attr;
+ }
+
+ /* Does attribute exist in CustomData layout? */
+ CustomData *cdata = sculpt_get_cdata(ob, domain);
+ if (cdata) {
+ int index = CustomData_get_named_layer_index(cdata, proptype, name);
+
+ if (index != -1) {
+ int totelem = 0;
+
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ totelem = BKE_sculptsession_vertex_count(ss);
+ break;
+ case ATTR_DOMAIN_FACE:
+ totelem = ss->totfaces;
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ attr = sculpt_alloc_attr(ss);
+
+ attr->used = true;
+ attr->proptype = proptype;
+ attr->data = cdata->layers[index].data;
+ attr->bmesh_cd_offset = cdata->layers[index].offset;
+ attr->elem_num = totelem;
+ attr->layer = cdata->layers + index;
+ attr->elem_size = CustomData_get_elem_size(attr->layer);
+
+ BLI_strncpy_utf8(attr->name, name, sizeof(attr->name));
+ return attr;
+ }
+ }
+
+ return NULL;
+}
+
+static SculptAttribute *sculpt_attribute_ensure_ex(Object *ob,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name,
+ const SculptAttributeParams *params,
+ PBVHType pbvhtype,
+ bool flat_array_for_bmesh)
+{
+ SculptSession *ss = ob->sculpt;
+ SculptAttribute *attr = BKE_sculpt_attribute_get(ob, domain, proptype, name);
+
+ if (attr) {
+ return attr;
+ }
+
+ attr = sculpt_alloc_attr(ss);
+
+ /* Create attribute. */
+ sculpt_attribute_create(
+ ss, ob, domain, proptype, name, attr, params, pbvhtype, flat_array_for_bmesh);
+ sculpt_attribute_update_refs(ob);
+
+ return attr;
+}
+
+SculptAttribute *BKE_sculpt_attribute_ensure(Object *ob,
+ eAttrDomain domain,
+ eCustomDataType proptype,
+ const char *name,
+ const SculptAttributeParams *params)
+{
+ SculptAttributeParams temp_params = *params;
+
+ return sculpt_attribute_ensure_ex(
+ ob, domain, proptype, name, &temp_params, BKE_pbvh_type(ob->sculpt->pbvh), true);
+}
+
+static void sculptsession_bmesh_attr_update_internal(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+
+ sculptsession_bmesh_add_layers(ob);
+
+ if (ss->pbvh) {
+ BKE_pbvh_update_bmesh_offsets(ss->pbvh,
+ ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset,
+ ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset);
+ }
+}
+
+void sculptsession_bmesh_add_layers(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+ SculptAttributeParams params = {0};
+
+ ss->attrs.dyntopo_node_id_vertex = sculpt_attribute_ensure_ex(
+ ob,
+ ATTR_DOMAIN_POINT,
+ CD_PROP_INT32,
+ SCULPT_ATTRIBUTE_NAME(dyntopo_node_id_vertex),
+ &params,
+ PBVH_BMESH,
+ false);
+
+ ss->attrs.dyntopo_node_id_face = sculpt_attribute_ensure_ex(
+ ob,
+ ATTR_DOMAIN_FACE,
+ CD_PROP_INT32,
+ SCULPT_ATTRIBUTE_NAME(dyntopo_node_id_face),
+ &params,
+ PBVH_BMESH,
+ false);
+}
+
+void BKE_sculpt_attributes_destroy_temporary_stroke(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+
+ for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) {
+ SculptAttribute *attr = ss->temp_attributes + i;
+
+ if (attr->params.stroke_only) {
+ BKE_sculpt_attribute_destroy(ob, attr);
+ }
+ }
+}
+
+static void sculpt_attribute_update_refs(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+
+ /* run twice, in case sculpt_attr_update had to recreate a layer and
+ messed up the bmesh offsets. */
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < SCULPT_MAX_ATTRIBUTES; j++) {
+ SculptAttribute *attr = ss->temp_attributes + j;
+
+ if (attr->used) {
+ sculpt_attr_update(ob, attr);
+ }
+ }
+
+ if (ss->bm) {
+ sculptsession_bmesh_attr_update_internal(ob);
+ }
+ }
+
+ Mesh *me = BKE_object_get_original_mesh(ob);
+
+ if (ss->pbvh) {
+ BKE_pbvh_update_active_vcol(ss->pbvh, me);
+ }
+}
+
+void BKE_sculpt_attribute_destroy_temporary_all(Object *ob)
+{
+ SculptSession *ss = ob->sculpt;
+
+ for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) {
+ SculptAttribute *attr = ss->temp_attributes + i;
+
+ if (attr->used && !attr->params.permanent) {
+ BKE_sculpt_attribute_destroy(ob, attr);
+ }
+ }
+}
+
+bool BKE_sculpt_attribute_destroy(Object *ob, SculptAttribute *attr)
+{
+ SculptSession *ss = ob->sculpt;
+ eAttrDomain domain = attr->domain;
+
+ BLI_assert(attr->used);
+
+ /* Remove from convenience pointer struct. */
+ SculptAttribute **ptrs = (SculptAttribute **)&ss->attrs;
+ int ptrs_num = sizeof(ss->attrs) / sizeof(void *);
+
+ for (int i = 0; i < ptrs_num; i++) {
+ if (ptrs[i] == attr) {
+ ptrs[i] = NULL;
+ }
+ }
+
+ /* Remove from internal temp_attributes array. */
+ for (int i = 0; i < SCULPT_MAX_ATTRIBUTES; i++) {
+ SculptAttribute *attr2 = ss->temp_attributes + i;
+
+ if (STREQ(attr2->name, attr->name) && attr2->domain == attr->domain &&
+ attr2->proptype == attr->proptype) {
+
+ attr2->used = false;
+ }
+ }
+
+ Mesh *me = BKE_object_get_original_mesh(ob);
+
+ if (attr->params.simple_array) {
+ MEM_SAFE_FREE(attr->data);
+ }
+ else if (ss->bm) {
+ CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &ss->bm->vdata : &ss->bm->pdata;
+
+ BM_data_layer_free_named(ss->bm, cdata, attr->name);
+ }
+ else {
+ CustomData *cdata = NULL;
+ int totelem = 0;
+
+ switch (domain) {
+ case ATTR_DOMAIN_POINT:
+ cdata = ss->bm ? &ss->bm->vdata : &me->vdata;
+ totelem = ss->totvert;
+ break;
+ case ATTR_DOMAIN_FACE:
+ cdata = ss->bm ? &ss->bm->pdata : &me->pdata;
+ totelem = ss->totfaces;
+ break;
+ default:
+ BLI_assert_unreachable();
+ return false;
+ }
+
+ /* We may have been called after destroying ss->bm in which case attr->layer
+ * might be invalid.
+ */
+ int layer_i = CustomData_get_named_layer_index(cdata, attr->proptype, attr->name);
+ if (layer_i != 0) {
+ CustomData_free_layer(cdata, attr->proptype, totelem, layer_i);
+ }
+
+ sculpt_attribute_update_refs(ob);
+ }
+
+ attr->data = NULL;
+ attr->used = false;
+
+ return true;
+}
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index ed1d93647ce..561043b553e 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -453,7 +453,7 @@ static int distribute_binary_search(const float *sum, int n, float value)
return low;
}
-/* the max number if calls to rng_* funcs within psys_thread_distribute_particle
+/* the max number if calls to rng_* functions within psys_thread_distribute_particle
* be sure to keep up to date if this changes */
#define PSYS_RND_DIST_SKIP 3
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 991a0863235..b6f792812a8 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -705,11 +705,12 @@ void BKE_pbvh_build_grids(PBVH *pbvh,
MEM_freeN(prim_bbc);
}
-PBVH *BKE_pbvh_new(void)
+PBVH *BKE_pbvh_new(PBVHType type)
{
PBVH *pbvh = MEM_callocN(sizeof(PBVH), "pbvh");
pbvh->respect_hide = true;
pbvh->draw_cache_invalid = true;
+ pbvh->header.type = type;
return pbvh;
}
@@ -3104,9 +3105,9 @@ bool pbvh_has_face_sets(PBVH *pbvh)
{
switch (pbvh->header.type) {
case PBVH_GRIDS:
- return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS));
case PBVH_FACES:
- return (pbvh->pdata && CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS));
+ return pbvh->pdata &&
+ CustomData_get_layer_named(pbvh->pdata, CD_PROP_INT32, ".sculpt_face_set") != NULL;
case PBVH_BMESH:
return false;
}
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 9240f8cb80f..502a71a9719 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -1863,6 +1863,12 @@ static void pbvh_bmesh_create_nodes_fast_recursive(
/***************************** Public API *****************************/
+void BKE_pbvh_update_bmesh_offsets(PBVH *pbvh, int cd_vert_node_offset, int cd_face_node_offset)
+{
+ pbvh->cd_vert_node_offset = cd_vert_node_offset;
+ pbvh->cd_face_node_offset = cd_face_node_offset;
+}
+
void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMesh *bm,
bool smooth_shading,
@@ -1870,8 +1876,6 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
const int cd_vert_node_offset,
const int cd_face_node_offset)
{
- pbvh->cd_vert_node_offset = cd_vert_node_offset;
- pbvh->cd_face_node_offset = cd_face_node_offset;
pbvh->header.bm = bm;
BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75);
@@ -1882,6 +1886,8 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
/* TODO: choose leaf limit better */
pbvh->leaf_limit = 100;
+ BKE_pbvh_update_bmesh_offsets(pbvh, cd_vert_node_offset, cd_face_node_offset);
+
if (smooth_shading) {
pbvh->flags |= PBVH_DYNTOPO_SMOOTH_SHADING;
}
@@ -1999,7 +2005,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
BLI_mempool_destroy(queue_pool);
}
- /* Unmark nodes */
+ /* Unmark nodes. */
for (int n = 0; n < pbvh->totnode; n++) {
PBVHNode *node = &pbvh->nodes[n];
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 6adb728b515..2705241425b 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -1545,7 +1545,7 @@ void BKE_rigidbody_remove_object(Main *bmain, Scene *scene, Object *ob, const bo
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
- /* Relying on usercount of the object should be OK, and it is much cheaper than looping in all
+ /* Relying on user-count of the object should be OK, and it is much cheaper than looping in all
* collections to check whether the object is already in another one... */
if (ID_REAL_USERS(&ob->id) == 1) {
/* Some users seems to find it funny to use a view-layer instancing collection
diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc
index db950492f69..bf1b1586db8 100644
--- a/source/blender/blenkernel/intern/scene.cc
+++ b/source/blender/blenkernel/intern/scene.cc
@@ -235,7 +235,7 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
{
Scene *scene_dst = (Scene *)id_dst;
const Scene *scene_src = (const Scene *)id_src;
- /* We never handle usercount here for own data. */
+ /* We never handle user-count here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
/* We always need allocation of our private ID data. */
const int flag_private_id_data = flag & ~LIB_ID_CREATE_NO_ALLOCATE;
@@ -1228,7 +1228,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
}
/* Active channels root pointer. */
- if (ed->displayed_channels == old_displayed_channels || ed->displayed_channels == nullptr) {
+ if (ELEM(ed->displayed_channels, old_displayed_channels, nullptr)) {
ed->displayed_channels = &ed->channels;
}
else {
@@ -1263,7 +1263,7 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id)
}
}
- if (ms->old_channels == old_displayed_channels || ms->old_channels == nullptr) {
+ if (ELEM(ms->old_channels, old_displayed_channels, nullptr)) {
ms->old_channels = &ed->channels;
}
else {
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 40348824a13..03f0c3ff1e9 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -305,7 +305,7 @@ IDTypeInfo IDType_ID_SCR = {
.lib_override_apply_post = NULL,
};
-/* ************ Spacetype/regiontype handling ************** */
+/* ************ Space-type/region-type handling ************** */
/* keep global; this has to be accessible outside of windowmanager */
static ListBase spacetypes = {NULL, NULL};
@@ -1662,7 +1662,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area)
LISTBASE_FOREACH_MUTABLE (ConsoleLine *, cl, &sconsole->history) {
BLO_read_data_address(reader, &cl->line);
if (cl->line) {
- /* the allocted length is not written, so reset here */
+ /* The allocated length is not written, so reset here. */
cl->len_alloc = cl->len + 1;
}
else {
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index de1d0d3c30e..6e23ca0e89f 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -1155,11 +1155,12 @@ void BKE_sound_update_scene(Depsgraph *depsgraph, Scene *scene)
/* cheap test to skip looping over all objects (no speakers is a common case) */
if (DEG_id_type_any_exists(depsgraph, ID_SPK)) {
- DEG_OBJECT_ITER_BEGIN (depsgraph,
- object,
- (DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
- DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY |
- DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET)) {
+ DEGObjectIterSettings deg_iter_settings = {0};
+ deg_iter_settings.depsgraph = depsgraph;
+ deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET;
+ DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, object) {
sound_update_base(scene, object, new_set);
}
DEG_OBJECT_ITER_END;
diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc
deleted file mode 100644
index a674bf7800a..00000000000
--- a/source/blender/blenkernel/intern/spline_base.cc
+++ /dev/null
@@ -1,526 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_array.hh"
-#include "BLI_generic_virtual_array.hh"
-#include "BLI_span.hh"
-#include "BLI_task.hh"
-#include "BLI_timeit.hh"
-
-#include "BKE_attribute_math.hh"
-#include "BKE_spline.hh"
-
-using blender::Array;
-using blender::float3;
-using blender::GMutableSpan;
-using blender::GSpan;
-using blender::GVArray;
-using blender::IndexRange;
-using blender::MutableSpan;
-using blender::Span;
-using blender::VArray;
-using blender::attribute_math::convert_to_static_type;
-using blender::bke::AttributeIDRef;
-using blender::bke::AttributeMetaData;
-
-CurveType Spline::type() const
-{
- return type_;
-}
-
-void Spline::copy_base_settings(const Spline &src, Spline &dst)
-{
- dst.normal_mode = src.normal_mode;
- dst.is_cyclic_ = src.is_cyclic_;
-}
-
-static SplinePtr create_spline(const CurveType type)
-{
- switch (type) {
- case CURVE_TYPE_POLY:
- return std::make_unique<PolySpline>();
- case CURVE_TYPE_BEZIER:
- return std::make_unique<BezierSpline>();
- case CURVE_TYPE_NURBS:
- return std::make_unique<NURBSpline>();
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
- return {};
- }
- BLI_assert_unreachable();
- return {};
-}
-
-SplinePtr Spline::copy() const
-{
- SplinePtr dst = this->copy_without_attributes();
- dst->attributes = this->attributes;
- return dst;
-}
-
-SplinePtr Spline::copy_only_settings() const
-{
- SplinePtr dst = create_spline(type_);
- this->copy_base_settings(*this, *dst);
- this->copy_settings(*dst);
- return dst;
-}
-
-SplinePtr Spline::copy_without_attributes() const
-{
- SplinePtr dst = this->copy_only_settings();
- this->copy_data(*dst);
-
- /* Though the attributes storage is empty, it still needs to know the correct size. */
- dst->attributes.reallocate(dst->size());
- return dst;
-}
-
-void Spline::translate(const blender::float3 &translation)
-{
- for (float3 &position : this->positions()) {
- position += translation;
- }
- this->mark_cache_invalid();
-}
-
-void Spline::transform(const blender::float4x4 &matrix)
-{
- for (float3 &position : this->positions()) {
- position = matrix * position;
- }
- this->mark_cache_invalid();
-}
-
-void Spline::reverse()
-{
- this->positions().reverse();
- this->radii().reverse();
- this->tilts().reverse();
-
- this->attributes.foreach_attribute(
- [&](const AttributeIDRef &id, const AttributeMetaData &meta_data) {
- std::optional<blender::GMutableSpan> attribute = this->attributes.get_for_write(id);
- if (!attribute) {
- BLI_assert_unreachable();
- return false;
- }
- convert_to_static_type(meta_data.data_type, [&](auto dummy) {
- using T = decltype(dummy);
- attribute->typed<T>().reverse();
- });
- return true;
- },
- ATTR_DOMAIN_POINT);
-
- this->reverse_impl();
- this->mark_cache_invalid();
-}
-
-int Spline::evaluated_edges_num() const
-{
- const int eval_num = this->evaluated_points_num();
- if (eval_num < 2) {
- /* Two points are required for an edge. */
- return 0;
- }
-
- return this->is_cyclic_ ? eval_num : eval_num - 1;
-}
-
-float Spline::length() const
-{
- Span<float> lengths = this->evaluated_lengths();
- return lengths.is_empty() ? 0.0f : this->evaluated_lengths().last();
-}
-
-int Spline::segments_num() const
-{
- const int num = this->size();
-
- return is_cyclic_ ? num : num - 1;
-}
-
-bool Spline::is_cyclic() const
-{
- return is_cyclic_;
-}
-
-void Spline::set_cyclic(const bool value)
-{
- is_cyclic_ = value;
-}
-
-static void accumulate_lengths(Span<float3> positions,
- const bool is_cyclic,
- MutableSpan<float> lengths)
-{
- using namespace blender::math;
-
- float length = 0.0f;
- for (const int i : IndexRange(positions.size() - 1)) {
- length += distance(positions[i], positions[i + 1]);
- lengths[i] = length;
- }
- if (is_cyclic) {
- lengths.last() = length + distance(positions.last(), positions.first());
- }
-}
-
-Span<float> Spline::evaluated_lengths() const
-{
- if (!length_cache_dirty_) {
- return evaluated_lengths_cache_;
- }
-
- std::lock_guard lock{length_cache_mutex_};
- if (!length_cache_dirty_) {
- return evaluated_lengths_cache_;
- }
-
- const int total = evaluated_edges_num();
- evaluated_lengths_cache_.resize(total);
- if (total != 0) {
- Span<float3> positions = this->evaluated_positions();
- accumulate_lengths(positions, is_cyclic_, evaluated_lengths_cache_);
- }
-
- length_cache_dirty_ = false;
- return evaluated_lengths_cache_;
-}
-
-static float3 direction_bisect(const float3 &prev, const float3 &middle, const float3 &next)
-{
- using namespace blender::math;
-
- const float3 dir_prev = normalize(middle - prev);
- const float3 dir_next = normalize(next - middle);
-
- const float3 result = normalize(dir_prev + dir_next);
- if (UNLIKELY(is_zero(result))) {
- return float3(0.0f, 0.0f, 1.0f);
- }
- return result;
-}
-
-static void calculate_tangents(Span<float3> positions,
- const bool is_cyclic,
- MutableSpan<float3> tangents)
-{
- using namespace blender::math;
-
- if (positions.size() == 1) {
- tangents.first() = float3(0.0f, 0.0f, 1.0f);
- return;
- }
-
- for (const int i : IndexRange(1, positions.size() - 2)) {
- tangents[i] = direction_bisect(positions[i - 1], positions[i], positions[i + 1]);
- }
-
- if (is_cyclic) {
- const float3 &second_to_last = positions[positions.size() - 2];
- const float3 &last = positions.last();
- const float3 &first = positions.first();
- const float3 &second = positions[1];
- tangents.first() = direction_bisect(last, first, second);
- tangents.last() = direction_bisect(second_to_last, last, first);
- }
- else {
- tangents.first() = normalize(positions[1] - positions[0]);
- tangents.last() = normalize(positions.last() - positions[positions.size() - 2]);
- }
-}
-
-Span<float3> Spline::evaluated_tangents() const
-{
- if (!tangent_cache_dirty_) {
- return evaluated_tangents_cache_;
- }
-
- std::lock_guard lock{tangent_cache_mutex_};
- if (!tangent_cache_dirty_) {
- return evaluated_tangents_cache_;
- }
-
- const int eval_num = this->evaluated_points_num();
- evaluated_tangents_cache_.resize(eval_num);
-
- Span<float3> positions = this->evaluated_positions();
-
- calculate_tangents(positions, is_cyclic_, evaluated_tangents_cache_);
- this->correct_end_tangents();
-
- tangent_cache_dirty_ = false;
- return evaluated_tangents_cache_;
-}
-
-static float3 rotate_direction_around_axis(const float3 &direction,
- const float3 &axis,
- const float angle)
-{
- using namespace blender::math;
-
- BLI_ASSERT_UNIT_V3(direction);
- BLI_ASSERT_UNIT_V3(axis);
-
- const float3 axis_scaled = axis * dot(direction, axis);
- const float3 diff = direction - axis_scaled;
- const float3 cross = blender::math::cross(axis, diff);
-
- return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
-}
-
-static void calculate_normals_z_up(Span<float3> tangents, MutableSpan<float3> r_normals)
-{
- using namespace blender::math;
-
- BLI_assert(r_normals.size() == tangents.size());
-
- /* Same as in `vec_to_quat`. */
- const float epsilon = 1e-4f;
- for (const int i : r_normals.index_range()) {
- const float3 &tangent = tangents[i];
- if (fabsf(tangent.x) + fabsf(tangent.y) < epsilon) {
- r_normals[i] = {1.0f, 0.0f, 0.0f};
- }
- else {
- r_normals[i] = normalize(float3(tangent.y, -tangent.x, 0.0f));
- }
- }
-}
-
-/**
- * Rotate the last normal in the same way the tangent has been rotated.
- */
-static float3 calculate_next_normal(const float3 &last_normal,
- const float3 &last_tangent,
- const float3 &current_tangent)
-{
- using namespace blender::math;
-
- if (is_zero(last_tangent) || is_zero(current_tangent)) {
- return last_normal;
- }
- const float angle = angle_normalized_v3v3(last_tangent, current_tangent);
- if (angle != 0.0) {
- const float3 axis = normalize(cross(last_tangent, current_tangent));
- return rotate_direction_around_axis(last_normal, axis, angle);
- }
- return last_normal;
-}
-
-static void calculate_normals_minimum(Span<float3> tangents,
- const bool cyclic,
- MutableSpan<float3> r_normals)
-{
- using namespace blender::math;
- BLI_assert(r_normals.size() == tangents.size());
-
- if (r_normals.is_empty()) {
- return;
- }
-
- const float epsilon = 1e-4f;
-
- /* Set initial normal. */
- const float3 &first_tangent = tangents[0];
- if (fabs(first_tangent.x) + fabs(first_tangent.y) < epsilon) {
- r_normals[0] = {1.0f, 0.0f, 0.0f};
- }
- else {
- r_normals[0] = normalize(float3(first_tangent.y, -first_tangent.x, 0.0f));
- }
-
- /* Forward normal with minimum twist along the entire spline. */
- for (const int i : IndexRange(1, r_normals.size() - 1)) {
- r_normals[i] = calculate_next_normal(r_normals[i - 1], tangents[i - 1], tangents[i]);
- }
-
- if (!cyclic) {
- return;
- }
-
- /* Compute how much the first normal deviates from the normal that has been forwarded along the
- * entire cyclic spline. */
- const float3 uncorrected_last_normal = calculate_next_normal(
- r_normals.last(), tangents.last(), tangents[0]);
- float correction_angle = angle_signed_on_axis_v3v3_v3(
- r_normals[0], uncorrected_last_normal, tangents[0]);
- if (correction_angle > M_PI) {
- correction_angle = correction_angle - 2 * M_PI;
- }
-
- /* Gradually apply correction by rotating all normals slightly. */
- const float angle_step = correction_angle / r_normals.size();
- for (const int i : r_normals.index_range()) {
- const float angle = angle_step * i;
- r_normals[i] = rotate_direction_around_axis(r_normals[i], tangents[i], angle);
- }
-}
-
-Span<float3> Spline::evaluated_normals() const
-{
- if (!normal_cache_dirty_) {
- return evaluated_normals_cache_;
- }
-
- std::lock_guard lock{normal_cache_mutex_};
- if (!normal_cache_dirty_) {
- return evaluated_normals_cache_;
- }
-
- const int eval_num = this->evaluated_points_num();
- evaluated_normals_cache_.resize(eval_num);
-
- Span<float3> tangents = this->evaluated_tangents();
- MutableSpan<float3> normals = evaluated_normals_cache_;
-
- /* Only Z up normals are supported at the moment. */
- switch (this->normal_mode) {
- case NORMAL_MODE_Z_UP: {
- calculate_normals_z_up(tangents, normals);
- break;
- }
- case NORMAL_MODE_MINIMUM_TWIST: {
- calculate_normals_minimum(tangents, is_cyclic_, normals);
- break;
- }
- }
-
- /* Rotate the generated normals with the interpolated tilt data. */
- VArray<float> tilts = this->interpolate_to_evaluated(this->tilts());
- for (const int i : normals.index_range()) {
- normals[i] = rotate_direction_around_axis(normals[i], tangents[i], tilts[i]);
- }
-
- normal_cache_dirty_ = false;
- return evaluated_normals_cache_;
-}
-
-Spline::LookupResult Spline::lookup_evaluated_factor(const float factor) const
-{
- return this->lookup_evaluated_length(this->length() * factor);
-}
-
-Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
-{
- BLI_assert(length >= 0.0f && length <= this->length());
-
- Span<float> lengths = this->evaluated_lengths();
-
- const float *offset = std::lower_bound(lengths.begin(), lengths.end(), length);
- const int index = offset - lengths.begin();
- const int next_index = (index == this->evaluated_points_num() - 1) ? 0 : index + 1;
-
- const float previous_length = (index == 0) ? 0.0f : lengths[index - 1];
- const float length_in_segment = length - previous_length;
- const float segment_length = lengths[index] - previous_length;
- const float factor = segment_length == 0.0f ? 0.0f : length_in_segment / segment_length;
-
- return LookupResult{index, next_index, factor};
-}
-
-Array<float> Spline::sample_uniform_index_factors(const int samples_num) const
-{
- const Span<float> lengths = this->evaluated_lengths();
-
- BLI_assert(samples_num > 0);
- Array<float> samples(samples_num);
-
- samples[0] = 0.0f;
- if (samples_num == 1) {
- return samples;
- }
-
- const float total_length = this->length();
- const float sample_length = total_length / (samples_num - (is_cyclic_ ? 0 : 1));
-
- /* Store the length at the previous evaluated point in a variable so it can
- * start out at zero (the lengths array doesn't contain 0 for the first point). */
- float prev_length = 0.0f;
- int i_sample = 1;
- for (const int i_evaluated : IndexRange(this->evaluated_edges_num())) {
- const float length = lengths[i_evaluated];
-
- /* Add every sample that fits in this evaluated edge. */
- while ((sample_length * i_sample) < length && i_sample < samples_num) {
- const float factor = (sample_length * i_sample - prev_length) / (length - prev_length);
- samples[i_sample] = i_evaluated + factor;
- i_sample++;
- }
-
- prev_length = length;
- }
-
- /* Zero lengths or float inaccuracies can cause invalid values, or simply
- * skip some, so set the values that weren't completed in the main loop. */
- for (const int i : IndexRange(i_sample, samples_num - i_sample)) {
- samples[i] = float(samples_num);
- }
-
- if (!is_cyclic_) {
- /* In rare cases this can prevent overflow of the stored index. */
- samples.last() = lengths.size();
- }
-
- return samples;
-}
-
-Spline::LookupResult Spline::lookup_data_from_index_factor(const float index_factor) const
-{
- const int eval_num = this->evaluated_points_num();
-
- if (is_cyclic_) {
- if (index_factor < eval_num) {
- const int index = std::floor(index_factor);
- const int next_index = (index < eval_num - 1) ? index + 1 : 0;
- return LookupResult{index, next_index, index_factor - index};
- }
- return LookupResult{eval_num - 1, 0, 1.0f};
- }
-
- if (index_factor < eval_num - 1) {
- const int index = std::floor(index_factor);
- const int next_index = index + 1;
- return LookupResult{index, next_index, index_factor - index};
- }
- return LookupResult{eval_num - 2, eval_num - 1, 1.0f};
-}
-
-void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
-{
- Span<float3> positions = use_evaluated ? this->evaluated_positions() : this->positions();
- for (const float3 &position : positions) {
- minmax_v3v3_v3(min, max, position);
- }
-}
-
-GVArray Spline::interpolate_to_evaluated(GSpan data) const
-{
- return this->interpolate_to_evaluated(GVArray::ForSpan(data));
-}
-
-void Spline::sample_with_index_factors(const GVArray &src,
- Span<float> index_factors,
- GMutableSpan dst) const
-{
- BLI_assert(src.size() == this->evaluated_points_num());
-
- blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- const VArray<T> src_typed = src.typed<T>();
- MutableSpan<T> dst_typed = dst.typed<T>();
- if (src.size() == 1) {
- dst_typed.fill(src_typed[0]);
- return;
- }
- blender::threading::parallel_for(dst_typed.index_range(), 1024, [&](IndexRange range) {
- for (const int i : range) {
- const LookupResult interp = this->lookup_data_from_index_factor(index_factors[i]);
- dst_typed[i] = blender::attribute_math::mix2(interp.factor,
- src_typed[interp.evaluated_index],
- src_typed[interp.next_evaluated_index]);
- }
- });
- });
-}
diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc
deleted file mode 100644
index 80515d0ef37..00000000000
--- a/source/blender/blenkernel/intern/spline_bezier.cc
+++ /dev/null
@@ -1,646 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_array.hh"
-#include "BLI_span.hh"
-#include "BLI_task.hh"
-
-#include "BKE_spline.hh"
-
-using blender::Array;
-using blender::float3;
-using blender::GVArray;
-using blender::IndexRange;
-using blender::MutableSpan;
-using blender::Span;
-using blender::VArray;
-
-void BezierSpline::copy_settings(Spline &dst) const
-{
- BezierSpline &bezier = static_cast<BezierSpline &>(dst);
- bezier.resolution_ = resolution_;
-}
-
-void BezierSpline::copy_data(Spline &dst) const
-{
- BezierSpline &bezier = static_cast<BezierSpline &>(dst);
- bezier.positions_ = positions_;
- bezier.handle_types_left_ = handle_types_left_;
- bezier.handle_positions_left_ = handle_positions_left_;
- bezier.handle_types_right_ = handle_types_right_;
- bezier.handle_positions_right_ = handle_positions_right_;
- bezier.radii_ = radii_;
- bezier.tilts_ = tilts_;
-}
-
-int BezierSpline::size() const
-{
- const int size = positions_.size();
- BLI_assert(size == handle_types_left_.size());
- BLI_assert(size == handle_positions_left_.size());
- BLI_assert(size == handle_types_right_.size());
- BLI_assert(size == handle_positions_right_.size());
- BLI_assert(size == radii_.size());
- BLI_assert(size == tilts_.size());
- return size;
-}
-
-int BezierSpline::resolution() const
-{
- return resolution_;
-}
-
-void BezierSpline::set_resolution(const int value)
-{
- BLI_assert(value > 0);
- resolution_ = value;
- this->mark_cache_invalid();
-}
-
-void BezierSpline::resize(const int size)
-{
- handle_types_left_.resize(size);
- handle_positions_left_.resize(size);
- positions_.resize(size);
- handle_types_right_.resize(size);
- handle_positions_right_.resize(size);
- radii_.resize(size);
- tilts_.resize(size);
- this->mark_cache_invalid();
- attributes.reallocate(size);
-}
-
-MutableSpan<float3> BezierSpline::positions()
-{
- return positions_;
-}
-Span<float3> BezierSpline::positions() const
-{
- return positions_;
-}
-MutableSpan<float> BezierSpline::radii()
-{
- return radii_;
-}
-Span<float> BezierSpline::radii() const
-{
- return radii_;
-}
-MutableSpan<float> BezierSpline::tilts()
-{
- return tilts_;
-}
-Span<float> BezierSpline::tilts() const
-{
- return tilts_;
-}
-Span<int8_t> BezierSpline::handle_types_left() const
-{
- return handle_types_left_;
-}
-MutableSpan<int8_t> BezierSpline::handle_types_left()
-{
- return handle_types_left_;
-}
-Span<float3> BezierSpline::handle_positions_left() const
-{
- this->ensure_auto_handles();
- return handle_positions_left_;
-}
-MutableSpan<float3> BezierSpline::handle_positions_left(const bool write_only)
-{
- if (!write_only) {
- this->ensure_auto_handles();
- }
- return handle_positions_left_;
-}
-
-Span<int8_t> BezierSpline::handle_types_right() const
-{
- return handle_types_right_;
-}
-MutableSpan<int8_t> BezierSpline::handle_types_right()
-{
- return handle_types_right_;
-}
-Span<float3> BezierSpline::handle_positions_right() const
-{
- this->ensure_auto_handles();
- return handle_positions_right_;
-}
-MutableSpan<float3> BezierSpline::handle_positions_right(const bool write_only)
-{
- if (!write_only) {
- this->ensure_auto_handles();
- }
- return handle_positions_right_;
-}
-
-void BezierSpline::reverse_impl()
-{
- this->handle_positions_left().reverse();
- this->handle_positions_right().reverse();
- std::swap(this->handle_positions_left_, this->handle_positions_right_);
-
- this->handle_types_left().reverse();
- this->handle_types_right().reverse();
- std::swap(this->handle_types_left_, this->handle_types_right_);
-}
-
-static float3 previous_position(Span<float3> positions, const bool cyclic, const int i)
-{
- if (i == 0) {
- if (cyclic) {
- return positions[positions.size() - 1];
- }
- return 2.0f * positions[i] - positions[i + 1];
- }
- return positions[i - 1];
-}
-
-static float3 next_position(Span<float3> positions, const bool cyclic, const int i)
-{
- if (i == positions.size() - 1) {
- if (cyclic) {
- return positions[0];
- }
- return 2.0f * positions[i] - positions[i - 1];
- }
- return positions[i + 1];
-}
-
-void BezierSpline::ensure_auto_handles() const
-{
- if (!auto_handles_dirty_) {
- return;
- }
-
- std::lock_guard lock{auto_handle_mutex_};
- if (!auto_handles_dirty_) {
- return;
- }
-
- if (this->size() == 1) {
- auto_handles_dirty_ = false;
- return;
- }
-
- for (const int i : IndexRange(this->size())) {
- using namespace blender;
-
- if (ELEM(BEZIER_HANDLE_AUTO, handle_types_left_[i], handle_types_right_[i])) {
- const float3 prev_diff = positions_[i] - previous_position(positions_, is_cyclic_, i);
- const float3 next_diff = next_position(positions_, is_cyclic_, i) - positions_[i];
- float prev_len = math::length(prev_diff);
- float next_len = math::length(next_diff);
- if (prev_len == 0.0f) {
- prev_len = 1.0f;
- }
- if (next_len == 0.0f) {
- next_len = 1.0f;
- }
- const float3 dir = next_diff / next_len + prev_diff / prev_len;
-
- /* This magic number is unfortunate, but comes from elsewhere in Blender. */
- const float len = math::length(dir) * 2.5614f;
- if (len != 0.0f) {
- if (handle_types_left_[i] == BEZIER_HANDLE_AUTO) {
- const float prev_len_clamped = std::min(prev_len, next_len * 5.0f);
- handle_positions_left_[i] = positions_[i] + dir * -(prev_len_clamped / len);
- }
- if (handle_types_right_[i] == BEZIER_HANDLE_AUTO) {
- const float next_len_clamped = std::min(next_len, prev_len * 5.0f);
- handle_positions_right_[i] = positions_[i] + dir * (next_len_clamped / len);
- }
- }
- }
-
- if (handle_types_left_[i] == BEZIER_HANDLE_VECTOR) {
- const float3 prev = previous_position(positions_, is_cyclic_, i);
- handle_positions_left_[i] = math::interpolate(positions_[i], prev, 1.0f / 3.0f);
- }
-
- if (handle_types_right_[i] == BEZIER_HANDLE_VECTOR) {
- const float3 next = next_position(positions_, is_cyclic_, i);
- handle_positions_right_[i] = math::interpolate(positions_[i], next, 1.0f / 3.0f);
- }
- }
-
- auto_handles_dirty_ = false;
-}
-
-void BezierSpline::translate(const blender::float3 &translation)
-{
- for (float3 &position : this->positions()) {
- position += translation;
- }
- for (float3 &handle_position : this->handle_positions_left()) {
- handle_position += translation;
- }
- for (float3 &handle_position : this->handle_positions_right()) {
- handle_position += translation;
- }
- this->mark_cache_invalid();
-}
-
-void BezierSpline::transform(const blender::float4x4 &matrix)
-{
- for (float3 &position : this->positions()) {
- position = matrix * position;
- }
- for (float3 &handle_position : this->handle_positions_left()) {
- handle_position = matrix * handle_position;
- }
- for (float3 &handle_position : this->handle_positions_right()) {
- handle_position = matrix * handle_position;
- }
- this->mark_cache_invalid();
-}
-
-static void set_handle_position(const float3 &position,
- const HandleType type,
- const HandleType type_other,
- const float3 &new_value,
- float3 &handle,
- float3 &handle_other)
-{
- using namespace blender::math;
-
- /* Don't bother when the handle positions are calculated automatically anyway. */
- if (ELEM(type, BEZIER_HANDLE_AUTO, BEZIER_HANDLE_VECTOR)) {
- return;
- }
-
- handle = new_value;
- if (type_other == BEZIER_HANDLE_ALIGN) {
- /* Keep track of the old length of the opposite handle. */
- const float length = distance(handle_other, position);
- /* Set the other handle to directly opposite from the current handle. */
- const float3 dir = normalize(handle - position);
- handle_other = position - dir * length;
- }
-}
-
-void BezierSpline::set_handle_position_right(const int index, const blender::float3 &value)
-{
- set_handle_position(positions_[index],
- static_cast<HandleType>(handle_types_right_[index]),
- static_cast<HandleType>(handle_types_left_[index]),
- value,
- handle_positions_right_[index],
- handle_positions_left_[index]);
-}
-
-void BezierSpline::set_handle_position_left(const int index, const blender::float3 &value)
-{
- set_handle_position(positions_[index],
- static_cast<HandleType>(handle_types_right_[index]),
- static_cast<HandleType>(handle_types_left_[index]),
- value,
- handle_positions_left_[index],
- handle_positions_right_[index]);
-}
-
-bool BezierSpline::point_is_sharp(const int index) const
-{
- return ELEM(handle_types_left_[index], BEZIER_HANDLE_VECTOR, BEZIER_HANDLE_FREE) ||
- ELEM(handle_types_right_[index], BEZIER_HANDLE_VECTOR, BEZIER_HANDLE_FREE);
-}
-
-bool BezierSpline::segment_is_vector(const int index) const
-{
- /* Two control points are necessary to form a segment, that should be checked by the caller. */
- BLI_assert(this->size() > 1);
-
- if (index == this->size() - 1) {
- if (is_cyclic_) {
- return handle_types_right_.last() == BEZIER_HANDLE_VECTOR &&
- handle_types_left_.first() == BEZIER_HANDLE_VECTOR;
- }
- /* There is actually no segment in this case, but it's nice to avoid
- * having a special case for the last segment in calling code. */
- return true;
- }
- return handle_types_right_[index] == BEZIER_HANDLE_VECTOR &&
- handle_types_left_[index + 1] == BEZIER_HANDLE_VECTOR;
-}
-
-void BezierSpline::mark_cache_invalid()
-{
- offset_cache_dirty_ = true;
- position_cache_dirty_ = true;
- mapping_cache_dirty_ = true;
- tangent_cache_dirty_ = true;
- normal_cache_dirty_ = true;
- length_cache_dirty_ = true;
- auto_handles_dirty_ = true;
-}
-
-int BezierSpline::evaluated_points_num() const
-{
- BLI_assert(this->size() > 0);
- return this->control_point_offsets().last();
-}
-
-void BezierSpline::correct_end_tangents() const
-{
- using namespace blender::math;
- if (is_cyclic_) {
- return;
- }
-
- MutableSpan<float3> tangents(evaluated_tangents_cache_);
-
- if (handle_positions_right_.first() != positions_.first()) {
- tangents.first() = normalize(handle_positions_right_.first() - positions_.first());
- }
- if (handle_positions_left_.last() != positions_.last()) {
- tangents.last() = normalize(positions_.last() - handle_positions_left_.last());
- }
-}
-
-BezierSpline::InsertResult BezierSpline::calculate_segment_insertion(const int index,
- const int next_index,
- const float parameter)
-{
- using namespace blender::math;
-
- BLI_assert(parameter <= 1.0f && parameter >= 0.0f);
- BLI_assert(ELEM(next_index, 0, index + 1));
- const float3 &point_prev = positions_[index];
- const float3 &handle_prev = handle_positions_right_[index];
- const float3 &handle_next = handle_positions_left_[next_index];
- const float3 &point_next = positions_[next_index];
- const float3 center_point = interpolate(handle_prev, handle_next, parameter);
-
- BezierSpline::InsertResult result;
- result.handle_prev = interpolate(point_prev, handle_prev, parameter);
- result.handle_next = interpolate(handle_next, point_next, parameter);
- result.left_handle = interpolate(result.handle_prev, center_point, parameter);
- result.right_handle = interpolate(center_point, result.handle_next, parameter);
- result.position = interpolate(result.left_handle, result.right_handle, parameter);
- return result;
-}
-
-static void bezier_forward_difference_3d(const float3 &point_0,
- const float3 &point_1,
- const float3 &point_2,
- const float3 &point_3,
- MutableSpan<float3> result)
-{
- BLI_assert(result.size() > 0);
- const float inv_len = 1.0f / static_cast<float>(result.size());
- const float inv_len_squared = inv_len * inv_len;
- const float inv_len_cubed = inv_len_squared * inv_len;
-
- const float3 rt1 = 3.0f * (point_1 - point_0) * inv_len;
- const float3 rt2 = 3.0f * (point_0 - 2.0f * point_1 + point_2) * inv_len_squared;
- const float3 rt3 = (point_3 - point_0 + 3.0f * (point_1 - point_2)) * inv_len_cubed;
-
- float3 q0 = point_0;
- float3 q1 = rt1 + rt2 + rt3;
- float3 q2 = 2.0f * rt2 + 6.0f * rt3;
- float3 q3 = 6.0f * rt3;
- for (const int i : result.index_range()) {
- result[i] = q0;
- q0 += q1;
- q1 += q2;
- q2 += q3;
- }
-}
-
-void BezierSpline::evaluate_segment(const int index,
- const int next_index,
- MutableSpan<float3> positions) const
-{
- if (this->segment_is_vector(index)) {
- BLI_assert(positions.size() == 1);
- positions.first() = positions_[index];
- }
- else {
- bezier_forward_difference_3d(positions_[index],
- handle_positions_right_[index],
- handle_positions_left_[next_index],
- positions_[next_index],
- positions);
- }
-}
-
-Span<int> BezierSpline::control_point_offsets() const
-{
- if (!offset_cache_dirty_) {
- return offset_cache_;
- }
-
- std::lock_guard lock{offset_cache_mutex_};
- if (!offset_cache_dirty_) {
- return offset_cache_;
- }
-
- const int size = this->size();
- offset_cache_.resize(size + 1);
-
- MutableSpan<int> offsets = offset_cache_;
- if (size == 1) {
- offsets.first() = 0;
- offsets.last() = 1;
- }
- else {
- int offset = 0;
- for (const int i : IndexRange(size)) {
- offsets[i] = offset;
- offset += this->segment_is_vector(i) ? 1 : resolution_;
- }
- offsets.last() = offset;
- }
-
- offset_cache_dirty_ = false;
- return offsets;
-}
-
-static void calculate_mappings_linear_resolution(Span<int> offsets,
- const int size,
- const int resolution,
- const bool is_cyclic,
- MutableSpan<float> r_mappings)
-{
- const float first_segment_len_inv = 1.0f / offsets[1];
- for (const int i : IndexRange(0, offsets[1])) {
- r_mappings[i] = i * first_segment_len_inv;
- }
-
- const int grain_size = std::max(2048 / resolution, 1);
- blender::threading::parallel_for(IndexRange(1, size - 2), grain_size, [&](IndexRange range) {
- for (const int i_control_point : range) {
- const int segment_len = offsets[i_control_point + 1] - offsets[i_control_point];
- const float segment_len_inv = 1.0f / segment_len;
- for (const int i : IndexRange(segment_len)) {
- r_mappings[offsets[i_control_point] + i] = i_control_point + i * segment_len_inv;
- }
- }
- });
-
- if (is_cyclic) {
- const int last_segment_len = offsets[size] - offsets[size - 1];
- const float last_segment_len_inv = 1.0f / last_segment_len;
- for (const int i : IndexRange(last_segment_len)) {
- r_mappings[offsets[size - 1] + i] = size - 1 + i * last_segment_len_inv;
- }
- }
- else {
- r_mappings.last() = size - 1;
- }
-}
-
-Span<float> BezierSpline::evaluated_mappings() const
-{
- if (!mapping_cache_dirty_) {
- return evaluated_mapping_cache_;
- }
-
- std::lock_guard lock{mapping_cache_mutex_};
- if (!mapping_cache_dirty_) {
- return evaluated_mapping_cache_;
- }
-
- const int num = this->size();
- const int eval_num = this->evaluated_points_num();
- evaluated_mapping_cache_.resize(eval_num);
- MutableSpan<float> mappings = evaluated_mapping_cache_;
-
- if (eval_num == 1) {
- mappings.first() = 0.0f;
- mapping_cache_dirty_ = false;
- return mappings;
- }
-
- Span<int> offsets = this->control_point_offsets();
-
- blender::threading::isolate_task([&]() {
- /* Isolate the task, since this is function is multi-threaded and holds a lock. */
- calculate_mappings_linear_resolution(offsets, num, resolution_, is_cyclic_, mappings);
- });
-
- mapping_cache_dirty_ = false;
- return mappings;
-}
-
-Span<float3> BezierSpline::evaluated_positions() const
-{
- if (!position_cache_dirty_) {
- return evaluated_position_cache_;
- }
-
- std::lock_guard lock{position_cache_mutex_};
- if (!position_cache_dirty_) {
- return evaluated_position_cache_;
- }
-
- const int num = this->size();
- const int eval_num = this->evaluated_points_num();
- evaluated_position_cache_.resize(eval_num);
-
- MutableSpan<float3> positions = evaluated_position_cache_;
-
- if (num == 1) {
- /* Use a special case for single point splines to avoid checking in #evaluate_segment. */
- BLI_assert(eval_num == 1);
- positions.first() = positions_.first();
- position_cache_dirty_ = false;
- return positions;
- }
-
- this->ensure_auto_handles();
-
- Span<int> offsets = this->control_point_offsets();
-
- const int grain_size = std::max(512 / resolution_, 1);
- blender::threading::isolate_task([&]() {
- /* Isolate the task, since this is function is multi-threaded and holds a lock. */
- blender::threading::parallel_for(IndexRange(num - 1), grain_size, [&](IndexRange range) {
- for (const int i : range) {
- this->evaluate_segment(i, i + 1, positions.slice(offsets[i], offsets[i + 1] - offsets[i]));
- }
- });
- });
- if (is_cyclic_) {
- this->evaluate_segment(
- num - 1, 0, positions.slice(offsets[num - 1], offsets[num] - offsets[num - 1]));
- }
- else {
- /* Since evaluating the bezier segment doesn't add the final point,
- * it must be added manually in the non-cyclic case. */
- positions.last() = positions_.last();
- }
-
- position_cache_dirty_ = false;
- return positions;
-}
-
-BezierSpline::InterpolationData BezierSpline::interpolation_data_from_index_factor(
- const float index_factor) const
-{
- const int num = this->size();
-
- if (is_cyclic_) {
- if (index_factor < num) {
- const int index = std::floor(index_factor);
- const int next_index = (index < num - 1) ? index + 1 : 0;
- return InterpolationData{index, next_index, index_factor - index};
- }
- return InterpolationData{num - 1, 0, 1.0f};
- }
-
- if (index_factor < num - 1) {
- const int index = std::floor(index_factor);
- const int next_index = index + 1;
- return InterpolationData{index, next_index, index_factor - index};
- }
- return InterpolationData{num - 2, num - 1, 1.0f};
-}
-
-/* Use a spline argument to avoid adding this to the header. */
-template<typename T>
-static void interpolate_to_evaluated_impl(const BezierSpline &spline,
- const blender::VArray<T> &src,
- MutableSpan<T> dst)
-{
- BLI_assert(src.size() == spline.size());
- BLI_assert(dst.size() == spline.evaluated_points_num());
- Span<float> mappings = spline.evaluated_mappings();
-
- for (const int i : dst.index_range()) {
- BezierSpline::InterpolationData interp = spline.interpolation_data_from_index_factor(
- mappings[i]);
-
- const T &value = src[interp.control_point_index];
- const T &next_value = src[interp.next_control_point_index];
-
- dst[i] = blender::attribute_math::mix2(interp.factor, value, next_value);
- }
-}
-
-GVArray BezierSpline::interpolate_to_evaluated(const GVArray &src) const
-{
- BLI_assert(src.size() == this->size());
-
- if (src.is_single()) {
- return src;
- }
-
- const int eval_num = this->evaluated_points_num();
- if (eval_num == 1) {
- return src;
- }
-
- GVArray new_varray;
- blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) {
- Array<T> values(eval_num);
- interpolate_to_evaluated_impl<T>(*this, src.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
- }
- });
-
- return new_varray;
-}
diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc
deleted file mode 100644
index a7eeb82d854..00000000000
--- a/source/blender/blenkernel/intern/spline_nurbs.cc
+++ /dev/null
@@ -1,395 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_array.hh"
-#include "BLI_span.hh"
-#include "BLI_virtual_array.hh"
-
-#include "BKE_attribute_math.hh"
-#include "BKE_spline.hh"
-
-using blender::Array;
-using blender::float3;
-using blender::GVArray;
-using blender::IndexRange;
-using blender::MutableSpan;
-using blender::Span;
-using blender::VArray;
-
-void NURBSpline::copy_settings(Spline &dst) const
-{
- NURBSpline &nurbs = static_cast<NURBSpline &>(dst);
- nurbs.knots_mode = knots_mode;
- nurbs.resolution_ = resolution_;
- nurbs.order_ = order_;
-}
-
-void NURBSpline::copy_data(Spline &dst) const
-{
- NURBSpline &nurbs = static_cast<NURBSpline &>(dst);
- nurbs.positions_ = positions_;
- nurbs.weights_ = weights_;
- nurbs.knots_ = knots_;
- nurbs.knots_dirty_ = knots_dirty_;
- nurbs.radii_ = radii_;
- nurbs.tilts_ = tilts_;
-}
-
-int NURBSpline::size() const
-{
- const int size = positions_.size();
- BLI_assert(size == radii_.size());
- BLI_assert(size == tilts_.size());
- BLI_assert(size == weights_.size());
- return size;
-}
-
-int NURBSpline::resolution() const
-{
- return resolution_;
-}
-
-void NURBSpline::set_resolution(const int value)
-{
- BLI_assert(value > 0);
- resolution_ = value;
- this->mark_cache_invalid();
-}
-
-uint8_t NURBSpline::order() const
-{
- return order_;
-}
-
-void NURBSpline::set_order(const uint8_t value)
-{
- BLI_assert(value >= 2 && value <= 6);
- order_ = value;
- this->mark_cache_invalid();
-}
-
-void NURBSpline::resize(const int size)
-{
- positions_.resize(size);
- radii_.resize(size);
- tilts_.resize(size);
- weights_.resize(size);
- this->mark_cache_invalid();
- attributes.reallocate(size);
-}
-
-MutableSpan<float3> NURBSpline::positions()
-{
- return positions_;
-}
-Span<float3> NURBSpline::positions() const
-{
- return positions_;
-}
-MutableSpan<float> NURBSpline::radii()
-{
- return radii_;
-}
-Span<float> NURBSpline::radii() const
-{
- return radii_;
-}
-MutableSpan<float> NURBSpline::tilts()
-{
- return tilts_;
-}
-Span<float> NURBSpline::tilts() const
-{
- return tilts_;
-}
-MutableSpan<float> NURBSpline::weights()
-{
- return weights_;
-}
-Span<float> NURBSpline::weights() const
-{
- return weights_;
-}
-
-void NURBSpline::reverse_impl()
-{
- this->weights().reverse();
-}
-
-void NURBSpline::mark_cache_invalid()
-{
- basis_cache_dirty_ = true;
- position_cache_dirty_ = true;
- tangent_cache_dirty_ = true;
- normal_cache_dirty_ = true;
- length_cache_dirty_ = true;
-}
-
-int NURBSpline::evaluated_points_num() const
-{
- if (!this->check_valid_num_and_order()) {
- return 0;
- }
- return resolution_ * this->segments_num();
-}
-
-void NURBSpline::correct_end_tangents() const
-{
-}
-
-bool NURBSpline::check_valid_num_and_order() const
-{
- if (this->size() < order_) {
- return false;
- }
-
- if (ELEM(this->knots_mode, NURBS_KNOT_MODE_BEZIER, NURBS_KNOT_MODE_ENDPOINT_BEZIER)) {
- if (this->knots_mode == NURBS_KNOT_MODE_BEZIER && this->size() <= order_) {
- return false;
- }
- return (!is_cyclic_ || this->size() % (order_ - 1) == 0);
- }
-
- return true;
-}
-
-int NURBSpline::knots_num() const
-{
- const int num = this->size() + order_;
- return is_cyclic_ ? num + order_ - 1 : num;
-}
-
-void NURBSpline::calculate_knots() const
-{
- const KnotsMode mode = this->knots_mode;
- const int order = order_;
- const bool is_bezier = ELEM(mode, NURBS_KNOT_MODE_BEZIER, NURBS_KNOT_MODE_ENDPOINT_BEZIER);
- const bool is_end_point = ELEM(mode, NURBS_KNOT_MODE_ENDPOINT, NURBS_KNOT_MODE_ENDPOINT_BEZIER);
- /* Inner knots are always repeated once except on Bezier case. */
- const int repeat_inner = is_bezier ? order - 1 : 1;
- /* How many times to repeat 0.0 at the beginning of knot. */
- const int head = is_end_point ? (order - (is_cyclic_ ? 1 : 0)) :
- (is_bezier ? min_ii(2, repeat_inner) : 1);
- /* Number of knots replicating widths of the starting knots.
- * Covers both Cyclic and EndPoint cases. */
- const int tail = is_cyclic_ ? 2 * order - 1 : (is_end_point ? order : 0);
-
- knots_.resize(this->knots_num());
- MutableSpan<float> knots = knots_;
-
- int r = head;
- float current = 0.0f;
-
- const int offset = is_end_point && is_cyclic_ ? 1 : 0;
- if (offset) {
- knots[0] = current;
- current += 1.0f;
- }
-
- for (const int i : IndexRange(offset, knots.size() - offset - tail)) {
- knots[i] = current;
- r--;
- if (r == 0) {
- current += 1.0;
- r = repeat_inner;
- }
- }
-
- const int tail_index = knots.size() - tail;
- for (const int i : IndexRange(tail)) {
- knots[tail_index + i] = current + (knots[i] - knots[0]);
- }
-}
-
-Span<float> NURBSpline::knots() const
-{
- if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->knots_num());
- return knots_;
- }
-
- std::lock_guard lock{knots_mutex_};
- if (!knots_dirty_) {
- BLI_assert(knots_.size() == this->knots_num());
- return knots_;
- }
-
- this->calculate_knots();
-
- knots_dirty_ = false;
-
- return knots_;
-}
-
-static void calculate_basis_for_point(const float parameter,
- const int num,
- const int degree,
- const Span<float> knots,
- MutableSpan<float> r_weights,
- int &r_start_index)
-{
- const int order = degree + 1;
-
- int start = 0;
- int end = 0;
- for (const int i : IndexRange(num + degree)) {
- const bool knots_equal = knots[i] == knots[i + 1];
- if (knots_equal || parameter < knots[i] || parameter > knots[i + 1]) {
- continue;
- }
-
- start = std::max(i - degree, 0);
- end = i;
- break;
- }
-
- Array<float, 12> buffer(order * 2, 0.0f);
-
- buffer[end - start] = 1.0f;
-
- for (const int i_order : IndexRange(2, degree)) {
- if (end + i_order >= knots.size()) {
- end = num + degree - i_order;
- }
- for (const int i : IndexRange(end - start + 1)) {
- const int knot_index = start + i;
-
- float new_basis = 0.0f;
- if (buffer[i] != 0.0f) {
- new_basis += ((parameter - knots[knot_index]) * buffer[i]) /
- (knots[knot_index + i_order - 1] - knots[knot_index]);
- }
-
- if (buffer[i + 1] != 0.0f) {
- new_basis += ((knots[knot_index + i_order] - parameter) * buffer[i + 1]) /
- (knots[knot_index + i_order] - knots[knot_index + 1]);
- }
-
- buffer[i] = new_basis;
- }
- }
-
- buffer.as_mutable_span().drop_front(end - start + 1).fill(0.0f);
- r_weights.copy_from(buffer.as_span().take_front(order));
- r_start_index = start;
-}
-
-const NURBSpline::BasisCache &NURBSpline::calculate_basis_cache() const
-{
- if (!basis_cache_dirty_) {
- return basis_cache_;
- }
-
- std::lock_guard lock{basis_cache_mutex_};
- if (!basis_cache_dirty_) {
- return basis_cache_;
- }
-
- const int num = this->size();
- const int eval_num = this->evaluated_points_num();
-
- const int order = this->order();
- const int degree = order - 1;
-
- basis_cache_.weights.resize(eval_num * order);
- basis_cache_.start_indices.resize(eval_num);
-
- if (eval_num == 0) {
- return basis_cache_;
- }
-
- MutableSpan<float> basis_weights(basis_cache_.weights);
- MutableSpan<int> basis_start_indices(basis_cache_.start_indices);
-
- const Span<float> control_weights = this->weights();
- const Span<float> knots = this->knots();
-
- const int last_control_point_index = is_cyclic_ ? num + degree : num;
-
- const float start = knots[degree];
- const float end = knots[last_control_point_index];
- const float step = (end - start) / this->evaluated_edges_num();
- for (const int i : IndexRange(eval_num)) {
- /* Clamp parameter due to floating point inaccuracy. */
- const float parameter = std::clamp(start + step * i, knots[0], knots[num + degree]);
-
- MutableSpan<float> point_weights = basis_weights.slice(i * order, order);
-
- calculate_basis_for_point(
- parameter, last_control_point_index, degree, knots, point_weights, basis_start_indices[i]);
-
- for (const int j : point_weights.index_range()) {
- const int point_index = (basis_start_indices[i] + j) % num;
- point_weights[j] *= control_weights[point_index];
- }
- }
-
- basis_cache_dirty_ = false;
- return basis_cache_;
-}
-
-template<typename T>
-void interpolate_to_evaluated_impl(const NURBSpline::BasisCache &basis_cache,
- const int order,
- const blender::VArray<T> &src,
- MutableSpan<T> dst)
-{
- const int num = src.size();
- blender::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);
- const int start_index = basis_cache.start_indices[i];
-
- for (const int j : point_weights.index_range()) {
- const int point_index = (start_index + j) % num;
- mixer.mix_in(i, src[point_index], point_weights[j]);
- }
- }
-
- mixer.finalize();
-}
-
-GVArray NURBSpline::interpolate_to_evaluated(const GVArray &src) const
-{
- BLI_assert(src.size() == this->size());
-
- if (src.is_single()) {
- return src;
- }
-
- const BasisCache &basis_cache = this->calculate_basis_cache();
-
- GVArray new_varray;
- blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
- using T = decltype(dummy);
- if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) {
- Array<T> values(this->evaluated_points_num());
- interpolate_to_evaluated_impl<T>(basis_cache, this->order(), src.typed<T>(), values);
- new_varray = VArray<T>::ForContainer(std::move(values));
- }
- });
-
- return new_varray;
-}
-
-Span<float3> NURBSpline::evaluated_positions() const
-{
- if (!position_cache_dirty_) {
- return evaluated_position_cache_;
- }
-
- std::lock_guard lock{position_cache_mutex_};
- if (!position_cache_dirty_) {
- return evaluated_position_cache_;
- }
-
- const int eval_num = this->evaluated_points_num();
- evaluated_position_cache_.resize(eval_num);
-
- /* TODO: Avoid copying the evaluated data from the temporary array. */
- VArray<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span());
- evaluated.materialize(evaluated_position_cache_);
-
- position_cache_dirty_ = false;
- return evaluated_position_cache_;
-}
diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc
deleted file mode 100644
index c3cc268c81c..00000000000
--- a/source/blender/blenkernel/intern/spline_poly.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-
-#include "BLI_span.hh"
-#include "BLI_virtual_array.hh"
-
-#include "BKE_spline.hh"
-
-using blender::float3;
-using blender::GVArray;
-using blender::MutableSpan;
-using blender::Span;
-
-void PolySpline::copy_settings(Spline &UNUSED(dst)) const
-{
- /* Poly splines have no settings not covered by the base class. */
-}
-
-void PolySpline::copy_data(Spline &dst) const
-{
- PolySpline &poly = static_cast<PolySpline &>(dst);
- poly.positions_ = positions_;
- poly.radii_ = radii_;
- poly.tilts_ = tilts_;
-}
-
-int PolySpline::size() const
-{
- const int size = positions_.size();
- BLI_assert(size == radii_.size());
- BLI_assert(size == tilts_.size());
- return size;
-}
-
-void PolySpline::resize(const int size)
-{
- positions_.resize(size);
- radii_.resize(size);
- tilts_.resize(size);
- this->mark_cache_invalid();
- attributes.reallocate(size);
-}
-
-MutableSpan<float3> PolySpline::positions()
-{
- return positions_;
-}
-Span<float3> PolySpline::positions() const
-{
- return positions_;
-}
-MutableSpan<float> PolySpline::radii()
-{
- return radii_;
-}
-Span<float> PolySpline::radii() const
-{
- return radii_;
-}
-MutableSpan<float> PolySpline::tilts()
-{
- return tilts_;
-}
-Span<float> PolySpline::tilts() const
-{
- return tilts_;
-}
-
-void PolySpline::reverse_impl()
-{
-}
-
-void PolySpline::mark_cache_invalid()
-{
- tangent_cache_dirty_ = true;
- normal_cache_dirty_ = true;
- length_cache_dirty_ = true;
-}
-
-int PolySpline::evaluated_points_num() const
-{
- return this->size();
-}
-
-void PolySpline::correct_end_tangents() const
-{
-}
-
-Span<float3> PolySpline::evaluated_positions() const
-{
- return this->positions();
-}
-
-GVArray PolySpline::interpolate_to_evaluated(const GVArray &src) const
-{
- BLI_assert(src.size() == this->size());
- return src;
-}
diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.c b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
index b13aec37c78..aabed2cea28 100644
--- a/source/blender/blenkernel/intern/subdiv_converter_mesh.c
+++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.c
@@ -41,6 +41,8 @@ typedef struct ConverterStorage {
/* CustomData layer for vertex sharpnesses. */
const float *cd_vertex_crease;
+ /* CustomData layer for edge sharpness. */
+ const float *cd_edge_crease;
/* Indexed by loop index, value denotes index of face-varying vertex
* which corresponds to the UV coordinate.
*/
@@ -157,12 +159,11 @@ static float get_edge_sharpness(const OpenSubdiv_Converter *converter, int manif
return 10.0f;
}
#endif
- if (!storage->settings.use_creases) {
+ if (!storage->settings.use_creases || storage->cd_edge_crease == NULL) {
return 0.0f;
}
const int edge_index = storage->manifold_edge_index_reverse[manifold_edge_index];
- const MEdge *medge = storage->edges;
- return BKE_subdiv_crease_to_sharpness_char(medge[edge_index].crease);
+ return BKE_subdiv_crease_to_sharpness_f(storage->cd_edge_crease[edge_index]);
}
static bool is_infinite_sharp_vertex(const OpenSubdiv_Converter *converter,
@@ -211,6 +212,7 @@ static void precalc_uv_layer(const OpenSubdiv_Converter *converter, const int la
UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create(
storage->polys,
(const bool *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, ".hide_poly"),
+ (const bool *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, ".select_poly"),
storage->loops,
mloopuv,
num_poly,
@@ -398,6 +400,7 @@ static void init_user_data(OpenSubdiv_Converter *converter,
user_data->polys = BKE_mesh_polys(mesh);
user_data->loops = BKE_mesh_loops(mesh);
user_data->cd_vertex_crease = CustomData_get_layer(&mesh->vdata, CD_CREASE);
+ user_data->cd_edge_crease = CustomData_get_layer(&mesh->edata, CD_CREASE);
user_data->loop_uv_indices = NULL;
initialize_manifold_indices(user_data);
converter->user_data = user_data;
diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc
index 44bdd6e6d06..6bc188fd1fc 100644
--- a/source/blender/blenkernel/intern/subdiv_mesh.cc
+++ b/source/blender/blenkernel/intern/subdiv_mesh.cc
@@ -518,9 +518,11 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex
const int *UNUSED(subdiv_polygon_offset))
{
/* Multi-resolution grid data will be applied or become invalid after subdivision,
- * so don't try to preserve it and use memory. */
+ * so don't try to preserve it and use memory. Crease values should also not be interpolated. */
CustomData_MeshMasks mask = CD_MASK_EVERYTHING;
mask.lmask &= ~CD_MASK_MULTIRES_GRIDS;
+ mask.vmask &= ~CD_MASK_CREASE;
+ mask.emask &= ~CD_MASK_CREASE;
SubdivMeshContext *subdiv_context = static_cast<SubdivMeshContext *>(foreach_context->user_data);
subdiv_context->subdiv_mesh = BKE_mesh_new_nomain_from_template_ex(
@@ -790,7 +792,7 @@ static void subdiv_copy_edge_data(SubdivMeshContext *ctx,
{
const int subdiv_edge_index = subdiv_edge - ctx->subdiv_edges;
if (coarse_edge == nullptr) {
- subdiv_edge->crease = 0;
+ /* TODO: Ensure crease layer isn't copied to result. */
subdiv_edge->flag = 0;
if (!ctx->settings->use_optimal_display) {
subdiv_edge->flag |= ME_EDGERENDER;
@@ -1135,8 +1137,6 @@ static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach
is_simple,
u,
subdiv_vertex->co);
- /* Reset flags and such. */
- subdiv_vertex->flag = 0;
}
/** \} */
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 0e5f9f30243..c95c43a8099 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -285,7 +285,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss,
* 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, NULL, mloop, mloopuv, totface, totvert, limit, false, true);
+ mpoly, NULL, NULL, mloop, mloopuv, totface, totvert, limit, false, true);
if (!vmap) {
return 0;
}
@@ -592,11 +592,12 @@ static void ss_sync_ccg_from_derivedmesh(CCGSubSurf *ss,
me = medge;
index = (int *)dm->getEdgeDataArray(dm, CD_ORIGINDEX);
+ const float *creases = (const float *)dm->getEdgeDataArray(dm, CD_CREASE);
for (i = 0; i < totedge; i++, me++) {
CCGEdge *e;
float crease;
- crease = useFlatSubdiv ? creaseFactor : me->crease * creaseFactor / 255.0f;
+ crease = useFlatSubdiv ? creaseFactor : (creases ? creases[i] * creaseFactor : 0.0f);
ccgSubSurf_syncEdge(
ss, POINTER_FROM_INT(i), POINTER_FROM_UINT(me->v1), POINTER_FROM_UINT(me->v2), crease, &e);
@@ -879,7 +880,6 @@ static void ccgDM_getFinalVertNo(DerivedMesh *dm, int vertNum, float r_no[3])
BLI_INLINE void ccgDM_to_MVert(MVert *mv, const CCGKey *key, CCGElem *elem)
{
copy_v3_v3(mv->co, CCG_elem_co(key, elem));
- mv->flag = 0;
}
static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
@@ -949,7 +949,6 @@ BLI_INLINE void ccgDM_to_MEdge(MEdge *med, const int v1, const int v2, const sho
{
med->v1 = v1;
med->v2 = v2;
- med->crease = 0;
med->flag = flag;
}
diff --git a/source/blender/blenkernel/intern/vfont.c b/source/blender/blenkernel/intern/vfont.c
index 288493c9d65..ddc758c6887 100644
--- a/source/blender/blenkernel/intern/vfont.c
+++ b/source/blender/blenkernel/intern/vfont.c
@@ -81,7 +81,7 @@ static void vfont_copy_data(Main *UNUSED(bmain),
{
VFont *vfont_dst = (VFont *)id_dst;
- /* We never handle usercount here for own data. */
+ /* We never handle user-count here for own data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
/* Just to be sure, should not have any value actually after reading time. */
diff --git a/source/blender/blenkernel/intern/workspace.c b/source/blender/blenkernel/intern/workspace.cc
index f59be7f0111..8008dacc853 100644
--- a/source/blender/blenkernel/intern/workspace.c
+++ b/source/blender/blenkernel/intern/workspace.cc
@@ -57,7 +57,7 @@ static void workspace_free_data(ID *id)
BLI_freelistN(&workspace->layouts);
while (!BLI_listbase_is_empty(&workspace->tools)) {
- BKE_workspace_tool_remove(workspace, workspace->tools.first);
+ BKE_workspace_tool_remove(workspace, static_cast<bToolRef *>(workspace->tools.first));
}
MEM_SAFE_FREE(workspace->status_text);
@@ -107,12 +107,12 @@ static void workspace_blend_read_data(BlendDataReader *reader, ID *id)
}
LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
- tref->runtime = NULL;
+ tref->runtime = nullptr;
BLO_read_data_address(reader, &tref->properties);
IDP_BlendDataRead(reader, &tref->properties);
}
- workspace->status_text = NULL;
+ workspace->status_text = nullptr;
id_us_ensure_real(&workspace->id);
}
@@ -125,15 +125,15 @@ static void workspace_blend_read_lib(BlendLibReader *reader, ID *id)
/* Do not keep the scene reference when appending a workspace. Setting a scene for a workspace is
* a convenience feature, but the workspace should never truly depend on scene data. */
if (ID_IS_LINKED(id)) {
- workspace->pin_scene = NULL;
+ workspace->pin_scene = nullptr;
}
else {
- BLO_read_id_address(reader, NULL, &workspace->pin_scene);
+ BLO_read_id_address(reader, nullptr, &workspace->pin_scene);
}
/* Restore proper 'parent' pointers to relevant data, and clean up unused/invalid entries. */
LISTBASE_FOREACH_MUTABLE (WorkSpaceDataRelation *, relation, &workspace->hook_layout_relations) {
- relation->parent = NULL;
+ relation->parent = nullptr;
LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
if (win->winid == relation->parentid) {
@@ -141,7 +141,7 @@ static void workspace_blend_read_lib(BlendLibReader *reader, ID *id)
}
}
}
- if (relation->parent == NULL) {
+ if (relation->parent == nullptr) {
BLI_freelinkN(&workspace->hook_layout_relations, relation);
}
}
@@ -176,33 +176,33 @@ static void workspace_blend_read_expand(BlendExpander *expander, ID *id)
}
IDTypeInfo IDType_ID_WS = {
- .id_code = ID_WS,
- .id_filter = FILTER_ID_WS,
- .main_listbase_index = INDEX_ID_WS,
- .struct_size = sizeof(WorkSpace),
- .name = "WorkSpace",
- .name_plural = "workspaces",
- .translation_context = BLT_I18NCONTEXT_ID_WORKSPACE,
- .flags = IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
- .asset_type_info = NULL,
-
- .init_data = workspace_init_data,
- .copy_data = NULL,
- .free_data = workspace_free_data,
- .make_local = NULL,
- .foreach_id = workspace_foreach_id,
- .foreach_cache = NULL,
- .foreach_path = NULL,
- .owner_pointer_get = NULL,
-
- .blend_write = workspace_blend_write,
- .blend_read_data = workspace_blend_read_data,
- .blend_read_lib = workspace_blend_read_lib,
- .blend_read_expand = workspace_blend_read_expand,
-
- .blend_read_undo_preserve = NULL,
-
- .lib_override_apply_post = NULL,
+ /* id_code */ ID_WS,
+ /* id_filter */ FILTER_ID_WS,
+ /* main_listbase_index */ INDEX_ID_WS,
+ /* struct_size */ sizeof(WorkSpace),
+ /* name */ "WorkSpace",
+ /* name_plural */ "workspaces",
+ /* translation_context */ BLT_I18NCONTEXT_ID_WORKSPACE,
+ /* flags */ IDTYPE_FLAGS_NO_COPY | IDTYPE_FLAGS_ONLY_APPEND | IDTYPE_FLAGS_NO_ANIMDATA,
+ /* asset_type_info */ nullptr,
+
+ /* init_data */ workspace_init_data,
+ /* copy_data */ nullptr,
+ /* free_data */ workspace_free_data,
+ /* make_local */ nullptr,
+ /* foreach_id */ workspace_foreach_id,
+ /* foreach_cache */ nullptr,
+ /* foreach_path */ nullptr,
+ /* owner_pointer_get */ nullptr,
+
+ /* blend_write */ workspace_blend_write,
+ /* blend_read_data */ workspace_blend_read_data,
+ /* blend_read_lib */ workspace_blend_read_lib,
+ /* blend_read_expand */ workspace_blend_read_expand,
+
+ /* blend_read_undo_preserve */ nullptr,
+
+ /* lib_override_apply_post */ nullptr,
};
/* -------------------------------------------------------------------- */
@@ -230,7 +230,8 @@ static void workspace_layout_name_set(WorkSpace *workspace,
static WorkSpaceLayout *workspace_layout_find_exec(const WorkSpace *workspace,
const bScreen *screen)
{
- return BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen));
+ return static_cast<WorkSpaceLayout *>(
+ BLI_findptr(&workspace->layouts, screen, offsetof(WorkSpaceLayout, screen)));
}
static void workspace_relation_add(ListBase *relation_list,
@@ -238,7 +239,7 @@ static void workspace_relation_add(ListBase *relation_list,
const int parentid,
void *data)
{
- WorkSpaceDataRelation *relation = MEM_callocN(sizeof(*relation), __func__);
+ WorkSpaceDataRelation *relation = MEM_cnew<WorkSpaceDataRelation>(__func__);
relation->parent = parent;
relation->parentid = parentid;
relation->value = data;
@@ -256,9 +257,9 @@ static void workspace_relation_ensure_updated(ListBase *relation_list,
const int parentid,
void *data)
{
- WorkSpaceDataRelation *relation = BLI_listbase_bytes_find(
- relation_list, &parentid, sizeof(parentid), offsetof(WorkSpaceDataRelation, parentid));
- if (relation != NULL) {
+ WorkSpaceDataRelation *relation = static_cast<WorkSpaceDataRelation *>(BLI_listbase_bytes_find(
+ relation_list, &parentid, sizeof(parentid), offsetof(WorkSpaceDataRelation, parentid)));
+ if (relation != nullptr) {
relation->parent = parent;
relation->value = data;
/* reinsert at the head of the list, so that more commonly used relations are found faster. */
@@ -274,13 +275,13 @@ static void workspace_relation_ensure_updated(ListBase *relation_list,
static void *workspace_relation_get_data_matching_parent(const ListBase *relation_list,
const void *parent)
{
- WorkSpaceDataRelation *relation = BLI_findptr(
- relation_list, parent, offsetof(WorkSpaceDataRelation, parent));
- if (relation != NULL) {
+ WorkSpaceDataRelation *relation = static_cast<WorkSpaceDataRelation *>(
+ BLI_findptr(relation_list, parent, offsetof(WorkSpaceDataRelation, parent)));
+ if (relation != nullptr) {
return relation->value;
}
- return NULL;
+ return nullptr;
}
/**
@@ -296,7 +297,8 @@ static bool UNUSED_FUNCTION(workspaces_is_screen_used)
#endif
(const Main *bmain, bScreen *screen)
{
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ for (WorkSpace *workspace = static_cast<WorkSpace *>(bmain->workspaces.first); workspace;
+ workspace = static_cast<WorkSpace *>(workspace->id.next)) {
if (workspace_layout_find_exec(workspace, screen)) {
return true;
}
@@ -313,14 +315,16 @@ static bool UNUSED_FUNCTION(workspaces_is_screen_used)
WorkSpace *BKE_workspace_add(Main *bmain, const char *name)
{
- WorkSpace *new_workspace = BKE_id_new(bmain, ID_WS, name);
+ WorkSpace *new_workspace = static_cast<WorkSpace *>(BKE_id_new(bmain, ID_WS, name));
id_us_ensure_real(&new_workspace->id);
return new_workspace;
}
void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
{
- for (WorkSpaceLayout *layout = workspace->layouts.first, *layout_next; layout;
+ for (WorkSpaceLayout *layout = static_cast<WorkSpaceLayout *>(workspace->layouts.first),
+ *layout_next;
+ layout;
layout = layout_next) {
layout_next = layout->next;
BKE_workspace_layout_remove(bmain, workspace, layout);
@@ -330,11 +334,13 @@ void BKE_workspace_remove(Main *bmain, WorkSpace *workspace)
WorkSpaceInstanceHook *BKE_workspace_instance_hook_create(const Main *bmain, const int winid)
{
- WorkSpaceInstanceHook *hook = MEM_callocN(sizeof(WorkSpaceInstanceHook), __func__);
+ WorkSpaceInstanceHook *hook = MEM_cnew<WorkSpaceInstanceHook>(__func__);
/* set an active screen-layout for each possible window/workspace combination */
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- BKE_workspace_active_layout_set(hook, winid, workspace, workspace->layouts.first);
+ for (WorkSpace *workspace = static_cast<WorkSpace *>(bmain->workspaces.first); workspace;
+ workspace = static_cast<WorkSpace *>(workspace->id.next)) {
+ BKE_workspace_active_layout_set(
+ hook, winid, workspace, static_cast<WorkSpaceLayout *>(workspace->layouts.first));
}
return hook;
@@ -347,8 +353,11 @@ void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *
BLI_assert(!BLI_listbase_is_empty(&bmain->workspaces) || G.background);
/* Free relations for this hook */
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
- for (WorkSpaceDataRelation *relation = workspace->hook_layout_relations.first, *relation_next;
+ for (WorkSpace *workspace = static_cast<WorkSpace *>(bmain->workspaces.first); workspace;
+ workspace = static_cast<WorkSpace *>(workspace->id.next)) {
+ for (WorkSpaceDataRelation *relation = static_cast<WorkSpaceDataRelation *>(
+ workspace->hook_layout_relations.first),
+ *relation_next;
relation;
relation = relation_next) {
relation_next = relation->next;
@@ -366,7 +375,7 @@ WorkSpaceLayout *BKE_workspace_layout_add(Main *bmain,
bScreen *screen,
const char *name)
{
- WorkSpaceLayout *layout = MEM_callocN(sizeof(*layout), __func__);
+ WorkSpaceLayout *layout = MEM_cnew<WorkSpaceLayout>(__func__);
BLI_assert(!workspaces_is_screen_used(bmain, screen));
#ifndef DEBUG
@@ -393,7 +402,10 @@ void BKE_workspace_layout_remove(Main *bmain, WorkSpace *workspace, WorkSpaceLay
void BKE_workspace_relations_free(ListBase *relation_list)
{
- for (WorkSpaceDataRelation *relation = relation_list->first, *relation_next; relation;
+ for (WorkSpaceDataRelation *
+ relation = static_cast<WorkSpaceDataRelation *>(relation_list->first),
+ *relation_next;
+ relation;
relation = relation_next) {
relation_next = relation->next;
workspace_relation_remove(relation_list, relation);
@@ -420,7 +432,7 @@ WorkSpaceLayout *BKE_workspace_layout_find(const WorkSpace *workspace, const bSc
workspace->id.name + 2,
screen->id.name + 2);
- return NULL;
+ return nullptr;
}
WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
@@ -430,10 +442,11 @@ WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
WorkSpaceLayout *layout;
if (r_workspace) {
- *r_workspace = NULL;
+ *r_workspace = nullptr;
}
- for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) {
+ for (WorkSpace *workspace = static_cast<WorkSpace *>(bmain->workspaces.first); workspace;
+ workspace = static_cast<WorkSpace *>(workspace->id.next)) {
if ((layout = workspace_layout_find_exec(workspace, screen))) {
if (r_workspace) {
*r_workspace = workspace;
@@ -443,7 +456,7 @@ WorkSpaceLayout *BKE_workspace_layout_find_global(const Main *bmain,
}
}
- return NULL;
+ return nullptr;
}
WorkSpaceLayout *BKE_workspace_layout_iter_circular(const WorkSpace *workspace,
@@ -464,15 +477,15 @@ WorkSpaceLayout *BKE_workspace_layout_iter_circular(const WorkSpace *workspace,
LISTBASE_CIRCULAR_BACKWARD_END(WorkSpaceLayout *, &workspace->layouts, iter_layout, start);
}
else {
- LISTBASE_CIRCULAR_FORWARD_BEGIN (&workspace->layouts, iter_layout, start) {
+ LISTBASE_CIRCULAR_FORWARD_BEGIN (WorkSpaceLayout *, &workspace->layouts, iter_layout, start) {
if (!callback(iter_layout, arg)) {
return iter_layout;
}
}
- LISTBASE_CIRCULAR_FORWARD_END(&workspace->layouts, iter_layout, start);
+ LISTBASE_CIRCULAR_FORWARD_END(WorkSpaceLayout *, &workspace->layouts, iter_layout, start);
}
- return NULL;
+ return nullptr;
}
void BKE_workspace_tool_remove(struct WorkSpace *workspace, struct bToolRef *tref)
@@ -494,13 +507,13 @@ bool BKE_workspace_owner_id_check(const WorkSpace *workspace, const char *owner_
}
/* We could use hash lookup, for now this list is highly likely under < ~16 items. */
- return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != NULL;
+ return BLI_findstring(&workspace->owner_ids, owner_id, offsetof(wmOwnerID, name)) != nullptr;
}
void BKE_workspace_id_tag_all_visible(Main *bmain, int tag)
{
BKE_main_id_tag_listbase(&bmain->workspaces, tag, false);
- wmWindowManager *wm = bmain->wm.first;
+ wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
workspace->id.tag |= tag;
@@ -523,14 +536,14 @@ void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace)
* that optimization is possible and needed.
* This code can be called from places where we might have this equality, but still want to
* ensure/update the active layout below.
- * Known case where this is buggy and will crash later due to NULL active layout: reading
+ * Known case where this is buggy and will crash later due to nullptr active layout: reading
* a blend file, when the new read workspace ID happens to have the exact same memory address
* as when it was saved in the blend file (extremely unlikely, but possible). */
hook->active = workspace;
if (workspace) {
- WorkSpaceLayout *layout = workspace_relation_get_data_matching_parent(
- &workspace->hook_layout_relations, hook);
+ WorkSpaceLayout *layout = static_cast<WorkSpaceLayout *>(
+ workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook));
if (layout) {
hook->act_layout = layout;
}
@@ -551,7 +564,8 @@ WorkSpaceLayout *BKE_workspace_active_layout_for_workspace_get(const WorkSpaceIn
}
/* Inactive workspace */
- return workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook);
+ return static_cast<WorkSpaceLayout *>(
+ workspace_relation_get_data_matching_parent(&workspace->hook_layout_relations, hook));
}
void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook,