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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel')
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h13
-rw-r--r--source/blender/blenkernel/BKE_attribute.hh31
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h4
-rw-r--r--source/blender/blenkernel/BKE_compute_contexts.hh46
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.h2
-rw-r--r--source/blender/blenkernel/BKE_cryptomatte.hh26
-rw-r--r--source/blender/blenkernel/BKE_curves.hh73
-rw-r--r--source/blender/blenkernel/BKE_curves_utils.hh328
-rw-r--r--source/blender/blenkernel/BKE_customdata.h10
-rw-r--r--source/blender/blenkernel/BKE_deform.h18
-rw-r--r--source/blender/blenkernel/BKE_node_runtime.hh30
-rw-r--r--source/blender/blenkernel/BKE_paint.h18
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h8
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.cc84
-rw-r--r--source/blender/blenkernel/intern/appdir.c10
-rw-r--r--source/blender/blenkernel/intern/attribute_access.cc58
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c40
-rw-r--r--source/blender/blenkernel/intern/compute_contexts.cc38
-rw-r--r--source/blender/blenkernel/intern/cryptomatte.cc79
-rw-r--r--source/blender/blenkernel/intern/curve_catmull_rom.cc14
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc97
-rw-r--r--source/blender/blenkernel/intern/customdata.cc34
-rw-r--r--source/blender/blenkernel/intern/image_save.cc4
-rw-r--r--source/blender/blenkernel/intern/mesh.cc22
-rw-r--r--source/blender/blenkernel/intern/mesh_convert.cc11
-rw-r--r--source/blender/blenkernel/intern/mesh_legacy_convert.cc18
-rw-r--r--source/blender/blenkernel/intern/mesh_remesh_voxel.cc5
-rw-r--r--source/blender/blenkernel/intern/nla.c2
-rw-r--r--source/blender/blenkernel/intern/node.cc1
-rw-r--r--source/blender/blenkernel/intern/node_runtime.cc18
-rw-r--r--source/blender/blenkernel/intern/packedFile.c36
-rw-r--r--source/blender/blenkernel/intern/paint.cc262
-rw-r--r--source/blender/blenkernel/intern/pbvh.c27
-rw-r--r--source/blender/blenkernel/intern/pbvh_intern.h1
-rw-r--r--source/blender/blenkernel/intern/pointcloud.cc8
36 files changed, 998 insertions, 480 deletions
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 4274ca97fd1..da1e45ababd 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -141,14 +141,6 @@ struct DerivedMesh {
void (*copyLoopArray)(DerivedMesh *dm, struct MLoop *r_loop);
void (*copyPolyArray)(DerivedMesh *dm, struct MPoly *r_poly);
- /** Return a copy of all verts/edges/faces from the derived mesh
- * it is the caller's responsibility to free the returned pointer
- */
- struct MVert *(*dupVertArray)(DerivedMesh *dm);
- struct MEdge *(*dupEdgeArray)(DerivedMesh *dm);
- struct MLoop *(*dupLoopArray)(DerivedMesh *dm);
- struct MPoly *(*dupPolyArray)(DerivedMesh *dm);
-
/** Return a pointer to the entire array of vert/edge/face custom data
* from the derived mesh (this gives a pointer to the actual data, not
* a copy)
@@ -254,11 +246,6 @@ void DM_copy_vert_data(struct DerivedMesh *source,
int count);
/**
- * Sets up mpolys for a DM based on face iterators in source.
- */
-void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
-
-/**
* Ensure the array is large enough.
*
* \note This function must always be thread-protected by caller.
diff --git a/source/blender/blenkernel/BKE_attribute.hh b/source/blender/blenkernel/BKE_attribute.hh
index 4aa6c133e9e..fbdacee139c 100644
--- a/source/blender/blenkernel/BKE_attribute.hh
+++ b/source/blender/blenkernel/BKE_attribute.hh
@@ -553,6 +553,11 @@ class MutableAttributeAccessor : public AttributeAccessor {
GAttributeWriter lookup_for_write(const AttributeIDRef &attribute_id);
/**
+ * Same as above, but returns a type that makes it easier to work with the attribute as a span.
+ */
+ GSpanAttributeWriter lookup_for_write_span(const AttributeIDRef &attribute_id);
+
+ /**
* Get a writable attribute or non if it does not exist.
* Make sure to call #finish after changes are done.
*/
@@ -569,6 +574,19 @@ class MutableAttributeAccessor : public AttributeAccessor {
}
/**
+ * Same as above, but returns a type that makes it easier to work with the attribute as a span.
+ */
+ template<typename T>
+ SpanAttributeWriter<T> lookup_for_write_span(const AttributeIDRef &attribute_id)
+ {
+ AttributeWriter<T> attribute = this->lookup_for_write<T>(attribute_id);
+ if (attribute) {
+ return SpanAttributeWriter<T>{std::move(attribute), true};
+ }
+ return {};
+ }
+
+ /**
* Create a new attribute.
* \return True, when a new attribute has been created. False, when it's not possible to create
* this attribute or there is already an attribute with that id.
@@ -692,6 +710,19 @@ Vector<AttributeTransferData> retrieve_attributes_for_transfer(
eAttrDomainMask domain_mask,
const Set<std::string> &skip = {});
+/**
+ * Copy attributes for the domain based on the elementwise mask.
+ *
+ * \param mask_indices: Indexed elements to copy from the source data-block.
+ * \param domain: Attribute domain to transfer.
+ * \param skip: Named attributes to ignore/skip.
+ */
+void copy_attribute_domain(AttributeAccessor src_attributes,
+ MutableAttributeAccessor dst_attributes,
+ IndexMask selection,
+ eAttrDomain domain,
+ const Set<std::string> &skip = {});
+
bool allow_procedural_attribute_access(StringRef attribute_name);
extern const char *no_procedural_access_message;
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index 3c929857c14..2d1aca7c3c8 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -25,10 +25,6 @@ struct Mesh;
* data to not overwrite the original. */
struct DerivedMesh *CDDM_from_mesh(struct Mesh *mesh);
-/* Copies the given DerivedMesh with verts, faces & edges stored as
- * custom element data. */
-struct DerivedMesh *CDDM_copy(struct DerivedMesh *source);
-
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_compute_contexts.hh b/source/blender/blenkernel/BKE_compute_contexts.hh
new file mode 100644
index 00000000000..a8f0022f49b
--- /dev/null
+++ b/source/blender/blenkernel/BKE_compute_contexts.hh
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+/**
+ * This file implements some specific compute contexts for concepts in Blender.
+ */
+
+#include "BLI_compute_context.hh"
+
+namespace blender::bke {
+
+class ModifierComputeContext : public ComputeContext {
+ private:
+ static constexpr const char *s_static_type = "MODIFIER";
+
+ /**
+ * Use modifier name instead of something like `session_uuid` for now because:
+ * - It's more obvious that the name matches between the original and evaluated object.
+ * - We might want that the context hash is consistent between sessions in the future.
+ */
+ std::string modifier_name_;
+
+ public:
+ ModifierComputeContext(const ComputeContext *parent, std::string modifier_name);
+
+ private:
+ void print_current_in_line(std::ostream &stream) const override;
+};
+
+class NodeGroupComputeContext : public ComputeContext {
+ private:
+ static constexpr const char *s_static_type = "NODE_GROUP";
+
+ std::string node_name_;
+
+ public:
+ NodeGroupComputeContext(const ComputeContext *parent, std::string node_name);
+
+ StringRefNull node_name() const;
+
+ private:
+ void print_current_in_line(std::ostream &stream) const override;
+};
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h
index 56049ecf405..b2024f09278 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.h
+++ b/source/blender/blenkernel/BKE_cryptomatte.h
@@ -25,6 +25,8 @@ struct CryptomatteSession *BKE_cryptomatte_init(void);
struct CryptomatteSession *BKE_cryptomatte_init_from_render_result(
const struct RenderResult *render_result);
struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *scene);
+struct CryptomatteSession *BKE_cryptomatte_init_from_view_layer(
+ const struct ViewLayer *view_layer);
void BKE_cryptomatte_free(struct CryptomatteSession *session);
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name);
diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh
index cd3f8dc9f58..dd08f7b5c4f 100644
--- a/source/blender/blenkernel/BKE_cryptomatte.hh
+++ b/source/blender/blenkernel/BKE_cryptomatte.hh
@@ -12,6 +12,7 @@
#include "BKE_cryptomatte.h"
+#include "BLI_hash_mm3.h"
#include "BLI_map.hh"
#include "BLI_string_ref.hh"
@@ -54,10 +55,14 @@ struct CryptomatteHash {
uint32_t hash;
CryptomatteHash(uint32_t hash);
- CryptomatteHash(const char *name, int name_len);
- static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded);
+ CryptomatteHash(const char *name, int name_len)
+ {
+ hash = BLI_hash_mm3((const unsigned char *)name, name_len, 0);
+ }
+ static CryptomatteHash from_hex_encoded(blender::StringRef hex_encoded);
std::string hex_encoded() const;
+
/**
* Convert a cryptomatte hash to a float.
*
@@ -70,7 +75,20 @@ struct CryptomatteHash {
*
* Note that this conversion assumes to be running on a L-endian system.
*/
- float float_encoded() const;
+ float float_encoded() const
+ {
+ uint32_t mantissa = hash & ((1 << 23) - 1);
+ uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
+ exponent = MAX2(exponent, (uint32_t)1);
+ exponent = MIN2(exponent, (uint32_t)254);
+ exponent = exponent << 23;
+ uint32_t sign = (hash >> 31);
+ sign = sign << 31;
+ uint32_t float_bits = sign | exponent | mantissa;
+ float f;
+ memcpy(&f, &float_bits, sizeof(uint32_t));
+ return f;
+ }
};
struct CryptomatteLayer {
@@ -107,6 +125,8 @@ struct CryptomatteStampDataCallbackData {
const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
const CryptomatteSession &session);
+CryptomatteLayer *BKE_cryptomatte_layer_get(CryptomatteSession &session,
+ const StringRef layer_name);
struct CryptomatteSessionDeleter {
void operator()(CryptomatteSession *session)
diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh
index 4b0fc293b54..9f150c13d6e 100644
--- a/source/blender/blenkernel/BKE_curves.hh
+++ b/source/blender/blenkernel/BKE_curves.hh
@@ -22,6 +22,7 @@
#include "BLI_virtual_array.hh"
#include "BKE_attribute.hh"
+#include "BKE_attribute_math.hh"
namespace blender::bke {
@@ -162,6 +163,11 @@ class CurvesGeometry : public ::CurvesGeometry {
IndexRange curves_range() const;
/**
+ * Number of control points in the indexed curve.
+ */
+ int points_num_for_curve(const int index) const;
+
+ /**
* The index of the first point in every curve. The size of this span is one larger than the
* number of curves. Consider using #points_for_curve rather than using the offsets directly.
*/
@@ -532,6 +538,16 @@ bool segment_is_vector(Span<int8_t> handle_types_left,
int segment_index);
/**
+ * True if the Bezier curve contains polygonal segments of HandleType::BEZIER_HANDLE_VECTOR.
+ *
+ * \param num_curve_points: Number of points in the curve.
+ * \param evaluated_size: Number of evaluated points in the curve.
+ * \param cyclic: If curve is cyclic.
+ * \param resolution: Curve resolution.
+ */
+bool has_vector_handles(int num_curve_points, int64_t evaluated_size, bool cyclic, int resolution);
+
+/**
* Return true if the curve's last cyclic segment has a vector type.
* This only makes a difference in the shape of cyclic curves.
*/
@@ -693,6 +709,36 @@ void interpolate_to_evaluated(const GSpan src,
const Span<int> evaluated_offsets,
GMutableSpan dst);
+void calculate_basis(const float parameter, float r_weights[4]);
+
+/**
+ * Interpolate the control point values for the given parameter on the piecewise segment.
+ * \param a: Value associated with the first control point influencing the segment.
+ * \param d: Value associated with the fourth control point.
+ * \param parameter: Parameter in range [0, 1] to compute the interpolation for.
+ */
+template<typename T>
+T interpolate(const T &a, const T &b, const T &c, const T &d, const float parameter)
+{
+ float n[4];
+ 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;
+ }
+ else {
+ return 0.5f * (a * n[0] + b * n[1] + c * n[2] + d * n[3]);
+ }
+}
+
} // namespace catmull_rom
/** \} */
@@ -807,6 +853,16 @@ inline IndexRange CurvesGeometry::curves_range() const
return IndexRange(this->curves_num());
}
+inline int CurvesGeometry::points_num_for_curve(const int index) const
+{
+ BLI_assert(this->curve_num > 0);
+ BLI_assert(this->curve_num > index);
+ BLI_assert(this->curve_offsets != nullptr);
+ const int offset = this->curve_offsets[index];
+ const int offset_next = this->curve_offsets[index + 1];
+ return offset_next - offset;
+}
+
inline bool CurvesGeometry::is_single_type(const CurveType type) const
{
return this->curve_type_counts()[type] == this->curves_num();
@@ -833,6 +889,7 @@ inline IndexRange CurvesGeometry::points_for_curve(const int index) const
{
/* Offsets are not allocated when there are no curves. */
BLI_assert(this->curve_num > 0);
+ BLI_assert(this->curve_num > index);
BLI_assert(this->curve_offsets != nullptr);
const int offset = this->curve_offsets[index];
const int offset_next = this->curve_offsets[index + 1];
@@ -905,11 +962,13 @@ inline float CurvesGeometry::evaluated_length_total_for_curve(const int curve_in
/** \} */
+namespace curves {
+
/* -------------------------------------------------------------------- */
/** \name Bezier Inline Methods
* \{ */
-namespace curves::bezier {
+namespace bezier {
inline bool point_is_sharp(const Span<int8_t> handle_types_left,
const Span<int8_t> handle_types_right,
@@ -929,14 +988,24 @@ inline bool segment_is_vector(const int8_t left, const int8_t right)
return segment_is_vector(HandleType(left), HandleType(right));
}
+inline bool has_vector_handles(const int num_curve_points,
+ const int64_t evaluated_size,
+ const bool cyclic,
+ const int resolution)
+{
+ return evaluated_size - !cyclic != (int64_t)segments_num(num_curve_points, cyclic) * resolution;
+}
+
inline float3 calculate_vector_handle(const float3 &point, const float3 &next_point)
{
return math::interpolate(point, next_point, 1.0f / 3.0f);
}
+} // namespace bezier
+
/** \} */
-} // namespace curves::bezier
+} // namespace curves
struct CurvesSurfaceTransforms {
float4x4 curves_to_world;
diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh
index 0fbd33002e1..5579ab5654a 100644
--- a/source/blender/blenkernel/BKE_curves_utils.hh
+++ b/source/blender/blenkernel/BKE_curves_utils.hh
@@ -11,9 +11,301 @@
#include "BLI_function_ref.hh"
#include "BLI_generic_pointer.hh"
+#include "BLI_index_range.hh"
namespace blender::bke::curves {
+/* --------------------------------------------------------------------
+ * Utility structs.
+ */
+
+/**
+ * Reference to a piecewise segment on a spline curve.
+ */
+struct CurveSegment {
+ /**
+ * Index of the previous control/evaluated point on the curve. First point on the segment.
+ */
+ int index;
+ /**
+ * Index of the next control/evaluated point on the curve. Last point on the curve segment.
+ * Should be 0 for looped segments.
+ */
+ int next_index;
+};
+
+/**
+ * Reference to a point on a piecewise curve (spline).
+ *
+ * Tracks indices of the neighbouring control/evaluated point pair associated with the segment
+ * in which the point resides. Referenced point within the segment is defined by a
+ * normalized parameter in the range [0, 1].
+ */
+struct CurvePoint : public CurveSegment {
+ /**
+ * Normalized parameter in the range [0, 1] defining the point on the piecewise segment.
+ * Note that the curve point representation is not unique at segment endpoints.
+ */
+ float parameter;
+
+ /**
+ * True if the parameter is an integer and references a control/evaluated point.
+ */
+ inline bool is_controlpoint() const;
+
+ /*
+ * Compare if the points are equal.
+ */
+ inline bool operator==(const CurvePoint &other) const;
+ inline bool operator!=(const CurvePoint &other) const;
+
+ /**
+ * Compare if 'this' point comes before 'other'. Loop segment for cyclical curves counts
+ * as the first (least) segment.
+ */
+ inline bool operator<(const CurvePoint &other) const;
+};
+
+/**
+ * Cyclical index range. Iterates the interval [start, end).
+ */
+class IndexRangeCyclic {
+ /* Index to the start and end of the iterated range.
+ */
+ int64_t start_ = 0;
+ int64_t end_ = 0;
+ /* Index for the start and end of the entire iterable range which contains the iterated range
+ * (e.g. the point range for an indiviudal spline/curve within the entire Curves point domain).
+ */
+ int64_t range_start_ = 0;
+ int64_t range_end_ = 0;
+ /* Number of times the range end is passed when the range is iterated.
+ */
+ int64_t cycles_ = 0;
+
+ constexpr IndexRangeCyclic(int64_t begin,
+ int64_t end,
+ int64_t iterable_range_start,
+ int64_t iterable_range_end,
+ int64_t cycles)
+ : start_(begin),
+ end_(end),
+ range_start_(iterable_range_start),
+ range_end_(iterable_range_end),
+ cycles_(cycles)
+ {
+ }
+
+ public:
+ constexpr IndexRangeCyclic() = default;
+ ~IndexRangeCyclic() = default;
+
+ constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range, int64_t cycles)
+ : start_(start),
+ end_(end),
+ range_start_(iterable_range.first()),
+ range_end_(iterable_range.one_after_last()),
+ cycles_(cycles)
+ {
+ }
+
+ /**
+ * Create an iterator over the cyclical interval [start_index, end_index).
+ */
+ constexpr IndexRangeCyclic(int64_t start, int64_t end, IndexRange iterable_range)
+ : start_(start),
+ end_(end == iterable_range.one_after_last() ? iterable_range.first() : end),
+ range_start_(iterable_range.first()),
+ range_end_(iterable_range.one_after_last()),
+ cycles_(end < start)
+ {
+ }
+
+ /**
+ * Increment the range by adding the given number of indices to the beginning of the range.
+ */
+ constexpr IndexRangeCyclic push_forward(int n)
+ {
+ BLI_assert(n >= 0);
+ int64_t nstart = start_ - n;
+ int64_t cycles = cycles_;
+ if (nstart < range_start_) {
+
+ cycles += (int64_t)(n / (range_end_ - range_start_)) + (end_ < nstart) - (end_ < start_);
+ }
+ return {nstart, end_, range_start_, range_end_, cycles};
+ }
+ /**
+ * Increment the range by adding the given number of indices to the end of the range.
+ */
+ constexpr IndexRangeCyclic push_backward(int n)
+ {
+ BLI_assert(n >= 0);
+ int64_t new_end = end_ + n;
+ int64_t cycles = cycles_;
+ if (range_end_ <= new_end) {
+ cycles += (int64_t)(n / (range_end_ - range_start_)) + (new_end < start_) - (end_ < start_);
+ }
+ return {start_, new_end, range_start_, range_end_, cycles};
+ }
+
+ /**
+ * Get the index range for the curve buffer.
+ */
+ constexpr IndexRange curve_range() const
+ {
+ return IndexRange(range_start_, total_size());
+ }
+
+ /**
+ * Range between the first element up to the end of the range.
+ */
+ constexpr IndexRange range_before_loop() const
+ {
+ return IndexRange(start_, size_before_loop());
+ }
+
+ /**
+ * Range between the first element in the iterable range up to the last element in the range.
+ */
+ constexpr IndexRange range_after_loop() const
+ {
+ return IndexRange(range_start_, size_after_loop());
+ }
+
+ /**
+ * Size of the entire iterable range.
+ */
+ constexpr int64_t total_size() const
+ {
+ return range_end_ - range_start_;
+ }
+
+ /**
+ * Number of elements between the first element in the range up to the last element in the curve.
+ */
+ constexpr int64_t size_before_loop() const
+ {
+ return range_end_ - start_;
+ }
+
+ /**
+ * Number of elements between the first element in the iterable range up to the last element in
+ * the range.
+ */
+ constexpr int64_t size_after_loop() const
+ {
+ return end_ - range_start_;
+ }
+
+ /**
+ * Get number of elements iterated by the cyclical index range.
+ */
+ constexpr int64_t size() const
+ {
+ if (cycles_ > 0) {
+ return size_before_loop() + end_ + (cycles_ - 1) * (range_end_ - range_start_);
+ }
+ else {
+ return end_ - start_;
+ }
+ }
+
+ /**
+ * Return the number of times the iterator will cycle before ending.
+ */
+ constexpr int64_t cycles() const
+ {
+ return cycles_;
+ }
+
+ constexpr int64_t first() const
+ {
+ return start_;
+ }
+
+ constexpr int64_t one_after_last() const
+ {
+ return end_;
+ }
+
+ struct CyclicIterator; /* Forward declaration */
+
+ constexpr CyclicIterator begin() const
+ {
+ return CyclicIterator(range_start_, range_end_, start_, 0);
+ }
+
+ constexpr CyclicIterator end() const
+ {
+ return CyclicIterator(range_start_, range_end_, end_, cycles_);
+ }
+
+ struct CyclicIterator {
+ int64_t index_, begin_, end_, cycles_;
+
+ constexpr CyclicIterator(int64_t range_begin, int64_t range_end, int64_t index, int64_t cycles)
+ : index_(index), begin_(range_begin), end_(range_end), cycles_(cycles)
+ {
+ BLI_assert(range_begin <= index && index <= range_end);
+ }
+
+ constexpr CyclicIterator(const CyclicIterator &copy)
+ : index_(copy.index_), begin_(copy.begin_), end_(copy.end_), cycles_(copy.cycles_)
+ {
+ }
+ ~CyclicIterator() = default;
+
+ constexpr CyclicIterator &operator=(const CyclicIterator &copy)
+ {
+ if (this == &copy) {
+ return *this;
+ }
+ index_ = copy.index_;
+ begin_ = copy.begin_;
+ end_ = copy.end_;
+ cycles_ = copy.cycles_;
+ return *this;
+ }
+ constexpr CyclicIterator &operator++()
+ {
+ index_++;
+ if (index_ == end_) {
+ index_ = begin_;
+ cycles_++;
+ }
+ return *this;
+ }
+
+ void increment(int64_t n)
+ {
+ for (int i = 0; i < n; i++) {
+ ++*this;
+ }
+ }
+
+ constexpr const int64_t &operator*() const
+ {
+ return index_;
+ }
+
+ constexpr bool operator==(const CyclicIterator &other) const
+ {
+ return index_ == other.index_ && cycles_ == other.cycles_;
+ }
+ constexpr bool operator!=(const CyclicIterator &other) const
+ {
+ return !this->operator==(other);
+ }
+ };
+};
+
+/** \} */
+
+/* --------------------------------------------------------------------
+ * Utility functions.
+ */
+
/**
* Copy the provided point attribute values between all curves in the #curve_ranges index
* ranges, assuming that all curves have the same number of control points in #src_curves
@@ -88,4 +380,40 @@ void foreach_curve_by_type(const VArray<int8_t> &types,
FunctionRef<void(IndexMask)> bezier_fn,
FunctionRef<void(IndexMask)> nurbs_fn);
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name #CurvePoint Inline Methods
+ * \{ */
+
+inline bool CurvePoint::is_controlpoint() const
+{
+ return parameter == 0.0 || parameter == 1.0;
+}
+
+inline bool CurvePoint::operator==(const CurvePoint &other) const
+{
+ return (parameter == other.parameter && index == other.index) ||
+ (parameter == 1.0 && other.parameter == 0.0 && next_index == other.index) ||
+ (parameter == 0.0 && other.parameter == 1.0 && index == other.next_index);
+}
+inline bool CurvePoint::operator!=(const CurvePoint &other) const
+{
+ return !this->operator==(other);
+}
+
+inline bool CurvePoint::operator<(const CurvePoint &other) const
+{
+ if (index == other.index) {
+ return parameter < other.parameter;
+ }
+ else {
+ /* Use next index for cyclic comparison due to loop segment < first segment. */
+ return next_index < other.next_index &&
+ !(next_index == other.index && parameter == 1.0 && other.parameter == 0.0);
+ }
+}
+
+/** \} */
+
} // namespace blender::bke::curves
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 09d37682b3c..24fa5f0e87a 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -178,13 +178,11 @@ bool CustomData_merge_mesh_to_bmesh(const struct CustomData *source,
int totelem);
/**
- * Reallocate custom data to a new element count.
- * Only affects on data layers which are owned by the CustomData itself,
- * referenced data is kept unchanged,
- *
- * \note Take care of referenced layers by yourself!
+ * Reallocate custom data to a new element count. If the new size is larger, the new values use
+ * the #CD_CONSTRUCT behavior, so trivial types must be initialized by the caller. After being
+ * resized, the #CustomData does not contain any referenced layers.
*/
-void CustomData_realloc(struct CustomData *data, int totelem);
+void CustomData_realloc(struct CustomData *data, int old_size, int new_size);
/**
* BMesh version of CustomData_merge; merges the layouts of source and `dest`,
diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h
index 677a1053826..4023d6829d4 100644
--- a/source/blender/blenkernel/BKE_deform.h
+++ b/source/blender/blenkernel/BKE_deform.h
@@ -50,19 +50,29 @@ void BKE_defgroup_copy_list(struct ListBase *outbase, const struct ListBase *inb
struct bDeformGroup *BKE_defgroup_duplicate(const struct bDeformGroup *ingroup);
struct bDeformGroup *BKE_object_defgroup_find_name(const struct Object *ob, const char *name);
/**
- * \note caller must free.
+ * Returns flip map for the vertex-groups of `ob`.
+ *
+ * \param use_default: How to handle cases where no symmetrical group is found.
+ * - false: sets these indices to -1, indicating the group should be ignored.
+ * - true: sets the index to its location in the array (making the group point to it's self).
+ * Enable this for symmetrical actions which apply weight operations on symmetrical vertices
+ * where the symmetrical group will be used (if found), otherwise the same group is used.
+ *
+ * \return An index array `r_flip_map_num` length,
+ * (aligned with the list result from `BKE_id_defgroup_list_get(ob)`).
+ * referencing the index of the symmetrical vertex-group of a fall-back value (see `use_default`).
+ * The caller is responsible for freeing the array.
*/
int *BKE_object_defgroup_flip_map(const struct Object *ob, bool use_default, int *r_flip_map_num);
/**
- * Returns flip map for only unlocked defgroups.
- * \note caller must free.
+ * A version of #BKE_object_defgroup_flip_map that ignores locked groups.
*/
int *BKE_object_defgroup_flip_map_unlocked(const struct Object *ob,
bool use_default,
int *r_flip_map_num);
/**
- * \note caller must free.
+ * A version of #BKE_object_defgroup_flip_map that only takes a single group into account.
*/
int *BKE_object_defgroup_flip_map_single(const struct Object *ob,
bool use_default,
diff --git a/source/blender/blenkernel/BKE_node_runtime.hh b/source/blender/blenkernel/BKE_node_runtime.hh
index f2e551a9f32..194820aa4ba 100644
--- a/source/blender/blenkernel/BKE_node_runtime.hh
+++ b/source/blender/blenkernel/BKE_node_runtime.hh
@@ -21,6 +21,7 @@ struct bNodeType;
namespace blender::nodes {
struct FieldInferencingInterface;
class NodeDeclaration;
+struct GeometryNodesLazyFunctionGraphInfo;
} // namespace blender::nodes
namespace blender::bke {
@@ -49,6 +50,15 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
std::unique_ptr<nodes::FieldInferencingInterface> field_inferencing_interface;
/**
+ * For geometry nodes, a lazy function graph with some additional info is cached. This is used to
+ * evaluate the node group. Caching it here allows us to reuse the preprocessed node tree in case
+ * its used multiple times.
+ */
+ std::mutex geometry_nodes_lazy_function_graph_info_mutex;
+ std::unique_ptr<nodes::GeometryNodesLazyFunctionGraphInfo>
+ geometry_nodes_lazy_function_graph_info;
+
+ /**
* Protects access to all topology cache variables below. This is necessary so that the cache can
* be updated on a const #bNodeTree.
*/
@@ -70,6 +80,7 @@ class bNodeTreeRuntime : NonCopyable, NonMovable {
MultiValueMap<const bNodeType *, bNode *> nodes_by_type;
Vector<bNode *> toposort_left_to_right;
Vector<bNode *> toposort_right_to_left;
+ Vector<bNode *> group_nodes;
bool has_link_cycle = false;
bool has_undefined_nodes_or_sockets = false;
bNode *group_output_node = nullptr;
@@ -148,6 +159,12 @@ class bNodeRuntime : NonCopyable, NonMovable {
namespace node_tree_runtime {
+/**
+ * Is executed when the depsgraph determines that something in the node group changed that will
+ * affect the output.
+ */
+void handle_node_tree_output_changed(bNodeTree &tree_cow);
+
class AllowUsingOutdatedInfo : NonCopyable, NonMovable {
private:
const bNodeTree &tree_;
@@ -241,6 +258,18 @@ inline blender::Span<bNode *> bNodeTree::all_nodes()
return this->runtime->nodes;
}
+inline blender::Span<const bNode *> bNodeTree::group_nodes() const
+{
+ BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+ return this->runtime->group_nodes;
+}
+
+inline blender::Span<bNode *> bNodeTree::group_nodes()
+{
+ BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
+ return this->runtime->group_nodes;
+}
+
inline bool bNodeTree::has_link_cycle() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
@@ -413,7 +442,6 @@ inline blender::Span<const bNodeLink *> bNode::internal_links_span() const
inline const blender::nodes::NodeDeclaration *bNode::declaration() const
{
- BLI_assert(this->runtime->declaration != nullptr);
return this->runtime->declaration;
}
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 9a067e761d7..eef91bacc2f 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -213,9 +213,7 @@ bool BKE_paint_always_hide_test(struct Object *ob);
/**
* Returns non-zero if any of the face's vertices are hidden, zero otherwise.
*/
-bool paint_is_face_hidden(const struct MLoopTri *lt,
- const bool *hide_vert,
- const struct MLoop *mloop);
+bool paint_is_face_hidden(const struct MLoopTri *lt, const bool *hide_poly);
/**
* Returns non-zero if any of the corners of the grid
* face whose inner corner is at (x, y) are hidden, zero otherwise.
@@ -689,7 +687,7 @@ void BKE_sculpt_update_object_for_edit(struct Depsgraph *depsgraph,
bool need_pmap,
bool need_mask,
bool is_paint_tool);
-void BKE_sculpt_update_object_before_eval(const struct Scene *scene, struct Object *ob_eval);
+void BKE_sculpt_update_object_before_eval(struct Object *ob_eval);
void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Object *ob_eval);
/**
@@ -698,6 +696,7 @@ void BKE_sculpt_update_object_after_eval(struct Depsgraph *depsgraph, struct Obj
*/
struct MultiresModifierData *BKE_sculpt_multires_active(const struct Scene *scene,
struct Object *ob);
+int *BKE_sculpt_face_sets_ensure(struct Mesh *mesh);
int BKE_sculpt_mask_layers_ensure(struct Object *ob, struct MultiresModifierData *mmd);
void BKE_sculpt_toolsettings_data_ensure(struct Scene *scene);
@@ -719,18 +718,17 @@ void BKE_sculpt_sync_face_sets_visibility_to_grids(struct Mesh *mesh,
struct SubdivCCG *subdiv_ccg);
/**
- * Ensures that a Face Set data-layers exists. If it does not, it creates one respecting the
- * visibility stored in the vertices of the mesh. If it does, it copies the visibility from the
- * mesh to the Face Sets. */
-void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(struct Mesh *mesh);
+ * If a face set layer exists, initialize its visibility (sign) from the mesh's hidden values.
+ */
+void BKE_sculpt_face_sets_update_from_base_mesh_visibility(struct Mesh *mesh);
/**
- * Ensures we do have expected mesh data in original mesh for the sculpt mode.
+ * Makes sculpt data consistent with other data on the mesh.
*
* \note IDs are expected to be original ones here, and calling code should ensure it updates its
* depsgraph properly after calling this function if it needs up-to-date evaluated data.
*/
-void BKE_sculpt_ensure_orig_mesh_data(struct Scene *scene, struct Object *object);
+void BKE_sculpt_ensure_orig_mesh_data(struct Object *object);
/**
* Test if PBVH can be used directly for drawing, which is faster than
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 716ee7d2a21..6a194698bd8 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -491,6 +491,12 @@ void BKE_pbvh_grids_update(PBVH *pbvh,
void BKE_pbvh_subdiv_cgg_set(PBVH *pbvh, struct SubdivCCG *subdiv_ccg);
void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets);
+/**
+ * If an operation causes the hide status stored in the mesh to change, this must be called
+ * to update the references to those attributes, since they are only added when necessary.
+ */
+void BKE_pbvh_update_hide_attributes_from_mesh(PBVH *pbvh);
+
void BKE_pbvh_face_sets_color_set(PBVH *pbvh, int seed, int color_default);
void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide);
@@ -674,6 +680,8 @@ const float (*BKE_pbvh_get_vert_normals(const PBVH *pbvh))[3];
const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh);
bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh);
+const bool *BKE_pbvh_get_poly_hide(const PBVH *pbvh);
+
PBVHColorBufferNode *BKE_pbvh_node_color_buffer_get(PBVHNode *node);
void BKE_pbvh_node_color_buffer_free(PBVH *pbvh);
bool BKE_pbvh_get_color_layer(const struct Mesh *me,
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index b982c69a378..2f1e1897f8d 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -98,6 +98,7 @@ set(SRC
intern/collision.c
intern/colorband.c
intern/colortools.c
+ intern/compute_contexts.cc
intern/constraint.c
intern/context.c
intern/crazyspace.cc
@@ -352,6 +353,7 @@ set(SRC
BKE_collision.h
BKE_colorband.h
BKE_colortools.h
+ BKE_compute_contexts.hh
BKE_constraint.h
BKE_context.h
BKE_crazyspace.h
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index 0036ed1cf61..d7db0ad765c 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -147,54 +147,6 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm)
return mpoly;
}
-static MVert *dm_dupVertArray(DerivedMesh *dm)
-{
- MVert *tmp = (MVert *)MEM_malloc_arrayN(
- dm->getNumVerts(dm), sizeof(*tmp), "dm_dupVertArray tmp");
-
- if (tmp) {
- dm->copyVertArray(dm, tmp);
- }
-
- return tmp;
-}
-
-static MEdge *dm_dupEdgeArray(DerivedMesh *dm)
-{
- MEdge *tmp = (MEdge *)MEM_malloc_arrayN(
- dm->getNumEdges(dm), sizeof(*tmp), "dm_dupEdgeArray tmp");
-
- if (tmp) {
- dm->copyEdgeArray(dm, tmp);
- }
-
- return tmp;
-}
-
-static MLoop *dm_dupLoopArray(DerivedMesh *dm)
-{
- MLoop *tmp = (MLoop *)MEM_malloc_arrayN(
- dm->getNumLoops(dm), sizeof(*tmp), "dm_dupLoopArray tmp");
-
- if (tmp) {
- dm->copyLoopArray(dm, tmp);
- }
-
- return tmp;
-}
-
-static MPoly *dm_dupPolyArray(DerivedMesh *dm)
-{
- MPoly *tmp = (MPoly *)MEM_malloc_arrayN(
- dm->getNumPolys(dm), sizeof(*tmp), "dm_dupPolyArray tmp");
-
- if (tmp) {
- dm->copyPolyArray(dm, tmp);
- }
-
- return tmp;
-}
-
static int dm_getNumLoopTri(DerivedMesh *dm)
{
const int numlooptris = poly_to_tri_count(dm->getNumPolys(dm), dm->getNumLoops(dm));
@@ -233,10 +185,6 @@ void DM_init_funcs(DerivedMesh *dm)
dm->getEdgeArray = dm_getEdgeArray;
dm->getLoopArray = dm_getLoopArray;
dm->getPolyArray = dm_getPolyArray;
- dm->dupVertArray = dm_dupVertArray;
- dm->dupEdgeArray = dm_dupEdgeArray;
- dm->dupLoopArray = dm_dupLoopArray;
- dm->dupPolyArray = dm_dupPolyArray;
dm->getLoopTriArray = dm_getLoopTriArray;
@@ -331,36 +279,6 @@ bool DM_release(DerivedMesh *dm)
return false;
}
-void DM_DupPolys(DerivedMesh *source, DerivedMesh *target)
-{
- CustomData_free(&target->loopData, source->numLoopData);
- CustomData_free(&target->polyData, source->numPolyData);
-
- CustomData_copy(&source->loopData,
- &target->loopData,
- CD_MASK_DERIVEDMESH.lmask,
- CD_DUPLICATE,
- source->numLoopData);
- CustomData_copy(&source->polyData,
- &target->polyData,
- CD_MASK_DERIVEDMESH.pmask,
- CD_DUPLICATE,
- source->numPolyData);
-
- target->numLoopData = source->numLoopData;
- target->numPolyData = source->numPolyData;
-
- if (!CustomData_has_layer(&target->polyData, CD_MPOLY)) {
- MPoly *mpoly;
- MLoop *mloop;
-
- mloop = source->dupLoopArray(source);
- mpoly = source->dupPolyArray(source);
- CustomData_add_layer(&target->loopData, CD_MLOOP, CD_ASSIGN, mloop, source->numLoopData);
- CustomData_add_layer(&target->polyData, CD_MPOLY, CD_ASSIGN, mpoly, source->numPolyData);
- }
-}
-
void DM_ensure_looptri_data(DerivedMesh *dm)
{
const unsigned int totpoly = dm->numPolyData;
@@ -1802,7 +1720,7 @@ void makeDerivedMesh(struct Depsgraph *depsgraph,
BKE_object_free_derived_caches(ob);
if (DEG_is_active(depsgraph)) {
- BKE_sculpt_update_object_before_eval(scene, ob);
+ BKE_sculpt_update_object_before_eval(ob);
}
/* NOTE: Access the `edit_mesh` after freeing the derived caches, so that `ob->data` is restored
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 24e4305d916..96ac81fdb63 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -371,14 +371,16 @@ static bool get_path_local_ex(char *targetpath,
relfolder[0] = '\0';
}
- /* Try `{g_app.program_dirname}/2.xx/{folder_name}` the default directory
+ /* Try `{g_app.program_dirname}/3.xx/{folder_name}` the default directory
* for a portable distribution. See `WITH_INSTALL_PORTABLE` build-option. */
const char *path_base = g_app.program_dirname;
#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE)
/* Due new code-sign situation in OSX > 10.9.5
- * we must move the blender_version dir with contents to Resources. */
- char osx_resourses[FILE_MAX];
- BLI_snprintf(osx_resourses, sizeof(osx_resourses), "%s../Resources", g_app.program_dirname);
+ * we must move the blender_version dir with contents to Resources.
+ * Add 4 + 9 for the temporary `/../` path & `Resources`. */
+ char osx_resourses[FILE_MAX + 4 + 9];
+ BLI_path_join(
+ osx_resourses, sizeof(osx_resourses), g_app.program_dirname, "..", "Resources", NULL);
/* Remove the '/../' added above. */
BLI_path_normalize(NULL, osx_resourses);
path_base = osx_resourses;
diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc
index 6ca3a286a5e..1e237da8119 100644
--- a/source/blender/blenkernel/intern/attribute_access.cc
+++ b/source/blender/blenkernel/intern/attribute_access.cc
@@ -14,6 +14,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
+#include "BLI_array_utils.hh"
#include "BLI_color.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
@@ -726,8 +727,22 @@ bool CustomDataAttributes::remove(const AttributeIDRef &attribute_id)
void CustomDataAttributes::reallocate(const int size)
{
+ const int old_size = size_;
size_ = size;
- CustomData_realloc(&data, size);
+ CustomData_realloc(&data, old_size, size_);
+ if (size_ > old_size) {
+ /* Fill default new values. */
+ const int new_elements_num = size_ - old_size;
+ this->foreach_attribute(
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData /*meta_data*/) {
+ GMutableSpan new_data = this->get_for_write(id)->take_back(new_elements_num);
+ const CPPType &type = new_data.type();
+ type.fill_assign_n(type.default_value(), new_data.data(), new_data.size());
+ return true;
+ },
+ /* Dummy. */
+ ATTR_DOMAIN_POINT);
+ }
}
void CustomDataAttributes::clear()
@@ -875,6 +890,16 @@ GAttributeWriter MutableAttributeAccessor::lookup_for_write(const AttributeIDRef
return attribute;
}
+GSpanAttributeWriter MutableAttributeAccessor::lookup_for_write_span(
+ const AttributeIDRef &attribute_id)
+{
+ GAttributeWriter attribute = this->lookup_for_write(attribute_id);
+ if (attribute) {
+ return GSpanAttributeWriter{std::move(attribute), true};
+ }
+ return {};
+}
+
GAttributeWriter MutableAttributeAccessor::lookup_or_add_for_write(
const AttributeIDRef &attribute_id,
const eAttrDomain domain,
@@ -950,6 +975,37 @@ Vector<AttributeTransferData> retrieve_attributes_for_transfer(
return attributes;
}
+void copy_attribute_domain(const AttributeAccessor src_attributes,
+ MutableAttributeAccessor dst_attributes,
+ const IndexMask selection,
+ const eAttrDomain domain,
+ const Set<std::string> &skip)
+{
+ src_attributes.for_all(
+ [&](const bke::AttributeIDRef &id, const bke::AttributeMetaData &meta_data) {
+ if (meta_data.domain != domain) {
+ return true;
+ }
+ if (id.is_named() && skip.contains(id.name())) {
+ return true;
+ }
+ if (!id.should_be_kept()) {
+ return true;
+ }
+
+ const GVArray src = src_attributes.lookup(id, meta_data.domain);
+ BLI_assert(src);
+
+ /* Copy attribute. */
+ GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
+ id, domain, meta_data.data_type);
+ array_utils::copy(src, selection, dst.span);
+ dst.finish();
+
+ return true;
+ });
+}
+
} // namespace blender::bke
/** \} */
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 93286751f92..0261b2d7674 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -244,43 +244,3 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh)
{
return cdDM_from_mesh_ex(mesh, CD_REFERENCE, &CD_MASK_MESH);
}
-
-DerivedMesh *CDDM_copy(DerivedMesh *source)
-{
- CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
- DerivedMesh *dm = &cddm->dm;
- int numVerts = source->numVertData;
- int numEdges = source->numEdgeData;
- int numTessFaces = 0;
- int numLoops = source->numLoopData;
- int numPolys = source->numPolyData;
-
- /* NOTE: Don't copy tessellation faces if not requested explicitly. */
-
- /* ensure these are created if they are made on demand */
- source->getVertDataArray(source, CD_ORIGINDEX);
- source->getEdgeDataArray(source, CD_ORIGINDEX);
- source->getPolyDataArray(source, CD_ORIGINDEX);
-
- /* this initializes dm, and copies all non mvert/medge/mface layers */
- DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, numLoops, numPolys);
- dm->deformedOnly = source->deformedOnly;
- dm->cd_flag = source->cd_flag;
-
- CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
- CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges);
-
- /* now add mvert/medge/mface layers */
- cddm->mvert = source->dupVertArray(source);
- cddm->medge = source->dupEdgeArray(source);
-
- CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
- CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
-
- DM_DupPolys(source, dm);
-
- cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
- cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
-
- return dm;
-}
diff --git a/source/blender/blenkernel/intern/compute_contexts.cc b/source/blender/blenkernel/intern/compute_contexts.cc
new file mode 100644
index 00000000000..026706d363e
--- /dev/null
+++ b/source/blender/blenkernel/intern/compute_contexts.cc
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "BKE_compute_contexts.hh"
+
+namespace blender::bke {
+
+ModifierComputeContext::ModifierComputeContext(const ComputeContext *parent,
+ std::string modifier_name)
+ : ComputeContext(s_static_type, parent), modifier_name_(std::move(modifier_name))
+{
+ hash_.mix_in(s_static_type, strlen(s_static_type));
+ hash_.mix_in(modifier_name_.data(), modifier_name_.size());
+}
+
+void ModifierComputeContext::print_current_in_line(std::ostream &stream) const
+{
+ stream << "Modifier: " << modifier_name_;
+}
+
+NodeGroupComputeContext::NodeGroupComputeContext(const ComputeContext *parent,
+ std::string node_name)
+ : ComputeContext(s_static_type, parent), node_name_(std::move(node_name))
+{
+ hash_.mix_in(s_static_type, strlen(s_static_type));
+ hash_.mix_in(node_name_.data(), node_name_.size());
+}
+
+StringRefNull NodeGroupComputeContext::node_name() const
+{
+ return node_name_;
+}
+
+void NodeGroupComputeContext::print_current_in_line(std::ostream &stream) const
+{
+ stream << "Node: " << node_name_;
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc
index 102bda0f2b6..72204f6624e 100644
--- a/source/blender/blenkernel/intern/cryptomatte.cc
+++ b/source/blender/blenkernel/intern/cryptomatte.cc
@@ -41,7 +41,9 @@ struct CryptomatteSession {
CryptomatteSession() = default;
CryptomatteSession(const Main *bmain);
CryptomatteSession(StampData *stamp_data);
+ CryptomatteSession(const ViewLayer *view_layer);
CryptomatteSession(const Scene *scene);
+ void init(const ViewLayer *view_layer);
blender::bke::cryptomatte::CryptomatteLayer &add_layer(std::string layer_name);
std::optional<std::string> operator[](float encoded_hash) const;
@@ -54,13 +56,15 @@ struct CryptomatteSession {
CryptomatteSession::CryptomatteSession(const Main *bmain)
{
if (!BLI_listbase_is_empty(&bmain->objects)) {
- blender::bke::cryptomatte::CryptomatteLayer &objects = add_layer("CryptoObject");
+ blender::bke::cryptomatte::CryptomatteLayer &objects = add_layer(
+ RE_PASSNAME_CRYPTOMATTE_OBJECT);
LISTBASE_FOREACH (ID *, id, &bmain->objects) {
objects.add_ID(*id);
}
}
if (!BLI_listbase_is_empty(&bmain->materials)) {
- blender::bke::cryptomatte::CryptomatteLayer &materials = add_layer("CryptoMaterial");
+ blender::bke::cryptomatte::CryptomatteLayer &materials = add_layer(
+ RE_PASSNAME_CRYPTOMATTE_MATERIAL);
LISTBASE_FOREACH (ID *, id, &bmain->materials) {
materials.add_ID(*id);
}
@@ -83,24 +87,34 @@ CryptomatteSession::CryptomatteSession(StampData *stamp_data)
false);
}
+CryptomatteSession::CryptomatteSession(const ViewLayer *view_layer)
+{
+ init(view_layer);
+}
+
CryptomatteSession::CryptomatteSession(const Scene *scene)
{
- LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) {
- eViewLayerCryptomatteFlags cryptoflags = static_cast<eViewLayerCryptomatteFlags>(
- view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ALL);
- if (cryptoflags == 0) {
- cryptoflags = static_cast<eViewLayerCryptomatteFlags>(VIEW_LAYER_CRYPTOMATTE_ALL);
- }
+ LISTBASE_FOREACH (const ViewLayer *, view_layer, &scene->view_layers) {
+ init(view_layer);
+ }
+}
- if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
- add_layer(blender::StringRefNull(view_layer->name) + ".CryptoObject");
- }
- if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
- add_layer(blender::StringRefNull(view_layer->name) + ".CryptoAsset");
- }
- if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
- add_layer(blender::StringRefNull(view_layer->name) + ".CryptoMaterial");
- }
+void CryptomatteSession::init(const ViewLayer *view_layer)
+{
+ eViewLayerCryptomatteFlags cryptoflags = static_cast<eViewLayerCryptomatteFlags>(
+ view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ALL);
+ if (cryptoflags == 0) {
+ cryptoflags = static_cast<eViewLayerCryptomatteFlags>(VIEW_LAYER_CRYPTOMATTE_ALL);
+ }
+
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_OBJECT) {
+ add_layer(blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_OBJECT);
+ }
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_ASSET) {
+ add_layer(blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_ASSET);
+ }
+ if (cryptoflags & VIEW_LAYER_CRYPTOMATTE_MATERIAL) {
+ add_layer(blender::StringRefNull(view_layer->name) + "." + RE_PASSNAME_CRYPTOMATTE_MATERIAL);
}
}
@@ -142,6 +156,12 @@ struct CryptomatteSession *BKE_cryptomatte_init_from_scene(const struct Scene *s
return session;
}
+struct CryptomatteSession *BKE_cryptomatte_init_from_view_layer(const struct ViewLayer *view_layer)
+{
+ CryptomatteSession *session = new CryptomatteSession(view_layer);
+ return session;
+}
+
void BKE_cryptomatte_add_layer(struct CryptomatteSession *session, const char *layer_name)
{
session->add_layer(layer_name);
@@ -485,11 +505,6 @@ CryptomatteHash::CryptomatteHash(uint32_t hash) : hash(hash)
{
}
-CryptomatteHash::CryptomatteHash(const char *name, const int name_len)
-{
- hash = BLI_hash_mm3((const unsigned char *)name, name_len, 0);
-}
-
CryptomatteHash CryptomatteHash::from_hex_encoded(blender::StringRef hex_encoded)
{
CryptomatteHash result(0);
@@ -504,21 +519,6 @@ std::string CryptomatteHash::hex_encoded() const
return encoded.str();
}
-float CryptomatteHash::float_encoded() const
-{
- uint32_t mantissa = hash & ((1 << 23) - 1);
- uint32_t exponent = (hash >> 23) & ((1 << 8) - 1);
- exponent = MAX2(exponent, (uint32_t)1);
- exponent = MIN2(exponent, (uint32_t)254);
- exponent = exponent << 23;
- uint32_t sign = (hash >> 31);
- sign = sign << 31;
- uint32_t float_bits = sign | exponent | mantissa;
- float f;
- memcpy(&f, &float_bits, sizeof(uint32_t));
- return f;
-}
-
std::unique_ptr<CryptomatteLayer> CryptomatteLayer::read_from_manifest(
blender::StringRefNull manifest)
{
@@ -625,4 +625,9 @@ const blender::Vector<std::string> &BKE_cryptomatte_layer_names_get(
return session.layer_names;
}
+CryptomatteLayer *BKE_cryptomatte_layer_get(CryptomatteSession &session, StringRef layer_name)
+{
+ return session.layers.lookup_ptr(layer_name);
+}
+
} // namespace blender::bke::cryptomatte
diff --git a/source/blender/blenkernel/intern/curve_catmull_rom.cc b/source/blender/blenkernel/intern/curve_catmull_rom.cc
index 952d59edcf9..dac88948036 100644
--- a/source/blender/blenkernel/intern/curve_catmull_rom.cc
+++ b/source/blender/blenkernel/intern/curve_catmull_rom.cc
@@ -17,16 +17,14 @@ int calculate_evaluated_num(const int points_num, const bool cyclic, const int r
}
/* Adapted from Cycles #catmull_rom_basis_eval function. */
-template<typename T>
-static T calculate_basis(const T &a, const T &b, const T &c, const T &d, const float parameter)
+void calculate_basis(const float parameter, float r_weights[4])
{
const float t = parameter;
const float s = 1.0f - parameter;
- const float n0 = -t * s * s;
- const float n1 = 2.0f + t * t * (3.0f * t - 5.0f);
- const float n2 = 2.0f + s * s * (3.0f * s - 5.0f);
- const float n3 = -s * t * t;
- return 0.5f * (a * n0 + b * n1 + c * n2 + d * n3);
+ r_weights[0] = -t * s * s;
+ r_weights[1] = 2.0f + t * t * (3.0f * t - 5.0f);
+ r_weights[2] = 2.0f + s * s * (3.0f * s - 5.0f);
+ r_weights[3] = -s * t * t;
}
template<typename T>
@@ -35,7 +33,7 @@ static void evaluate_segment(const T &a, const T &b, const T &c, const T &d, Mut
const float step = 1.0f / dst.size();
dst.first() = b;
for (const int i : dst.index_range().drop_front(1)) {
- dst[i] = calculate_basis<T>(a, b, c, d, i * step);
+ dst[i] = interpolate<T>(a, b, c, d, i * step);
}
}
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index 35b209179d3..06789e34ad4 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -963,11 +963,11 @@ void CurvesGeometry::ensure_can_interpolate_to_evaluated() const
void CurvesGeometry::resize(const int points_num, const int curves_num)
{
if (points_num != this->point_num) {
- CustomData_realloc(&this->point_data, points_num);
+ CustomData_realloc(&this->point_data, this->points_num(), points_num);
this->point_num = points_num;
}
if (curves_num != this->curve_num) {
- CustomData_realloc(&this->curve_data, curves_num);
+ CustomData_realloc(&this->curve_data, this->curves_num(), curves_num);
this->curve_num = curves_num;
this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curves_num + 1));
}
@@ -1380,69 +1380,49 @@ static void reverse_swap_curve_point_data(const CurvesGeometry &curves,
});
}
-static bool layer_matches_name_and_type(const CustomDataLayer &layer,
- const StringRef name,
- const eCustomDataType type)
-{
- if (layer.type != type) {
- return false;
- }
- return layer.name == name;
-}
-
void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
{
- CustomData_duplicate_referenced_layers(&this->point_data, this->points_num());
+ Set<StringRef> bezier_handle_names{{ATTR_HANDLE_POSITION_LEFT,
+ ATTR_HANDLE_POSITION_RIGHT,
+ ATTR_HANDLE_TYPE_LEFT,
+ ATTR_HANDLE_TYPE_RIGHT}};
- /* Collect the Bezier handle attributes while iterating through the point custom data layers;
- * they need special treatment later. */
- MutableSpan<float3> positions_left;
- MutableSpan<float3> positions_right;
- MutableSpan<int8_t> types_left;
- MutableSpan<int8_t> types_right;
+ MutableAttributeAccessor attributes = this->attributes_for_write();
- for (const int layer_i : IndexRange(this->point_data.totlayer)) {
- CustomDataLayer &layer = this->point_data.layers[layer_i];
-
- if (positions_left.is_empty() &&
- layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_LEFT, CD_PROP_FLOAT3)) {
- positions_left = {static_cast<float3 *>(layer.data), this->points_num()};
- continue;
- }
- if (positions_right.is_empty() &&
- layer_matches_name_and_type(layer, ATTR_HANDLE_POSITION_RIGHT, CD_PROP_FLOAT3)) {
- positions_right = {static_cast<float3 *>(layer.data), this->points_num()};
- continue;
- }
- if (types_left.is_empty() &&
- layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_LEFT, CD_PROP_INT8)) {
- types_left = {static_cast<int8_t *>(layer.data), this->points_num()};
- continue;
+ attributes.for_all([&](const AttributeIDRef &id, AttributeMetaData meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_POINT) {
+ return true;
}
- if (types_right.is_empty() &&
- layer_matches_name_and_type(layer, ATTR_HANDLE_TYPE_RIGHT, CD_PROP_INT8)) {
- types_right = {static_cast<int8_t *>(layer.data), this->points_num()};
- continue;
+ if (id.is_named() && bezier_handle_names.contains(id.name())) {
+ return true;
}
- const eCustomDataType data_type = static_cast<eCustomDataType>(layer.type);
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
+ attribute_math::convert_to_static_type(attribute.span.type(), [&](auto dummy) {
using T = decltype(dummy);
- reverse_curve_point_data<T>(
- *this, curves_to_reverse, {static_cast<T *>(layer.data), this->points_num()});
+ reverse_curve_point_data<T>(*this, curves_to_reverse, attribute.span.typed<T>());
});
- }
+ attribute.finish();
+ return true;
+ });
/* In order to maintain the shape of Bezier curves, handle attributes must reverse, but also the
* values for the left and right must swap. Use a utility to swap and reverse at the same time,
* to avoid loading the attribute twice. Generally we can expect the right layer to exist when
* the left does, but there's no need to count on it, so check for both attributes. */
- if (!positions_left.is_empty() && !positions_right.is_empty()) {
- reverse_swap_curve_point_data(*this, curves_to_reverse, positions_left, positions_right);
+ if (attributes.contains(ATTR_HANDLE_POSITION_LEFT) &&
+ attributes.contains(ATTR_HANDLE_POSITION_RIGHT)) {
+ reverse_swap_curve_point_data(*this,
+ curves_to_reverse,
+ this->handle_positions_left_for_write(),
+ this->handle_positions_right_for_write());
}
- if (!types_left.is_empty() && !types_right.is_empty()) {
- reverse_swap_curve_point_data(*this, curves_to_reverse, types_left, types_right);
+ if (attributes.contains(ATTR_HANDLE_TYPE_LEFT) && attributes.contains(ATTR_HANDLE_TYPE_RIGHT)) {
+ reverse_swap_curve_point_data(*this,
+ curves_to_reverse,
+ this->handle_types_left_for_write(),
+ this->handle_types_right_for_write());
}
this->tag_topology_changed();
@@ -1450,21 +1430,20 @@ void CurvesGeometry::reverse_curves(const IndexMask curves_to_reverse)
void CurvesGeometry::remove_attributes_based_on_types()
{
- const int points_num = this->points_num();
- const int curves_num = this->curves_num();
+ MutableAttributeAccessor attributes = this->attributes_for_write();
if (!this->has_curve_with_type(CURVE_TYPE_BEZIER)) {
- CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_LEFT.c_str(), points_num);
- CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_TYPE_RIGHT.c_str(), points_num);
- CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_LEFT.c_str(), points_num);
- CustomData_free_layer_named(&this->point_data, ATTR_HANDLE_POSITION_RIGHT.c_str(), points_num);
+ attributes.remove(ATTR_HANDLE_TYPE_LEFT);
+ attributes.remove(ATTR_HANDLE_TYPE_RIGHT);
+ attributes.remove(ATTR_HANDLE_POSITION_LEFT);
+ attributes.remove(ATTR_HANDLE_POSITION_RIGHT);
}
if (!this->has_curve_with_type(CURVE_TYPE_NURBS)) {
- CustomData_free_layer_named(&this->point_data, ATTR_NURBS_WEIGHT.c_str(), points_num);
- CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_ORDER.c_str(), curves_num);
- CustomData_free_layer_named(&this->curve_data, ATTR_NURBS_KNOTS_MODE.c_str(), curves_num);
+ attributes.remove(ATTR_NURBS_WEIGHT);
+ attributes.remove(ATTR_NURBS_ORDER);
+ attributes.remove(ATTR_NURBS_KNOTS_MODE);
}
if (!this->has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_CATMULL_ROM, CURVE_TYPE_NURBS})) {
- CustomData_free_layer_named(&this->curve_data, ATTR_RESOLUTION.c_str(), curves_num);
+ attributes.remove(ATTR_RESOLUTION);
}
}
diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc
index 24373053896..82a1a2aa8f6 100644
--- a/source/blender/blenkernel/intern/customdata.cc
+++ b/source/blender/blenkernel/intern/customdata.cc
@@ -2408,19 +2408,37 @@ bool CustomData_merge_mesh_to_bmesh(const CustomData *source,
return result;
}
-void CustomData_realloc(CustomData *data, const int totelem)
+void CustomData_realloc(CustomData *data, const int old_size, const int new_size)
{
- BLI_assert(totelem >= 0);
+ BLI_assert(new_size >= 0);
for (int i = 0; i < data->totlayer; i++) {
CustomDataLayer *layer = &data->layers[i];
- const LayerTypeInfo *typeInfo;
+ const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type);
+
+ const int64_t old_size_in_bytes = int64_t(old_size) * typeInfo->size;
+ const int64_t new_size_in_bytes = int64_t(new_size) * typeInfo->size;
if (layer->flag & CD_FLAG_NOFREE) {
- continue;
+ const void *old_data = layer->data;
+ layer->data = MEM_malloc_arrayN(new_size, typeInfo->size, __func__);
+ if (typeInfo->copy) {
+ typeInfo->copy(old_data, layer->data, std::min(old_size, new_size));
+ }
+ else {
+ std::memcpy(layer->data, old_data, std::min(old_size_in_bytes, new_size_in_bytes));
+ }
+ layer->flag &= ~CD_FLAG_NOFREE;
+ }
+ else {
+ layer->data = MEM_reallocN(layer->data, new_size_in_bytes);
+ }
+
+ if (new_size > old_size) {
+ /* Initialize new values for non-trivial types. */
+ if (typeInfo->construct) {
+ const int new_elements_num = new_size - old_size;
+ typeInfo->construct(POINTER_OFFSET(layer->data, old_size_in_bytes), new_elements_num);
+ }
}
- typeInfo = layerType_getInfo(layer->type);
- /* Use calloc to avoid the need to manually initialize new data in layers.
- * Useful for types like #MDeformVert which contain a pointer. */
- layer->data = MEM_recallocN(layer->data, (size_t)totelem * typeInfo->size);
}
}
diff --git a/source/blender/blenkernel/intern/image_save.cc b/source/blender/blenkernel/intern/image_save.cc
index e65a94d5301..6f62ee123cb 100644
--- a/source/blender/blenkernel/intern/image_save.cc
+++ b/source/blender/blenkernel/intern/image_save.cc
@@ -175,12 +175,12 @@ bool BKE_image_save_options_init(ImageSaveOptions *opts,
BLI_strncpy(opts->filepath, G.ima, sizeof(opts->filepath));
}
else {
- BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", DATA_("untitled"));
+ BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", DATA_("untitled"), nullptr);
BLI_path_abs(opts->filepath, BKE_main_blendfile_path(bmain));
}
}
else {
- BLI_snprintf(opts->filepath, sizeof(opts->filepath), "//%s", ima->id.name + 2);
+ BLI_path_join(opts->filepath, sizeof(opts->filepath), "//", ima->id.name + 2, nullptr);
BLI_path_make_safe(opts->filepath);
BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain));
}
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index a0548b7efd4..6bf25da5ae7 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -1416,19 +1416,15 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len)
}
else {
MutableAttributeAccessor attributes = me->attributes_for_write();
- AttributeWriter<int> material_indices = attributes.lookup_for_write<int>("material_index");
+ SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_span<int>(
+ "material_index", ATTR_DOMAIN_FACE);
if (!material_indices) {
return;
}
- if (material_indices.domain != ATTR_DOMAIN_FACE) {
- BLI_assert_unreachable();
- return;
- }
- MutableVArraySpan<int> indices_span(material_indices.varray);
- for (const int i : indices_span.index_range()) {
- MAT_NR_REMAP(indices_span[i]);
+ for (const int i : material_indices.span.index_range()) {
+ MAT_NR_REMAP(material_indices.span[i]);
}
- indices_span.save();
+ material_indices.span.save();
material_indices.finish();
}
@@ -1616,14 +1612,14 @@ void BKE_mesh_do_versions_cd_flag_init(Mesh *mesh)
const Span<MEdge> edges = mesh->edges();
for (const MVert &vert : verts) {
- if (vert.bweight != 0) {
+ if (vert.bweight_legacy != 0) {
mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
break;
}
}
for (const MEdge &edge : edges) {
- if (edge.bweight != 0) {
+ if (edge.bweight_legacy != 0) {
mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) {
break;
@@ -2095,11 +2091,11 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
const bool do_edges = (num_new_edges > 0);
/* Reallocate all vert and edge related data. */
+ CustomData_realloc(&mesh->vdata, mesh->totvert, mesh->totvert + num_new_verts);
mesh->totvert += num_new_verts;
- CustomData_realloc(&mesh->vdata, mesh->totvert);
if (do_edges) {
+ CustomData_realloc(&mesh->edata, mesh->totedge, mesh->totedge + num_new_edges);
mesh->totedge += num_new_edges;
- CustomData_realloc(&mesh->edata, mesh->totedge);
}
/* Update normals manually to avoid recalculation after this operation. */
diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc
index b7d8972aa7b..e56df0e3fe3 100644
--- a/source/blender/blenkernel/intern/mesh_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_convert.cc
@@ -105,8 +105,9 @@ static void make_edges_mdata_extend(Mesh &mesh)
#endif
if (totedge_new) {
- CustomData_realloc(&mesh.edata, totedge + totedge_new);
-
+ /* The only layer should be edges, so no other layers need to be initialized. */
+ BLI_assert(mesh.edata.totlayer == 1);
+ CustomData_realloc(&mesh.edata, totedge, totedge + totedge_new);
mesh.totedge += totedge_new;
MutableSpan<MEdge> edges = mesh.edges_for_write();
MEdge *medge = &edges[totedge];
@@ -634,9 +635,11 @@ void BKE_pointcloud_from_mesh(Mesh *me, PointCloud *pointcloud)
using namespace blender;
BLI_assert(me != nullptr);
-
+ /* The pointcloud should only contain the position attribute, otherwise more attributes would
+ * need to be initialized below. */
+ BLI_assert(pointcloud->attributes().all_ids().size() == 1);
+ CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint, me->totvert);
pointcloud->totpoint = me->totvert;
- CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
/* Copy over all attributes. */
CustomData_merge(&me->vdata, &pointcloud->pdata, CD_MASK_PROP_ALL, CD_DUPLICATE, me->totvert);
diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc
index 10fc8ff3195..627c0057a28 100644
--- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc
+++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc
@@ -929,13 +929,13 @@ void BKE_mesh_legacy_bevel_weight_from_layers(Mesh *mesh)
CustomData_get_layer(&mesh->vdata, CD_BWEIGHT))) {
mesh->cd_flag |= ME_CDFLAG_VERT_BWEIGHT;
for (const int i : verts.index_range()) {
- verts[i].bweight = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f;
+ verts[i].bweight_legacy = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f;
}
}
else {
mesh->cd_flag &= ~ME_CDFLAG_VERT_BWEIGHT;
for (const int i : verts.index_range()) {
- verts[i].bweight = 0;
+ verts[i].bweight_legacy = 0;
}
}
MutableSpan<MEdge> edges = mesh->edges_for_write();
@@ -943,13 +943,13 @@ void BKE_mesh_legacy_bevel_weight_from_layers(Mesh *mesh)
CustomData_get_layer(&mesh->edata, CD_BWEIGHT))) {
mesh->cd_flag |= ME_CDFLAG_EDGE_BWEIGHT;
for (const int i : edges.index_range()) {
- edges[i].bweight = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f;
+ edges[i].bweight_legacy = std::clamp(weights[i], 0.0f, 1.0f) * 255.0f;
}
}
else {
mesh->cd_flag &= ~ME_CDFLAG_EDGE_BWEIGHT;
for (const int i : edges.index_range()) {
- edges[i].bweight = 0;
+ edges[i].bweight_legacy = 0;
}
}
}
@@ -962,7 +962,7 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh)
float *weights = static_cast<float *>(
CustomData_add_layer(&mesh->vdata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, verts.size()));
for (const int i : verts.index_range()) {
- weights[i] = verts[i].bweight / 255.0f;
+ weights[i] = verts[i].bweight_legacy / 255.0f;
}
}
@@ -971,7 +971,7 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh)
float *weights = static_cast<float *>(
CustomData_add_layer(&mesh->edata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, edges.size()));
for (const int i : edges.index_range()) {
- weights[i] = edges[i].bweight / 255.0f;
+ weights[i] = edges[i].bweight_legacy / 255.0f;
}
}
}
@@ -1077,7 +1077,7 @@ void BKE_mesh_legacy_convert_material_indices_to_mpoly(Mesh *mesh)
"material_index", ATTR_DOMAIN_FACE, 0);
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
- polys[i].mat_nr = material_indices[i];
+ polys[i].mat_nr_legacy = material_indices[i];
}
});
}
@@ -1089,12 +1089,12 @@ void BKE_mesh_legacy_convert_mpoly_to_material_indices(Mesh *mesh)
MutableAttributeAccessor attributes = mesh->attributes_for_write();
const Span<MPoly> polys = mesh->polys();
if (std::any_of(
- polys.begin(), polys.end(), [](const MPoly &poly) { return poly.mat_nr != 0; })) {
+ polys.begin(), polys.end(), [](const MPoly &poly) { return poly.mat_nr_legacy != 0; })) {
SpanAttributeWriter<int> material_indices = attributes.lookup_or_add_for_write_only_span<int>(
"material_index", ATTR_DOMAIN_FACE);
threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) {
for (const int i : range) {
- material_indices.span[i] = polys[i].mat_nr;
+ material_indices.span[i] = polys[i].mat_nr_legacy;
}
});
material_indices.finish();
diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
index eb14028f49a..a77879fb573 100644
--- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
+++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc
@@ -124,6 +124,7 @@ static Mesh *remesh_quadriflow(const Mesh *input_mesh,
/* Construct the new output mesh */
Mesh *mesh = BKE_mesh_new_nomain(qrd.out_totverts, 0, 0, qrd.out_totfaces * 4, qrd.out_totfaces);
+ BKE_mesh_copy_parameters(mesh, input_mesh);
MutableSpan<MVert> mesh_verts = mesh->verts_for_write();
MutableSpan<MPoly> polys = mesh->polys_for_write();
MutableSpan<MLoop> loops = mesh->loops_for_write();
@@ -273,7 +274,9 @@ Mesh *BKE_mesh_remesh_voxel(const Mesh *mesh,
{
#ifdef WITH_OPENVDB
openvdb::FloatGrid::Ptr level_set = remesh_voxel_level_set_create(mesh, voxel_size);
- return remesh_voxel_volume_to_mesh(level_set, isovalue, adaptivity, false);
+ Mesh *result = remesh_voxel_volume_to_mesh(level_set, isovalue, adaptivity, false);
+ BKE_mesh_copy_parameters(result, mesh);
+ return result;
#else
UNUSED_VARS(mesh, voxel_size, adaptivity, isovalue);
return nullptr;
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 9457c20eb7d..da508ff865c 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -1241,7 +1241,7 @@ static NlaStrip *nlastrip_find_active(ListBase /* NlaStrip */ *strips)
float BKE_nlastrip_compute_frame_from_previous_strip(NlaStrip *strip)
{
- float limit_prev = MINFRAMEF;
+ float limit_prev = MINAFRAMEF;
/* Find the previous end frame, with a special case if the previous strip was a transition : */
if (strip->prev) {
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 2ae0b456b0d..b82cf30416a 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -71,6 +71,7 @@
#include "NOD_composite.h"
#include "NOD_function.h"
#include "NOD_geometry.h"
+#include "NOD_geometry_nodes_lazy_function.hh"
#include "NOD_node_declaration.hh"
#include "NOD_shader.h"
#include "NOD_socket.h"
diff --git a/source/blender/blenkernel/intern/node_runtime.cc b/source/blender/blenkernel/intern/node_runtime.cc
index a8281820a0b..00b78284791 100644
--- a/source/blender/blenkernel/intern/node_runtime.cc
+++ b/source/blender/blenkernel/intern/node_runtime.cc
@@ -10,8 +10,22 @@
#include "BLI_task.hh"
#include "BLI_timeit.hh"
+#include "NOD_geometry_nodes_lazy_function.hh"
+
namespace blender::bke::node_tree_runtime {
+void handle_node_tree_output_changed(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);
+ }
+}
+
static void double_checked_lock(std::mutex &mutex, bool &data_is_dirty, FunctionRef<void()> fn)
{
if (!data_is_dirty) {
@@ -36,11 +50,15 @@ static void update_node_vector(const bNodeTree &ntree)
{
bNodeTreeRuntime &tree_runtime = *ntree.runtime;
tree_runtime.nodes.clear();
+ tree_runtime.group_nodes.clear();
tree_runtime.has_undefined_nodes_or_sockets = false;
LISTBASE_FOREACH (bNode *, node, &ntree.nodes) {
node->runtime->index_in_tree = tree_runtime.nodes.append_and_get_index(node);
node->runtime->owner_tree = const_cast<bNodeTree *>(&ntree);
tree_runtime.has_undefined_nodes_or_sockets |= node->typeinfo == &NodeTypeUndefined;
+ if (node->is_group()) {
+ tree_runtime.group_nodes.append(node);
+ }
}
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index 7c96c463339..901b42ac0b2 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -526,21 +526,27 @@ static void unpack_generate_paths(const char *name,
BLI_strncpy(tempdir, "//", sizeof(tempdir));
}
- switch (id_type) {
- case ID_VF:
- BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname);
- break;
- case ID_SO:
- BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname);
- break;
- case ID_IM:
- BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
- break;
- case ID_VO:
- BLI_snprintf(r_relpath, relpathlen, "//volumes/%s", tempname);
- break;
- default:
- break;
+ {
+ const char *dir_name = NULL;
+ switch (id_type) {
+ case ID_VF:
+ dir_name = "fonts";
+ break;
+ case ID_SO:
+ dir_name = "sounds";
+ break;
+ case ID_IM:
+ dir_name = "textures";
+ break;
+ case ID_VO:
+ dir_name = "volumes";
+ break;
+ default:
+ break;
+ }
+ if (dir_name) {
+ BLI_path_join(r_relpath, relpathlen, "//", dir_name, tempname, NULL);
+ }
}
{
diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc
index d277bbcca63..1a1bf285847 100644
--- a/source/blender/blenkernel/intern/paint.cc
+++ b/source/blender/blenkernel/intern/paint.cc
@@ -1088,10 +1088,10 @@ bool BKE_paint_ensure(ToolSettings *ts, Paint **r_paint)
Sculpt *data = MEM_cnew<Sculpt>(__func__);
paint = &data->paint;
- /* Turn on X plane mirror symmetry by default */
+ /* Turn on X plane mirror symmetry by default. */
paint->symmetry_flags |= PAINT_SYMM_X;
- /* Make sure at least dyntopo subdivision is enabled */
+ /* Make sure at least dyntopo subdivision is enabled. */
data->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
}
else if ((GpPaint **)r_paint == &ts->gp_paint) {
@@ -1146,7 +1146,7 @@ void BKE_paint_init(Main *bmain, Scene *sce, ePaintMode mode, const uchar col[3]
brush = BKE_brush_first_search(bmain, ob_mode);
if (!brush) {
brush = BKE_brush_add(bmain, "Brush", ob_mode);
- id_us_min(&brush->id); /* fake user only */
+ id_us_min(&brush->id); /* Fake user only. */
}
BKE_paint_brush_set(paint, brush);
}
@@ -1247,18 +1247,17 @@ void BKE_paint_blend_read_lib(BlendLibReader *reader, Scene *sce, Paint *p)
}
}
-bool paint_is_face_hidden(const MLoopTri *lt, const bool *hide_vert, const MLoop *mloop)
+bool paint_is_face_hidden(const MLoopTri *lt, const bool *hide_poly)
{
- if (!hide_vert) {
+ if (!hide_poly) {
return false;
}
- return ((hide_vert[mloop[lt->tri[0]].v]) || (hide_vert[mloop[lt->tri[1]].v]) ||
- (hide_vert[mloop[lt->tri[2]].v]));
+ return hide_poly[lt->poly];
}
bool paint_is_grid_face_hidden(const uint *grid_hidden, int gridsize, int x, int y)
{
- /* skip face if any of its corners are hidden */
+ /* Skip face if any of its corners are hidden. */
return (BLI_BITMAP_TEST(grid_hidden, y * gridsize + x) ||
BLI_BITMAP_TEST(grid_hidden, y * gridsize + x + 1) ||
BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x + 1) ||
@@ -1288,7 +1287,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, uint level, uint x, uint y
return gpm->data[(y * factor) * gridsize + (x * factor)];
}
-/* threshold to move before updating the brush rotation */
+/* Threshold to move before updating the brush rotation. */
#define RAKE_THRESHHOLD 20
void paint_update_brush_rake_rotation(UnifiedPaintSettings *ups, Brush *brush, float rotation)
@@ -1331,8 +1330,8 @@ bool paint_calculate_rake_rotation(UnifiedPaintSettings *ups,
paint_update_brush_rake_rotation(ups, brush, rotation);
ok = true;
}
- /* make sure we reset here to the last rotation to avoid accumulating
- * values in case a random rotation is also added */
+ /* Make sure we reset here to the last rotation to avoid accumulating
+ * values in case a random rotation is also added. */
else {
paint_update_brush_rake_rotation(ups, brush, ups->last_rake_angle);
ok = false;
@@ -1528,20 +1527,29 @@ void BKE_sculptsession_free(Object *ob)
}
}
-MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob)
+static MultiresModifierData *sculpt_multires_modifier_get(const Scene *scene,
+ Object *ob,
+ const bool auto_create_mdisps)
{
Mesh *me = (Mesh *)ob->data;
ModifierData *md;
VirtualModifierData virtualModifierData;
if (ob->sculpt && ob->sculpt->bm) {
- /* can't combine multires and dynamic topology */
+ /* Can't combine multires and dynamic topology. */
return nullptr;
}
+ bool need_mdisps = false;
+
if (!CustomData_get_layer(&me->ldata, CD_MDISPS)) {
- /* multires can't work without displacement layer */
- return nullptr;
+ if (!auto_create_mdisps) {
+ /* Multires can't work without displacement layer. */
+ return nullptr;
+ }
+ else {
+ need_mdisps = true;
+ }
}
/* Weight paint operates on original vertices, and needs to treat multires as regular modifier
@@ -1559,6 +1567,10 @@ MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob)
}
if (mmd->sculptlvl > 0 && !(mmd->flags & eMultiresModifierFlag_UseSculptBaseMesh)) {
+ if (need_mdisps) {
+ CustomData_add_layer(&me->ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, me->totloop);
+ }
+
return mmd;
}
@@ -1569,6 +1581,11 @@ MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob)
return nullptr;
}
+MultiresModifierData *BKE_sculpt_multires_active(const Scene *scene, Object *ob)
+{
+ return sculpt_multires_modifier_get(scene, ob, false);
+}
+
/* Checks if there are any supported deformation modifiers active */
static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
{
@@ -1580,14 +1597,14 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
return false;
}
- /* non-locked shape keys could be handled in the same way as deformed mesh */
+ /* Non-locked shape keys could be handled in the same way as deformed mesh. */
if ((ob->shapeflag & OB_SHAPE_LOCK) == 0 && me->key && ob->shapenr) {
return true;
}
md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData);
- /* exception for shape keys because we can edit those */
+ /* Exception for shape keys because we can edit those. */
for (; md; md = md->next) {
const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type));
if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) {
@@ -1614,22 +1631,15 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
return false;
}
-/**
- * \param need_mask: So that the evaluated mesh that is returned has mask data.
- */
-static void sculpt_update_object(Depsgraph *depsgraph,
- Object *ob,
- Object *ob_eval,
- bool need_pmap,
- bool need_mask,
- bool is_paint_tool)
+static void sculpt_update_object(
+ Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool need_pmap, bool is_paint_tool)
{
Scene *scene = DEG_get_input_scene(depsgraph);
Sculpt *sd = scene->toolsettings->sculpt;
SculptSession *ss = ob->sculpt;
Mesh *me = BKE_object_get_original_mesh(ob);
Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
+ MultiresModifierData *mmd = sculpt_multires_modifier_get(scene, ob, true);
const bool use_face_sets = (ob->mode & OB_MODE_SCULPT) != 0;
BLI_assert(me_eval != nullptr);
@@ -1644,15 +1654,6 @@ static void sculpt_update_object(Depsgraph *depsgraph,
ss->scene = scene;
- if (need_mask) {
- if (mmd == nullptr) {
- BLI_assert(CustomData_has_layer(&me->vdata, CD_PAINT_MASK));
- }
- else {
- BLI_assert(CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK));
- }
- }
-
ss->shapekey_active = (mmd == nullptr) ? BKE_keyblock_from_object(ob) : nullptr;
/* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
@@ -1708,7 +1709,6 @@ static void sculpt_update_object(Depsgraph *depsgraph,
/* Sculpt Face Sets. */
if (use_face_sets) {
- BLI_assert(CustomData_has_layer(&me->pdata, CD_SCULPT_FACE_SETS));
ss->face_sets = static_cast<int *>(CustomData_get_layer(&me->pdata, CD_SCULPT_FACE_SETS));
}
else {
@@ -1841,24 +1841,7 @@ static void sculpt_update_object(Depsgraph *depsgraph,
}
}
-static void sculpt_face_sets_ensure(Mesh *mesh)
-{
- if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) {
- return;
- }
-
- int *new_face_sets = static_cast<int *>(CustomData_add_layer(
- &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly));
-
- /* Initialize the new Face Set data-layer with a default valid visible ID and set the default
- * color to render it white. */
- for (int i = 0; i < mesh->totpoly; i++) {
- new_face_sets[i] = 1;
- }
- mesh->face_sets_color_default = 1;
-}
-
-void BKE_sculpt_update_object_before_eval(const Scene *scene, Object *ob_eval)
+void BKE_sculpt_update_object_before_eval(Object *ob_eval)
{
/* Update before mesh evaluation in the dependency graph. */
SculptSession *ss = ob_eval->sculpt;
@@ -1888,16 +1871,6 @@ void BKE_sculpt_update_object_before_eval(const Scene *scene, Object *ob_eval)
MEM_freeN(nodes);
}
}
-
- if (ss) {
- Object *ob_orig = DEG_get_original_object(ob_eval);
- Mesh *mesh = BKE_object_get_original_mesh(ob_orig);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob_orig);
-
- /* Ensure attribute layout is still correct. */
- sculpt_face_sets_ensure(mesh);
- BKE_sculpt_mask_layers_ensure(ob_orig, mmd);
- }
}
void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval)
@@ -1906,7 +1879,7 @@ void BKE_sculpt_update_object_after_eval(Depsgraph *depsgraph, Object *ob_eval)
* other data when modifiers change the mesh. */
Object *ob_orig = DEG_get_original_object(ob_eval);
- sculpt_update_object(depsgraph, ob_orig, ob_eval, false, false, false);
+ sculpt_update_object(depsgraph, ob_orig, ob_eval, false, false);
}
void BKE_sculpt_color_layer_create_if_needed(Object *object)
@@ -1944,13 +1917,53 @@ void BKE_sculpt_color_layer_create_if_needed(Object *object)
}
void BKE_sculpt_update_object_for_edit(
- Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool need_mask, bool is_paint_tool)
+ Depsgraph *depsgraph, Object *ob_orig, bool need_pmap, bool /*need_mask*/, bool is_paint_tool)
{
BLI_assert(ob_orig == DEG_get_original_object(ob_orig));
Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_orig);
- sculpt_update_object(depsgraph, ob_orig, ob_eval, need_pmap, need_mask, is_paint_tool);
+ sculpt_update_object(depsgraph, ob_orig, ob_eval, need_pmap, is_paint_tool);
+}
+
+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));
+ }
+
+ 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};
+
+ /* Initialize the new face sets with a default valid visible ID and set the default
+ * color to render it white. */
+ if (hide_poly.is_single() && !hide_poly.get_internal_single()) {
+ face_sets.fill(1);
+ }
+ else {
+ const int face_sets_default_visible_id = 1;
+ const int face_sets_default_hidden_id = -2;
+
+ const VArraySpan<bool> hide_poly_span{hide_poly};
+ for (const int i : face_sets.index_range()) {
+ /* Assign a new hidden ID to hidden faces. This way we get at initial split in two Face Sets
+ * between hidden and visible faces based on the previous mesh visibly from other mode that
+ * can be useful in some cases. */
+ face_sets[i] = hide_poly_span[i] ? face_sets_default_hidden_id :
+ face_sets_default_visible_id;
+ }
+ }
+
+ mesh->face_sets_color_default = 1;
+ return face_sets.data();
}
int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
@@ -2014,7 +2027,7 @@ int BKE_sculpt_mask_layers_ensure(Object *ob, MultiresModifierData *mmd)
ret |= SCULPT_MASK_LAYER_CALC_LOOP;
}
- /* create vertex paint mask layer if there isn't one already */
+ /* 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);
ret |= SCULPT_MASK_LAYER_CALC_VERT;
@@ -2038,7 +2051,7 @@ void BKE_sculpt_toolsettings_data_ensure(Scene *scene)
sd->constant_detail = 3.0f;
}
- /* Set sane default tiling offsets */
+ /* Set sane default tiling offsets. */
if (!sd->paint.tile_offset[0]) {
sd->paint.tile_offset[0] = 1.0f;
}
@@ -2056,8 +2069,7 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc
/* Active modifiers means extra deformation, which can't be handled correct
* on birth of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
- * stuff and show final evaluated mesh so user would see actual object shape.
- */
+ * stuff and show final evaluated mesh so user would see actual object shape. */
deformed |= object->sculpt->deform_modifiers_active;
if (for_construction) {
@@ -2066,75 +2078,55 @@ static bool check_sculpt_object_deformed(Object *object, const bool for_construc
else {
/* As in case with modifiers, we can't synchronize deformation made against
* PBVH and non-locked keyblock, so also use PBVH only for brushes and
- * final DM to give final result to user.
- */
+ * final DM to give final result to user. */
deformed |= object->sculpt->shapekey_active && (object->shapeflag & OB_SHAPE_LOCK) == 0;
}
return deformed;
}
-void BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(Mesh *mesh)
+void BKE_sculpt_face_sets_update_from_base_mesh_visibility(Mesh *mesh)
{
- const int face_sets_default_visible_id = 1;
- const int face_sets_default_hidden_id = -(face_sets_default_visible_id + 1);
-
- bool initialize_new_face_sets = false;
-
- if (CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) {
- /* Make everything visible. */
- int *current_face_sets = static_cast<int *>(
- CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS));
- for (int i = 0; i < mesh->totpoly; i++) {
- current_face_sets[i] = abs(current_face_sets[i]);
- }
- }
- else {
- initialize_new_face_sets = true;
- int *new_face_sets = static_cast<int *>(CustomData_add_layer(
- &mesh->pdata, CD_SCULPT_FACE_SETS, CD_CONSTRUCT, nullptr, mesh->totpoly));
-
- /* Initialize the new Face Set data-layer with a default valid visible ID and set the default
- * color to render it white. */
- for (int i = 0; i < mesh->totpoly; i++) {
- new_face_sets[i] = face_sets_default_visible_id;
- }
- mesh->face_sets_color_default = face_sets_default_visible_id;
+ using namespace blender;
+ using namespace blender::bke;
+ if (!CustomData_has_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)) {
+ return;
}
- int *face_sets = static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS));
- const bool *hide_poly = (const bool *)CustomData_get_layer_named(
- &mesh->pdata, CD_PROP_BOOL, ".hide_poly");
+ const AttributeAccessor attributes = mesh->attributes();
+ const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
+ ".hide_poly", ATTR_DOMAIN_FACE, false);
+ if (hide_poly.is_single() && !hide_poly.get_internal_single()) {
+ return;
+ }
- for (int i = 0; i < mesh->totpoly; i++) {
- if (!(hide_poly && hide_poly[i])) {
- continue;
- }
+ MutableSpan<int> face_sets{
+ static_cast<int *>(CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS)), mesh->totpoly};
- if (initialize_new_face_sets) {
- /* When initializing a new Face Set data-layer, assign a new hidden Face Set ID to hidden
- * vertices. This way, we get at initial split in two Face Sets between hidden and
- * visible vertices based on the previous mesh visibly from other mode that can be
- * useful in some cases. */
- face_sets[i] = face_sets_default_hidden_id;
- }
- else {
- /* Otherwise, set the already existing Face Set ID to hidden. */
- face_sets[i] = -abs(face_sets[i]);
- }
+ for (const int i : hide_poly.index_range()) {
+ face_sets[i] = hide_poly[i] ? -std::abs(face_sets[i]) : std::abs(face_sets[i]);
}
}
-void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh)
+static void set_hide_poly_from_face_sets(Mesh &mesh)
{
+ using namespace blender;
using namespace blender::bke;
- const int *face_sets = static_cast<const int *>(
- CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS));
- if (!face_sets) {
+ if (!CustomData_has_layer(&mesh.pdata, CD_SCULPT_FACE_SETS)) {
+ return;
+ }
+
+ const Span<int> face_sets{
+ static_cast<const int *>(CustomData_get_layer(&mesh.pdata, CD_SCULPT_FACE_SETS)),
+ mesh.totpoly};
+
+ MutableAttributeAccessor attributes = mesh.attributes_for_write();
+ if (std::all_of(
+ face_sets.begin(), face_sets.end(), [&](const int value) { return value > 0; })) {
+ attributes.remove(".hide_poly");
return;
}
- MutableAttributeAccessor attributes = mesh->attributes_for_write();
SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_only_span<bool>(
".hide_poly", ATTR_DOMAIN_FACE);
if (!hide_poly) {
@@ -2144,7 +2136,11 @@ void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh)
hide_poly.span[i] = face_sets[i] < 0;
}
hide_poly.finish();
+}
+void BKE_sculpt_sync_face_sets_visibility_to_base_mesh(Mesh *mesh)
+{
+ set_hide_poly_from_face_sets(*mesh);
BKE_mesh_flush_hidden_from_polys(mesh);
}
@@ -2182,41 +2178,29 @@ void BKE_sculpt_sync_face_sets_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv
void BKE_sculpt_sync_face_set_visibility(Mesh *mesh, SubdivCCG *subdiv_ccg)
{
- BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh);
+ BKE_sculpt_face_sets_update_from_base_mesh_visibility(mesh);
BKE_sculpt_sync_face_sets_visibility_to_base_mesh(mesh);
BKE_sculpt_sync_face_sets_visibility_to_grids(mesh, subdiv_ccg);
}
-void BKE_sculpt_ensure_orig_mesh_data(Scene *scene, Object *object)
+void BKE_sculpt_ensure_orig_mesh_data(Object *object)
{
Mesh *mesh = BKE_mesh_from_object(object);
- MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, object);
-
BLI_assert(object->mode == OB_MODE_SCULPT);
/* Copy the current mesh visibility to the Face Sets. */
- BKE_sculpt_face_sets_ensure_from_base_mesh_visibility(mesh);
- if (object->sculpt != nullptr) {
- /* If a sculpt session is active, ensure we have its face-set data properly up-to-date. */
- object->sculpt->face_sets = static_cast<int *>(
- CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS));
-
- /* NOTE: In theory we could add that on the fly when required by sculpt code.
- * But this then requires proper update of depsgraph etc. For now we play safe, optimization is
- * always possible later if it's worth it. */
- BKE_sculpt_mask_layers_ensure(object, mmd);
- }
+ BKE_sculpt_face_sets_update_from_base_mesh_visibility(mesh);
/* Tessfaces aren't used and will become invalid. */
BKE_mesh_tessface_clear(mesh);
/* We always need to flush updates from depsgraph here, since at the very least
- * `BKE_sculpt_face_sets_ensure_from_base_mesh_visibility()` will have updated some data layer of
+ * `BKE_sculpt_face_sets_update_from_base_mesh_visibility()` will have updated some data layer of
* the mesh.
*
* All known potential sources of updates:
* - Addition of, or changes to, the `CD_SCULPT_FACE_SETS` data layer
- * (`BKE_sculpt_face_sets_ensure_from_base_mesh_visibility`).
+ * (`BKE_sculpt_face_sets_update_from_base_mesh_visibility`).
* - Addition of a `CD_PAINT_MASK` data layer (`BKE_sculpt_mask_layers_ensure`).
* - Object has any active modifier (modifier stack can be different in Sculpt mode).
* - Multires:
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 6d761f56f13..2e273e076d5 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -285,7 +285,7 @@ static void build_mesh_leaf_node(PBVH *pbvh, PBVHNode *node)
}
if (has_visible == false) {
- if (!paint_is_face_hidden(lt, pbvh->hide_vert, pbvh->mloop)) {
+ if (!paint_is_face_hidden(lt, pbvh->hide_poly)) {
has_visible = true;
}
}
@@ -552,6 +552,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh,
pbvh->mesh = mesh;
pbvh->header.type = PBVH_FACES;
pbvh->mpoly = mpoly;
+ pbvh->hide_poly = (bool *)CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, ".hide_poly");
pbvh->material_indices = (const int *)CustomData_get_layer_named(
&mesh->pdata, CD_PROP_INT32, "material_index");
pbvh->mloop = mloop;
@@ -1313,11 +1314,7 @@ static void pbvh_update_draw_buffer_cb(void *__restrict userdata,
}
case PBVH_FACES:
node->draw_buffers = GPU_pbvh_mesh_buffers_build(
- pbvh->mesh,
- pbvh->looptri,
- CustomData_get_layer(pbvh->pdata, CD_SCULPT_FACE_SETS),
- node->prim_indices,
- node->totprim);
+ pbvh->mesh, pbvh->looptri, node->prim_indices, node->totprim);
break;
case PBVH_BMESH:
node->draw_buffers = GPU_pbvh_bmesh_buffers_build(pbvh->flags &
@@ -2293,7 +2290,7 @@ static bool pbvh_faces_node_raycast(PBVH *pbvh,
const MLoopTri *lt = &pbvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
- if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_vert, mloop)) {
+ if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_poly)) {
continue;
}
@@ -2602,7 +2599,7 @@ static bool pbvh_faces_node_nearest_to_ray(PBVH *pbvh,
const MLoopTri *lt = &pbvh->looptri[faces[i]];
const int *face_verts = node->face_vert_indices[i];
- if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_vert, mloop)) {
+ if (pbvh->respect_hide && paint_is_face_hidden(lt, pbvh->hide_poly)) {
continue;
}
@@ -3219,6 +3216,12 @@ const bool *BKE_pbvh_get_vert_hide(const PBVH *pbvh)
return pbvh->hide_vert;
}
+const bool *BKE_pbvh_get_poly_hide(const PBVH *pbvh)
+{
+ BLI_assert(pbvh->header.type == PBVH_FACES);
+ return pbvh->hide_poly;
+}
+
bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh)
{
BLI_assert(pbvh->header.type == PBVH_FACES);
@@ -3244,6 +3247,14 @@ void BKE_pbvh_face_sets_set(PBVH *pbvh, int *face_sets)
pbvh->face_sets = face_sets;
}
+void BKE_pbvh_update_hide_attributes_from_mesh(PBVH *pbvh)
+{
+ if (pbvh->header.type == PBVH_FACES) {
+ pbvh->hide_vert = CustomData_get_layer_named(&pbvh->mesh->vdata, CD_PROP_BOOL, ".hide_vert");
+ pbvh->hide_poly = CustomData_get_layer_named(&pbvh->mesh->pdata, CD_PROP_BOOL, ".hide_poly");
+ }
+}
+
void BKE_pbvh_respect_hide_set(PBVH *pbvh, bool respect_hide)
{
pbvh->respect_hide = respect_hide;
diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h
index b848327b7a9..8ab56839f9c 100644
--- a/source/blender/blenkernel/intern/pbvh_intern.h
+++ b/source/blender/blenkernel/intern/pbvh_intern.h
@@ -156,6 +156,7 @@ struct PBVH {
bool *hide_vert;
struct MVert *verts;
const struct MPoly *mpoly;
+ bool *hide_poly;
/** Material indices. Only valid for polygon meshes. */
const int *material_indices;
const struct MLoop *mloop;
diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc
index fe6353bc72d..b45e164b594 100644
--- a/source/blender/blenkernel/intern/pointcloud.cc
+++ b/source/blender/blenkernel/intern/pointcloud.cc
@@ -189,8 +189,9 @@ IDTypeInfo IDType_ID_PT = {
static void pointcloud_random(PointCloud *pointcloud)
{
+ BLI_assert(pointcloud->totpoint == 0);
pointcloud->totpoint = 400;
- CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
+ CustomData_realloc(&pointcloud->pdata, 0, pointcloud->totpoint);
RNG *rng = BLI_rng_new(0);
@@ -238,9 +239,6 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
nullptr, ID_PT, BKE_idtype_idcode_to_name(ID_PT), LIB_ID_CREATE_LOCALIZE));
pointcloud_init_data(&pointcloud->id);
-
- pointcloud->totpoint = totpoint;
-
CustomData_add_layer_named(&pointcloud->pdata,
CD_PROP_FLOAT,
CD_SET_DEFAULT,
@@ -248,8 +246,8 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint)
pointcloud->totpoint,
POINTCLOUD_ATTR_RADIUS);
+ CustomData_realloc(&pointcloud->pdata, 0, totpoint);
pointcloud->totpoint = totpoint;
- CustomData_realloc(&pointcloud->pdata, pointcloud->totpoint);
return pointcloud;
}