diff options
author | Fabian Schempp <fabianschempp@googlemail.com> | 2022-04-11 08:14:28 +0300 |
---|---|---|
committer | Fabian Schempp <fabianschempp@googlemail.com> | 2022-04-11 08:14:28 +0300 |
commit | f06d361da1249c93568153bae88bcdf43b4774a1 (patch) | |
tree | 5acd7443d2c13d3f89b40e81f7d93df5e2a56008 /source/blender/blenkernel/intern | |
parent | ab6939ff78f131e5270e17b9ee73075b512a1a3f (diff) | |
parent | 5e47056e8d97e414c9dabacea71fac2bdc7d2818 (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.c | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curve_eval.cc | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curve_poly.cc | 154 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/curves_geometry.cc | 141 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/geometry_component_curves.cc | 133 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/lib_override.c | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/lib_override_proxy_conversion.c | 27 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mask_rasterize.c | 52 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/scene.cc | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/type_conversions.cc | 2 |
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 ¤t_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); |