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:
authorFabian Schempp <fabianschempp@googlemail.com>2022-04-11 08:14:28 +0300
committerFabian Schempp <fabianschempp@googlemail.com>2022-04-11 08:14:28 +0300
commitf06d361da1249c93568153bae88bcdf43b4774a1 (patch)
tree5acd7443d2c13d3f89b40e81f7d93df5e2a56008 /source/blender/blenkernel/intern
parentab6939ff78f131e5270e17b9ee73075b512a1a3f (diff)
parent5e47056e8d97e414c9dabacea71fac2bdc7d2818 (diff)
Merge branch 'master' into soc-2021-porting-modifiers-to-nodes-remesh-voxel
# Conflicts: # intern/cycles/app/opengl/display_driver.cpp # intern/cycles/app/opengl/display_driver.h # intern/cycles/app/opengl/shader.cpp # intern/cycles/app/opengl/shader.h # intern/cycles/app/opengl/window.cpp # intern/cycles/app/opengl/window.h # intern/cycles/blender/addon/ui.py # intern/cycles/util/view.cpp # intern/cycles/util/view.h # release/scripts/startup/bl_ui/properties_data_armature.py # release/scripts/startup/bl_ui/properties_view_layer.py # source/blender/blenkernel/BKE_armature.h # source/blender/blenkernel/BKE_blender_version.h # source/blender/blenkernel/BKE_curves.hh # source/blender/blenkernel/BKE_gpencil_update_cache.h # source/blender/blenkernel/BKE_node.h # source/blender/blenkernel/CMakeLists.txt # source/blender/blenkernel/intern/curve_eval.cc # source/blender/blenkernel/intern/curves_geometry.cc # source/blender/blenkernel/intern/geometry_component_curves.cc # source/blender/blenkernel/intern/lib_override.c # source/blender/blenkernel/intern/lib_override_proxy_conversion.c # source/blender/blenkernel/intern/scene.cc # source/blender/blenkernel/intern/type_conversions.cc # source/blender/blenloader/intern/versioning_300.c # source/blender/draw/engines/eevee/eevee_data.c # source/blender/draw/engines/image/image_drawing_mode.hh # source/blender/draw/engines/image/image_space.hh # source/blender/draw/engines/workbench/shaders/infos/workbench_prepass_info.hh # source/blender/draw/intern/draw_cache_impl_subdivision.cc # source/blender/editors/gpencil/gpencil_fill.c # source/blender/editors/include/ED_paint.h # source/blender/editors/object/object_bake.c # source/blender/editors/render/render_intern.hh # source/blender/editors/render/render_ops.cc # source/blender/editors/render/render_shading.cc # source/blender/editors/screen/area.c # source/blender/editors/sculpt_paint/paint_canvas.cc # source/blender/editors/sculpt_paint/sculpt_intern.h # source/blender/editors/sculpt_paint/sculpt_paint_color.c # source/blender/editors/space_node/node_intern.hh # source/blender/editors/space_outliner/outliner_tools.cc # source/blender/editors/transform/transform_convert_sequencer.c # source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c # source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc # source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc # source/blender/makesdna/DNA_ID.h # source/blender/makesdna/DNA_curves_types.h # source/blender/makesrna/intern/rna_internal.h # source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc # source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r--source/blender/blenkernel/intern/constraint.c4
-rw-r--r--source/blender/blenkernel/intern/curve_eval.cc8
-rw-r--r--source/blender/blenkernel/intern/curve_poly.cc154
-rw-r--r--source/blender/blenkernel/intern/curves_geometry.cc141
-rw-r--r--source/blender/blenkernel/intern/geometry_component_curves.cc133
-rw-r--r--source/blender/blenkernel/intern/lib_override.c1
-rw-r--r--source/blender/blenkernel/intern/lib_override_proxy_conversion.c27
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c52
-rw-r--r--source/blender/blenkernel/intern/scene.cc1
-rw-r--r--source/blender/blenkernel/intern/type_conversions.cc2
10 files changed, 422 insertions, 101 deletions
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 0bab3d826fd..e85524d4bcb 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -888,7 +888,7 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
/* This following macro should be used for all standard single-target *_get_tars functions
* to save typing and reduce maintenance woes. It does not do the subtarget related operations
* (Hopefully all compilers will be happy with the lines with just a space on them. Those are
- * really just to help this code easier to read)
+ * really just to help this code easier to read)
*/
/* TODO: cope with getting rotation order... */
#define SINGLETARGETNS_GET_TARS(con, datatar, ct, list) \
@@ -932,7 +932,7 @@ static void default_get_tarmat_full_bbone(struct Depsgraph *UNUSED(depsgraph),
* to save typing and reduce maintenance woes. It does not do the subtarget related operations.
* NOTE: the pointer to ct will be changed to point to the next in the list (as it gets removed)
* (Hopefully all compilers will be happy with the lines with just a space on them. Those are
- * really just to help this code easier to read)
+ * really just to help this code easier to read)
*/
#define SINGLETARGETNS_FLUSH_TARS(con, datatar, ct, list, no_copy) \
{ \
diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc
index 9b1fd510fa8..6e09d1e8f10 100644
--- a/source/blender/blenkernel/intern/curve_eval.cc
+++ b/source/blender/blenkernel/intern/curve_eval.cc
@@ -381,6 +381,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
curves.geometry);
VArray<int> resolution = geometry.resolution();
+ VArray<int8_t> normal_mode = geometry.normal_mode();
VArray_Span<float> nurbs_weights{
src_component.attribute_get_for_read<float>("nurbs_weight", ATTR_DOMAIN_POINT, 0.0f)};
@@ -436,6 +437,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
spline->positions().fill(float3(0));
spline->tilts().fill(0.0f);
spline->radii().fill(1.0f);
+ spline->normal_mode = static_cast<NormalMode>(normal_mode[curve_index]);
curve_eval->add_spline(std::move(spline));
}
@@ -448,6 +450,7 @@ std::unique_ptr<CurveEval> curves_to_curve_eval(const Curves &curves)
dst_component,
{"curve_type",
"resolution",
+ "normal_mode",
"nurbs_weight",
"nurbs_order",
"knots_mode",
@@ -468,6 +471,8 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
geometry.offsets_for_write().copy_from(curve_eval.control_point_offsets());
MutableSpan<int8_t> curve_types = geometry.curve_types_for_write();
+ OutputAttribute_Typed<int8_t> normal_mode =
+ dst_component.attribute_try_get_for_output_only<int8_t>("normal_mode", ATTR_DOMAIN_CURVE);
OutputAttribute_Typed<float> nurbs_weight;
OutputAttribute_Typed<int> nurbs_order;
OutputAttribute_Typed<int8_t> nurbs_knots_mode;
@@ -491,7 +496,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
for (const int curve_index : curve_eval.splines().index_range()) {
const Spline &spline = *curve_eval.splines()[curve_index];
curve_types[curve_index] = curve_eval.splines()[curve_index]->type();
-
+ normal_mode.as_span()[curve_index] = curve_eval.splines()[curve_index]->normal_mode;
const IndexRange point_range = geometry.points_for_curve(curve_index);
switch (spline.type()) {
@@ -517,6 +522,7 @@ Curves *curve_eval_to_curves(const CurveEval &curve_eval)
}
}
+ normal_mode.save();
nurbs_weight.save();
nurbs_order.save();
nurbs_knots_mode.save();
diff --git a/source/blender/blenkernel/intern/curve_poly.cc b/source/blender/blenkernel/intern/curve_poly.cc
new file mode 100644
index 00000000000..b0ed62d38dd
--- /dev/null
+++ b/source/blender/blenkernel/intern/curve_poly.cc
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <algorithm>
+
+#include "BLI_math_vector.h"
+#include "BLI_math_vector.hh"
+
+#include "BKE_curves.hh"
+
+namespace blender::bke::curves::poly {
+
+static float3 direction_bisect(const float3 &prev, const float3 &middle, const float3 &next)
+{
+ const float3 dir_prev = math::normalize(middle - prev);
+ const float3 dir_next = math::normalize(next - middle);
+
+ const float3 result = math::normalize(dir_prev + dir_next);
+ if (UNLIKELY(math::is_zero(result))) {
+ return float3(0.0f, 0.0f, 1.0f);
+ }
+ return result;
+}
+
+void calculate_tangents(const Span<float3> positions,
+ const bool is_cyclic,
+ MutableSpan<float3> tangents)
+{
+ BLI_assert(positions.size() == tangents.size());
+
+ if (positions.size() == 1) {
+ tangents.first() = float3(0.0f, 0.0f, 1.0f);
+ return;
+ }
+
+ for (const int i : IndexRange(1, positions.size() - 2)) {
+ tangents[i] = direction_bisect(positions[i - 1], positions[i], positions[i + 1]);
+ }
+
+ if (is_cyclic) {
+ const float3 &second_to_last = positions[positions.size() - 2];
+ const float3 &last = positions.last();
+ const float3 &first = positions.first();
+ const float3 &second = positions[1];
+ tangents.first() = direction_bisect(last, first, second);
+ tangents.last() = direction_bisect(second_to_last, last, first);
+ }
+ else {
+ tangents.first() = math::normalize(positions[1] - positions.first());
+ tangents.last() = math::normalize(positions.last() - positions[positions.size() - 2]);
+ }
+}
+
+static float3 rotate_direction_around_axis(const float3 &direction,
+ const float3 &axis,
+ const float angle)
+{
+ BLI_ASSERT_UNIT_V3(direction);
+ BLI_ASSERT_UNIT_V3(axis);
+
+ const float3 axis_scaled = axis * math::dot(direction, axis);
+ const float3 diff = direction - axis_scaled;
+ const float3 cross = math::cross(axis, diff);
+
+ return axis_scaled + diff * std::cos(angle) + cross * std::sin(angle);
+}
+
+void calculate_normals_z_up(const Span<float3> tangents, MutableSpan<float3> normals)
+{
+ BLI_assert(normals.size() == tangents.size());
+
+ /* Same as in `vec_to_quat`. */
+ const float epsilon = 1e-4f;
+ for (const int i : normals.index_range()) {
+ const float3 &tangent = tangents[i];
+ if (std::abs(tangent.x) + std::abs(tangent.y) < epsilon) {
+ normals[i] = {1.0f, 0.0f, 0.0f};
+ }
+ else {
+ normals[i] = math::normalize(float3(tangent.y, -tangent.x, 0.0f));
+ }
+ }
+}
+
+/**
+ * Rotate the last normal in the same way the tangent has been rotated.
+ */
+static float3 calculate_next_normal(const float3 &last_normal,
+ const float3 &last_tangent,
+ const float3 &current_tangent)
+{
+ if (math::is_zero(last_tangent) || math::is_zero(current_tangent)) {
+ return last_normal;
+ }
+ const float angle = angle_normalized_v3v3(last_tangent, current_tangent);
+ if (angle != 0.0) {
+ const float3 axis = math::normalize(math::cross(last_tangent, current_tangent));
+ return rotate_direction_around_axis(last_normal, axis, angle);
+ }
+ return last_normal;
+}
+
+void calculate_normals_minimum(const Span<float3> tangents,
+ const bool cyclic,
+ MutableSpan<float3> normals)
+{
+ BLI_assert(normals.size() == tangents.size());
+
+ if (normals.is_empty()) {
+ return;
+ }
+
+ const float epsilon = 1e-4f;
+
+ /* Set initial normal. */
+ const float3 &first_tangent = tangents.first();
+ if (fabs(first_tangent.x) + fabs(first_tangent.y) < epsilon) {
+ normals.first() = {1.0f, 0.0f, 0.0f};
+ }
+ else {
+ normals.first() = math::normalize(float3(first_tangent.y, -first_tangent.x, 0.0f));
+ }
+
+ /* Forward normal with minimum twist along the entire spline. */
+ for (const int i : IndexRange(1, normals.size() - 1)) {
+ normals[i] = calculate_next_normal(normals[i - 1], tangents[i - 1], tangents[i]);
+ }
+
+ if (!cyclic) {
+ return;
+ }
+
+ /* Compute how much the first normal deviates from the normal that has been forwarded along the
+ * entire cyclic spline. */
+ const float3 uncorrected_last_normal = calculate_next_normal(
+ normals.last(), tangents.last(), tangents.first());
+ float correction_angle = angle_signed_on_axis_v3v3_v3(
+ normals.first(), uncorrected_last_normal, tangents.first());
+ if (correction_angle > M_PI) {
+ correction_angle = correction_angle - 2 * M_PI;
+ }
+
+ /* Gradually apply correction by rotating all normals slightly. */
+ const float angle_step = correction_angle / normals.size();
+ for (const int i : normals.index_range()) {
+ const float angle = angle_step * i;
+ normals[i] = rotate_direction_around_axis(normals[i], tangents[i], angle);
+ }
+}
+
+} // namespace blender::bke::curves::poly
diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc
index a76d8b08a16..5c89dfd4df5 100644
--- a/source/blender/blenkernel/intern/curves_geometry.cc
+++ b/source/blender/blenkernel/intern/curves_geometry.cc
@@ -25,6 +25,7 @@ static const std::string ATTR_RADIUS = "radius";
static const std::string ATTR_CURVE_TYPE = "curve_type";
static const std::string ATTR_CYCLIC = "cyclic";
static const std::string ATTR_RESOLUTION = "resolution";
+static const std::string ATTR_NORMAL_MODE = "normal_mode";
static const std::string ATTR_HANDLE_TYPE_LEFT = "handle_type_left";
static const std::string ATTR_HANDLE_TYPE_RIGHT = "handle_type_right";
static const std::string ATTR_HANDLE_POSITION_LEFT = "handle_left";
@@ -202,7 +203,8 @@ static Span<T> get_span_attribute(const CurvesGeometry &curves,
template<typename T>
static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
const AttributeDomain domain,
- const StringRefNull name)
+ const StringRefNull name,
+ const T default_value = T())
{
const int size = domain_size(curves, domain);
const CustomDataType type = cpp_type_to_custom_data_type(CPPType::get<T>());
@@ -215,7 +217,11 @@ static MutableSpan<T> get_mutable_attribute(CurvesGeometry &curves,
}
data = (T *)CustomData_add_layer_named(
&custom_data, type, CD_CALLOC, nullptr, size, name.c_str());
- return {data, size};
+ MutableSpan<T> span = {data, size};
+ if (size > 0 && span.first() != default_value) {
+ span.fill(default_value);
+ }
+ return span;
}
VArray<int8_t> CurvesGeometry::curve_types() const
@@ -303,7 +309,7 @@ VArray<bool> CurvesGeometry::cyclic() const
}
MutableSpan<bool> CurvesGeometry::cyclic_for_write()
{
- return get_mutable_attribute<bool>(*this, ATTR_DOMAIN_CURVE, ATTR_CYCLIC);
+ return get_mutable_attribute<bool>(*this, ATTR_DOMAIN_CURVE, ATTR_CYCLIC, false);
}
VArray<int> CurvesGeometry::resolution() const
@@ -312,7 +318,16 @@ VArray<int> CurvesGeometry::resolution() const
}
MutableSpan<int> CurvesGeometry::resolution_for_write()
{
- return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_RESOLUTION);
+ return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_RESOLUTION, 12);
+}
+
+VArray<int8_t> CurvesGeometry::normal_mode() const
+{
+ return get_varray_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NORMAL_MODE, 0);
+}
+MutableSpan<int8_t> CurvesGeometry::normal_mode_for_write()
+{
+ return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NORMAL_MODE);
}
VArray<int8_t> CurvesGeometry::handle_types_left() const
@@ -321,7 +336,7 @@ VArray<int8_t> CurvesGeometry::handle_types_left() const
}
MutableSpan<int8_t> CurvesGeometry::handle_types_left_for_write()
{
- return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_LEFT);
+ return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_LEFT, 0);
}
VArray<int8_t> CurvesGeometry::handle_types_right() const
@@ -330,7 +345,7 @@ VArray<int8_t> CurvesGeometry::handle_types_right() const
}
MutableSpan<int8_t> CurvesGeometry::handle_types_right_for_write()
{
- return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_RIGHT);
+ return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_POINT, ATTR_HANDLE_TYPE_RIGHT, 0);
}
Span<float3> CurvesGeometry::handle_positions_left() const
@@ -357,7 +372,7 @@ VArray<int8_t> CurvesGeometry::nurbs_orders() const
}
MutableSpan<int8_t> CurvesGeometry::nurbs_orders_for_write()
{
- return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_ORDER);
+ return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_ORDER, 4);
}
Span<float> CurvesGeometry::nurbs_weights() const
@@ -375,7 +390,7 @@ VArray<int8_t> CurvesGeometry::nurbs_knots_modes() const
}
MutableSpan<int8_t> CurvesGeometry::nurbs_knots_modes_for_write()
{
- return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE);
+ return get_mutable_attribute<int8_t>(*this, ATTR_DOMAIN_CURVE, ATTR_NURBS_KNOTS_MODE, 0);
}
VArray<int> CurvesGeometry::surface_triangle_indices() const
@@ -385,7 +400,7 @@ VArray<int> CurvesGeometry::surface_triangle_indices() const
MutableSpan<int> CurvesGeometry::surface_triangle_indices_for_write()
{
- return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX);
+ return get_mutable_attribute<int>(*this, ATTR_DOMAIN_CURVE, ATTR_SURFACE_TRIANGLE_INDEX, -1);
}
Span<float2> CurvesGeometry::surface_triangle_coords() const
@@ -629,9 +644,117 @@ Span<float3> CurvesGeometry::evaluated_positions() const
});
});
+ this->runtime->position_cache_dirty = false;
return this->runtime->evaluated_position_cache;
}
+Span<float3> CurvesGeometry::evaluated_tangents() const
+{
+ if (!this->runtime->tangent_cache_dirty) {
+ return this->runtime->evaluated_tangent_cache;
+ }
+
+ /* A double checked lock. */
+ std::scoped_lock lock{this->runtime->tangent_cache_mutex};
+ if (!this->runtime->tangent_cache_dirty) {
+ return this->runtime->evaluated_tangent_cache;
+ }
+
+ threading::isolate_task([&]() {
+ const Span<float3> evaluated_positions = this->evaluated_positions();
+ const VArray<bool> cyclic = this->cyclic();
+
+ this->runtime->evaluated_tangent_cache.resize(this->evaluated_points_num());
+ MutableSpan<float3> tangents = this->runtime->evaluated_tangent_cache;
+
+ threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
+ for (const int curve_index : curves_range) {
+ const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
+ if (UNLIKELY(evaluated_points.is_empty())) {
+ continue;
+ }
+ curves::poly::calculate_tangents(evaluated_positions.slice(evaluated_points),
+ cyclic[curve_index],
+ tangents.slice(evaluated_points));
+ }
+ });
+
+ /* Correct the first and last tangents of Bezier curves so that they align with the inner
+ * handles. This is a separate loop to avoid the cost when Bezier type curves are not used. */
+ Vector<int64_t> bezier_indices;
+ const IndexMask bezier_mask = this->indices_for_curve_type(CURVE_TYPE_BEZIER, bezier_indices);
+ if (!bezier_mask.is_empty()) {
+ const Span<float3> positions = this->positions();
+ const Span<float3> handles_left = this->handle_positions_left();
+ const Span<float3> handles_right = this->handle_positions_right();
+
+ threading::parallel_for(bezier_mask.index_range(), 1024, [&](IndexRange range) {
+ for (const int curve_index : bezier_mask.slice(range)) {
+ const IndexRange points = this->points_for_curve(curve_index);
+ const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
+
+ if (handles_right[points.first()] != positions[points.first()]) {
+ tangents[evaluated_points.first()] = math::normalize(handles_right[points.first()] -
+ positions[points.first()]);
+ }
+ if (handles_left[points.last()] != positions[points.last()]) {
+ tangents[evaluated_points.last()] = math::normalize(positions[points.last()] -
+ handles_left[points.last()]);
+ }
+ }
+ });
+ }
+ });
+
+ this->runtime->tangent_cache_dirty = false;
+ return this->runtime->evaluated_tangent_cache;
+}
+
+Span<float3> CurvesGeometry::evaluated_normals() const
+{
+ if (!this->runtime->normal_cache_dirty) {
+ return this->runtime->evaluated_normal_cache;
+ }
+
+ /* A double checked lock. */
+ std::scoped_lock lock{this->runtime->normal_cache_mutex};
+ if (!this->runtime->normal_cache_dirty) {
+ return this->runtime->evaluated_normal_cache;
+ }
+
+ threading::isolate_task([&]() {
+ const Span<float3> evaluated_tangents = this->evaluated_tangents();
+ const VArray<bool> cyclic = this->cyclic();
+ const VArray<int8_t> normal_mode = this->normal_mode();
+
+ this->runtime->evaluated_normal_cache.resize(this->evaluated_points_num());
+ MutableSpan<float3> evaluated_normals = this->runtime->evaluated_normal_cache;
+
+ threading::parallel_for(this->curves_range(), 128, [&](IndexRange curves_range) {
+ for (const int curve_index : curves_range) {
+ const IndexRange evaluated_points = this->evaluated_points_for_curve(curve_index);
+ if (UNLIKELY(evaluated_points.is_empty())) {
+ continue;
+ }
+ switch (normal_mode[curve_index]) {
+ case NORMAL_MODE_Z_UP:
+ curves::poly::calculate_normals_z_up(evaluated_tangents.slice(evaluated_points),
+ evaluated_normals.slice(evaluated_points));
+ break;
+ case NORMAL_MODE_MINIMUM_TWIST:
+ curves::poly::calculate_normals_minimum(evaluated_tangents.slice(evaluated_points),
+ cyclic[curve_index],
+ evaluated_normals.slice(evaluated_points));
+ break;
+ }
+ }
+ });
+ });
+
+ this->runtime->normal_cache_dirty = false;
+ return this->runtime->evaluated_normal_cache;
+}
+
void CurvesGeometry::interpolate_to_evaluated(const int curve_index,
const GSpan src,
GMutableSpan dst) const
diff --git a/source/blender/blenkernel/intern/geometry_component_curves.cc b/source/blender/blenkernel/intern/geometry_component_curves.cc
index 27c1a2f2f33..0bcab0aae7a 100644
--- a/source/blender/blenkernel/intern/geometry_component_curves.cc
+++ b/source/blender/blenkernel/intern/geometry_component_curves.cc
@@ -141,81 +141,97 @@ const Curve *CurveComponent::get_curve_for_render() const
namespace blender::bke {
-static void calculate_bezier_normals(const BezierSpline &spline, MutableSpan<float3> normals)
+static Array<float3> curve_normal_point_domain(const bke::CurvesGeometry &curves)
{
- Span<int> offsets = spline.control_point_offsets();
- Span<float3> evaluated_normals = spline.evaluated_normals();
- for (const int i : IndexRange(spline.size())) {
- normals[i] = evaluated_normals[offsets[i]];
- }
-}
+ const VArray<int8_t> types = curves.curve_types();
+ const VArray<int> resolutions = curves.resolution();
+ const VArray<bool> curves_cyclic = curves.cyclic();
-static void calculate_poly_normals(const PolySpline &spline, MutableSpan<float3> normals)
-{
- normals.copy_from(spline.evaluated_normals());
-}
+ const Span<float3> positions = curves.positions();
+ const VArray<int8_t> normal_modes = curves.normal_mode();
-/**
- * Because NURBS control points are not necessarily on the path, the normal at the control points
- * is not well defined, so create a temporary poly spline to find the normals. This requires extra
- * copying currently, but may be more efficient in the future if attributes have some form of CoW.
- */
-static void calculate_nurbs_normals(const NURBSpline &spline, MutableSpan<float3> normals)
-{
- PolySpline poly_spline;
- poly_spline.resize(spline.size());
- poly_spline.positions().copy_from(spline.positions());
- poly_spline.tilts().copy_from(spline.tilts());
- normals.copy_from(poly_spline.evaluated_normals());
-}
+ const Span<float3> evaluated_normals = curves.evaluated_normals();
-static Array<float3> curve_normal_point_domain(const CurveEval &curve)
-{
- Span<SplinePtr> splines = curve.splines();
- Array<int> offsets = curve.control_point_offsets();
- const int total_size = offsets.last();
- Array<float3> normals(total_size);
-
- threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) {
- for (const int i : range) {
- const Spline &spline = *splines[i];
- MutableSpan spline_normals{normals.as_mutable_span().slice(offsets[i], spline.size())};
- switch (splines[i]->type()) {
- case CURVE_TYPE_BEZIER:
- calculate_bezier_normals(static_cast<const BezierSpline &>(spline), spline_normals);
+ Array<float3> results(curves.points_num());
+
+ threading::parallel_for(curves.curves_range(), 128, [&](IndexRange range) {
+ Vector<float3> nurbs_tangents;
+
+ for (const int i_curve : range) {
+ const IndexRange points = curves.points_for_curve(i_curve);
+ const IndexRange evaluated_points = curves.evaluated_points_for_curve(i_curve);
+
+ MutableSpan<float3> curve_normals = results.as_mutable_span().slice(points);
+
+ switch (types[i_curve]) {
+ case CURVE_TYPE_CATMULL_ROM: {
+ const Span<float3> normals = evaluated_normals.slice(evaluated_points);
+ const int resolution = resolutions[i_curve];
+ for (const int i : IndexRange(points.size())) {
+ curve_normals[i] = normals[resolution * i];
+ }
break;
+ }
case CURVE_TYPE_POLY:
- calculate_poly_normals(static_cast<const PolySpline &>(spline), spline_normals);
+ curve_normals.copy_from(evaluated_normals.slice(evaluated_points));
break;
- case CURVE_TYPE_NURBS:
- calculate_nurbs_normals(static_cast<const NURBSpline &>(spline), spline_normals);
+ case CURVE_TYPE_BEZIER: {
+ const Span<float3> normals = evaluated_normals.slice(evaluated_points);
+ curve_normals.first() = normals.first();
+ const Span<int> offsets = curves.bezier_evaluated_offsets_for_curve(i_curve);
+ for (const int i : IndexRange(points.size()).drop_front(1)) {
+ curve_normals[i] = normals[offsets[i - 1]];
+ }
break;
- case CURVE_TYPE_CATMULL_ROM:
- BLI_assert_unreachable();
+ }
+ case CURVE_TYPE_NURBS: {
+ /* For NURBS curves there is no obvious correspondence between specific evaluated points
+ * and control points, so normals are determined by treating them as poly curves. */
+ nurbs_tangents.clear();
+ nurbs_tangents.resize(points.size());
+ const bool cyclic = curves_cyclic[i_curve];
+ const Span<float3> curve_positions = positions.slice(points);
+ bke::curves::poly::calculate_tangents(curve_positions, cyclic, nurbs_tangents);
+ switch (NormalMode(normal_modes[i_curve])) {
+ case NORMAL_MODE_Z_UP:
+ bke::curves::poly::calculate_normals_z_up(nurbs_tangents, curve_normals);
+ break;
+ case NORMAL_MODE_MINIMUM_TWIST:
+ bke::curves::poly::calculate_normals_minimum(nurbs_tangents, cyclic, curve_normals);
+ break;
+ }
break;
+ }
}
}
});
- return normals;
+ return results;
}
VArray<float3> curve_normals_varray(const CurveComponent &component, const AttributeDomain domain)
{
- if (component.is_empty()) {
- return nullptr;
+ if (!component.has_curves()) {
+ return {};
}
- const std::unique_ptr<CurveEval> curve = curves_to_curve_eval(*component.get_for_read());
+
+ const Curves &curves_id = *component.get_for_read();
+ const bke::CurvesGeometry &curves = bke::CurvesGeometry::wrap(curves_id.geometry);
+
+ const VArray<int8_t> types = curves.curve_types();
+ if (curves.is_single_type(CURVE_TYPE_POLY)) {
+ return component.attribute_try_adapt_domain<float3>(
+ VArray<float3>::ForSpan(curves.evaluated_normals()), ATTR_DOMAIN_POINT, domain);
+ }
+
+ Array<float3> normals = curve_normal_point_domain(curves);
if (domain == ATTR_DOMAIN_POINT) {
- Array<float3> normals = curve_normal_point_domain(*curve);
return VArray<float3>::ForContainer(std::move(normals));
}
if (domain == ATTR_DOMAIN_CURVE) {
- Array<float3> point_normals = curve_normal_point_domain(*curve);
- VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals));
return component.attribute_try_adapt_domain<float3>(
- std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
+ VArray<float3>::ForContainer(std::move(normals)), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE);
}
return nullptr;
@@ -456,6 +472,18 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
make_array_write_attribute<int>,
tag_component_topology_changed);
+ static BuiltinCustomDataLayerProvider normal_mode("normal_mode",
+ ATTR_DOMAIN_CURVE,
+ CD_PROP_INT8,
+ CD_PROP_INT8,
+ BuiltinAttributeProvider::Creatable,
+ BuiltinAttributeProvider::Writable,
+ BuiltinAttributeProvider::Deletable,
+ curve_access,
+ make_array_read_attribute<int8_t>,
+ make_array_write_attribute<int8_t>,
+ tag_component_normals_changed);
+
static BuiltinCustomDataLayerProvider nurbs_knots_mode("knots_mode",
ATTR_DOMAIN_CURVE,
CD_PROP_INT8,
@@ -490,7 +518,7 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
curve_access,
make_array_read_attribute<int>,
make_array_write_attribute<int>,
- tag_component_positions_changed);
+ tag_component_topology_changed);
static BuiltinCustomDataLayerProvider cyclic("cyclic",
ATTR_DOMAIN_CURVE,
@@ -515,6 +543,7 @@ static ComponentAttributeProviders create_attribute_providers_for_curve()
&handle_left,
&handle_type_right,
&handle_type_left,
+ &normal_mode,
&nurbs_order,
&nurbs_weight,
&curve_type,
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index 5fcb53acfcc..a2338eb9b39 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -157,6 +157,7 @@ void BKE_lib_override_library_copy(ID *dst_id, const ID *src_id, const bool do_f
id_us_plus(dst_id->override_library->reference);
dst_id->override_library->hierarchy_root = src_id->override_library->hierarchy_root;
+ dst_id->override_library->flag = src_id->override_library->flag;
if (do_full_copy) {
BLI_duplicatelist(&dst_id->override_library->properties,
diff --git a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
index 8a540f48c23..5e9d8e8c4d0 100644
--- a/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
+++ b/source/blender/blenkernel/intern/lib_override_proxy_conversion.c
@@ -9,6 +9,11 @@
#include "MEM_guardedalloc.h"
+#include "BLI_linklist.h"
+
+/* Required for proxy to liboverrides conversion code. */
+#define DNA_DEPRECATED_ALLOW
+
#include "DNA_ID.h"
#include "DNA_collection_types.h"
#include "DNA_object_types.h"
@@ -107,23 +112,29 @@ static void lib_override_library_proxy_convert_do(Main *bmain,
void BKE_lib_override_library_main_proxy_convert(Main *bmain, BlendFileReadReport *reports)
{
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
+ LinkNodePair proxy_objects = {NULL};
+
FOREACH_SCENE_OBJECT_BEGIN (scene, object) {
- if (object->proxy_group == NULL) {
- continue;
+ if (object->proxy_group != NULL) {
+ BLI_linklist_append(&proxy_objects, object);
}
-
- lib_override_library_proxy_convert_do(bmain, scene, object, reports);
}
FOREACH_SCENE_OBJECT_END;
FOREACH_SCENE_OBJECT_BEGIN (scene, object) {
- if (object->proxy == NULL) {
- continue;
+ if (object->proxy != NULL && object->proxy_group == NULL) {
+ BLI_linklist_append(&proxy_objects, object);
}
-
- lib_override_library_proxy_convert_do(bmain, scene, object, reports);
}
FOREACH_SCENE_OBJECT_END;
+
+ for (LinkNode *proxy_object_iter = proxy_objects.list; proxy_object_iter != NULL;
+ proxy_object_iter = proxy_object_iter->next) {
+ Object *proxy_object = proxy_object_iter->link;
+ lib_override_library_proxy_convert_do(bmain, scene, proxy_object, reports);
+ }
+
+ BLI_linklist_free(proxy_objects.list, NULL);
}
LISTBASE_FOREACH (Object *, object, &bmain->objects) {
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index f783121d02c..84aabbc7a9b 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -134,6 +134,14 @@ BLI_INLINE unsigned int clampis_uint(const unsigned int v,
return v < min ? min : (v > max ? max : v);
}
+static ScanFillVert *scanfill_vert_add_v2_with_depth(ScanFillContext *sf_ctx,
+ const float co_xy[2],
+ const float co_z)
+{
+ const float co[3] = {co_xy[0], co_xy[1], co_z};
+ return BLI_scanfill_vert_add(sf_ctx, co);
+}
+
/* --------------------------------------------------------------------- */
/* local structs for mask rasterizing */
/* --------------------------------------------------------------------- */
@@ -646,9 +654,6 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
ScanFillVert *sf_vert_prev;
unsigned int j;
- float co[3];
- co[2] = 0.0f;
-
sf_ctx.poly_nr++;
if (do_aspect_correct) {
@@ -704,8 +709,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
spline, diff_feather_points, tot_diff_feather_points);
}
- copy_v2_v2(co, diff_points[0]);
- sf_vert_prev = BLI_scanfill_vert_add(&sf_ctx, co);
+ sf_vert_prev = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_points[0], 0.0f);
sf_vert_prev->tmp.u = sf_vert_tot;
/* Absolute index of feather vert. */
@@ -713,10 +717,8 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
sf_vert_tot++;
- /* TODO: an alternate functions so we can avoid double vector copy! */
for (j = 1; j < tot_diff_point; j++) {
- copy_v2_v2(co, diff_points[j]);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
+ sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_points[j], 0.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = sf_vert_tot + tot_diff_point; /* absolute index of feather vert */
sf_vert_tot++;
@@ -741,16 +743,12 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
}
if (diff_feather_points) {
- float co_feather[3];
- co_feather[2] = 1.0f;
-
BLI_assert(tot_diff_feather_points == tot_diff_point);
/* NOTE: only added for convenience, we don't in fact use these to scan-fill,
* only to create feather faces after scan-fill. */
for (j = 0; j < tot_diff_feather_points; j++) {
- copy_v2_v2(co_feather, diff_feather_points[j]);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
+ sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_feather_points[j], 1.0f);
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
}
@@ -762,15 +760,11 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
/* unfilled spline */
if (diff_feather_points) {
- float co_diff[2];
-
- float co_feather[3];
- co_feather[2] = 1.0f;
-
if (spline->flag & MASK_SPLINE_NOINTERSECT) {
diff_feather_points_flip = MEM_mallocN(sizeof(float[2]) * tot_diff_feather_points,
"diff_feather_points_flip");
+ float co_diff[2];
for (j = 0; j < tot_diff_point; j++) {
sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]);
add_v2_v2v2(diff_feather_points_flip[j], diff_points[j], co_diff);
@@ -792,29 +786,29 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
for (j = 0; j < tot_diff_point; j++) {
/* center vert */
- copy_v2_v2(co, diff_points[j]);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co);
+ sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_points[j], 0.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
/* feather vert A */
- copy_v2_v2(co_feather, diff_feather_points[j]);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
+ sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, diff_feather_points[j], 1.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
/* feather vert B */
if (diff_feather_points_flip) {
- copy_v2_v2(co_feather, diff_feather_points_flip[j]);
+ sf_vert = scanfill_vert_add_v2_with_depth(
+ &sf_ctx, diff_feather_points_flip[j], 1.0f);
}
else {
- sub_v2_v2v2(co_diff, co, co_feather);
- add_v2_v2v2(co_feather, co, co_diff);
+ float co_diff[2];
+ sub_v2_v2v2(co_diff, diff_points[j], diff_feather_points[j]);
+ add_v2_v2v2(co_diff, diff_points[j], co_diff);
+ sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, co_diff, 1.0f);
}
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
@@ -857,9 +851,10 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
for (k = 1; k < vertex_total_cap; k++) {
const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
+ float co_feather[2];
rotate_point_v2(co_feather, fp_turn, fp_cent, angle, asp_xy);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
+ sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, co_feather, 1.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
@@ -877,9 +872,10 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle,
for (k = 1; k < vertex_total_cap; k++) {
const float angle = (float)k * (1.0f / (float)vertex_total_cap) * (float)M_PI;
+ float co_feather[2];
rotate_point_v2(co_feather, fp_turn, fp_cent, -angle, asp_xy);
- sf_vert = BLI_scanfill_vert_add(&sf_ctx, co_feather);
+ sf_vert = scanfill_vert_add_v2_with_depth(&sf_ctx, co_feather, 1.0f);
sf_vert->tmp.u = sf_vert_tot;
sf_vert->keyindex = SF_KEYINDEX_TEMP_ID;
sf_vert_tot++;
diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc
index 4e6191cca6f..0430269b75a 100644
--- a/source/blender/blenkernel/intern/scene.cc
+++ b/source/blender/blenkernel/intern/scene.cc
@@ -322,6 +322,7 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
SEQ_DUPE_ALL,
flag_subdata);
BLI_duplicatelist(&scene_dst->ed->channels, &scene_src->ed->channels);
+ scene_dst->ed->displayed_channels = &scene_dst->ed->channels;
}
if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) {
diff --git a/source/blender/blenkernel/intern/type_conversions.cc b/source/blender/blenkernel/intern/type_conversions.cc
index aa79199d668..e84ec5b3890 100644
--- a/source/blender/blenkernel/intern/type_conversions.cc
+++ b/source/blender/blenkernel/intern/type_conversions.cc
@@ -21,7 +21,7 @@ static void add_implicit_conversion(DataTypeConversions &conversions)
static fn::CustomMF_SI_SO<From, To> multi_function{
conversion_name.c_str(),
/* Use lambda instead of passing #ConversionF directly, because otherwise the compiler won't
- inline the function. */
+ * inline the function. */
[](const From &a) { return ConversionF(a); }};
static auto convert_single_to_initialized = [](const void *src, void *dst) {
*(To *)dst = ConversionF(*(const From *)src);