main sync #3

Merged
Patrick Busch merged 318 commits from blender/blender:main into main 2023-03-17 15:52:21 +01:00
3 changed files with 154 additions and 114 deletions
Showing only changes of commit 281f383c23 - Show all commits

View File

@ -167,7 +167,7 @@ bool has_anything_selected(const VArray<bool> &varray, const IndexRange range_to
bool has_anything_selected(const bke::CurvesGeometry &curves) bool has_anything_selected(const bke::CurvesGeometry &curves)
{ {
const VArray<bool> selection = curves.attributes().lookup<bool>(".selection"); const VArray<bool> selection = curves.attributes().lookup<bool>(".selection");
return !selection || contains(selection, curves.curves_range(), true); return !selection || contains(selection, selection.index_range(), true);
} }
bool has_anything_selected(const GSpan selection) bool has_anything_selected(const GSpan selection)
@ -321,9 +321,9 @@ void select_random(bke::CurvesGeometry &curves,
selection.finish(); selection.finish();
} }
static void apply_selection_operation_at_index(GMutableSpan selection, void apply_selection_operation_at_index(GMutableSpan selection,
const int index, const int index,
const eSelectOp sel_op) const eSelectOp sel_op)
{ {
if (selection.type().is<bool>()) { if (selection.type().is<bool>()) {
MutableSpan<bool> selection_typed = selection.typed<bool>(); MutableSpan<bool> selection_typed = selection.typed<bool>();
@ -361,14 +361,15 @@ static void apply_selection_operation_at_index(GMutableSpan selection,
} }
} }
static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph, static std::optional<FindClosestData> find_closest_point_to_screen_co(
const ARegion *region, const Depsgraph &depsgraph,
const RegionView3D *rv3d, const ARegion *region,
const Object &object, const RegionView3D *rv3d,
const bke::CurvesGeometry &curves, const Object &object,
float2 mouse_pos, const bke::CurvesGeometry &curves,
float radius, float2 mouse_pos,
FindClosestData &closest_data) float radius,
const FindClosestData &initial_closest)
{ {
float4x4 projection; float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr()); ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr());
@ -377,10 +378,10 @@ static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph,
bke::crazyspace::get_evaluated_curves_deformation(depsgraph, object); bke::crazyspace::get_evaluated_curves_deformation(depsgraph, object);
const float radius_sq = pow2f(radius); const float radius_sq = pow2f(radius);
closest_data = threading::parallel_reduce( const FindClosestData new_closest_data = threading::parallel_reduce(
curves.points_range(), curves.points_range(),
1024, 1024,
closest_data, initial_closest,
[&](const IndexRange point_range, const FindClosestData &init) { [&](const IndexRange point_range, const FindClosestData &init) {
FindClosestData best_match = init; FindClosestData best_match = init;
for (const int point_i : point_range) { for (const int point_i : point_range) {
@ -411,21 +412,23 @@ static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph,
} }
return b; return b;
}); });
if (closest_data.index >= 0) {
return true; if (new_closest_data.distance < initial_closest.distance) {
return new_closest_data;
} }
return false; return {};
} }
static bool find_closest_curve_to_screen_co(const Depsgraph &depsgraph, static std::optional<FindClosestData> find_closest_curve_to_screen_co(
const ARegion *region, const Depsgraph &depsgraph,
const RegionView3D *rv3d, const ARegion *region,
const Object &object, const RegionView3D *rv3d,
const bke::CurvesGeometry &curves, const Object &object,
float2 mouse_pos, const bke::CurvesGeometry &curves,
float radius, float2 mouse_pos,
FindClosestData &closest_data) float radius,
const FindClosestData &initial_closest)
{ {
float4x4 projection; float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr()); ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr());
@ -436,10 +439,10 @@ static bool find_closest_curve_to_screen_co(const Depsgraph &depsgraph,
const float radius_sq = pow2f(radius); const float radius_sq = pow2f(radius);
const OffsetIndices points_by_curve = curves.points_by_curve(); const OffsetIndices points_by_curve = curves.points_by_curve();
closest_data = threading::parallel_reduce( const FindClosestData new_closest_data = threading::parallel_reduce(
curves.curves_range(), curves.curves_range(),
256, 256,
closest_data, initial_closest,
[&](const IndexRange curves_range, const FindClosestData &init) { [&](const IndexRange curves_range, const FindClosestData &init) {
FindClosestData best_match = init; FindClosestData best_match = init;
for (const int curve_i : curves_range) { for (const int curve_i : curves_range) {
@ -499,64 +502,44 @@ static bool find_closest_curve_to_screen_co(const Depsgraph &depsgraph,
return b; return b;
}); });
if (closest_data.index >= 0) { if (new_closest_data.distance < initial_closest.distance) {
return true; return new_closest_data;
} }
return false; return {};
} }
bool select_pick(const ViewContext &vc, std::optional<FindClosestData> closest_elem_find_screen_space(
const Object &object, const ViewContext &vc,
bke::CurvesGeometry &curves, const Object &object,
const eAttrDomain selection_domain, bke::CurvesGeometry &curves,
const SelectPick_Params &params, const eAttrDomain domain,
const int2 coord, const int2 coord,
FindClosestData initial) const FindClosestData &initial_closest)
{ {
FindClosestData closest = initial; switch (domain) {
case ATTR_DOMAIN_POINT:
bool found = false; return find_closest_point_to_screen_co(*vc.depsgraph,
if (selection_domain == ATTR_DOMAIN_POINT) { vc.region,
found = find_closest_point_to_screen_co(*vc.depsgraph, vc.rv3d,
vc.region, object,
vc.rv3d, curves,
object, float2(coord),
curves, ED_view3d_select_dist_px(),
float2(coord), initial_closest);
ED_view3d_select_dist_px(), case ATTR_DOMAIN_CURVE:
closest); return find_closest_curve_to_screen_co(*vc.depsgraph,
vc.region,
vc.rv3d,
object,
curves,
float2(coord),
ED_view3d_select_dist_px(),
initial_closest);
default:
BLI_assert_unreachable();
return {};
} }
else if (selection_domain == ATTR_DOMAIN_CURVE) {
found = find_closest_curve_to_screen_co(*vc.depsgraph,
vc.region,
vc.rv3d,
object,
curves,
float2(coord),
ED_view3d_select_dist_px(),
closest);
}
bool deselected = false;
if (params.sel_op == SEL_OP_SET) {
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
if (found || ((params.deselect_all && has_anything_selected(selection.span)))) {
fill_selection_false(selection.span);
deselected = true;
}
selection.finish();
}
if (found) {
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
apply_selection_operation_at_index(selection.span, closest.index, params.sel_op);
selection.finish();
}
return deselected || found;
} }
bool select_box(const ViewContext &vc, bool select_box(const ViewContext &vc,

View File

@ -115,6 +115,9 @@ bke::GSpanAttributeWriter ensure_selection_attribute(bke::CurvesGeometry &curves
eAttrDomain selection_domain, eAttrDomain selection_domain,
eCustomDataType create_type); eCustomDataType create_type);
/** Apply a change to a single curve or point. Avoid using this when affecting many elements. */
void apply_selection_operation_at_index(GMutableSpan selection, int index, eSelectOp sel_op);
/** /**
* (De)select all the curves. * (De)select all the curves.
* *
@ -149,7 +152,7 @@ void select_random(bke::CurvesGeometry &curves,
float probability); float probability);
/** /**
* Helper struct for `select_pick`. * Helper struct for `closest_elem_find_screen_space`.
*/ */
struct FindClosestData { struct FindClosestData {
int index = -1; int index = -1;
@ -157,15 +160,16 @@ struct FindClosestData {
}; };
/** /**
* Select point or curve at a (screen-space) point. * Find the closest screen-space point or curve in projected region-space.
*
* \return A new point or curve closer than the \a initial input, if one exists.
*/ */
bool select_pick(const ViewContext &vc, std::optional<FindClosestData> closest_elem_find_screen_space(const ViewContext &vc,
const Object &object, const Object &object,
bke::CurvesGeometry &curves, bke::CurvesGeometry &curves,
eAttrDomain selection_domain, eAttrDomain domain,
const SelectPick_Params &params, int2 coord,
int2 coord, const FindClosestData &initial);
FindClosestData initial = {});
/** /**
* Select points or curves in a (screen-space) rectangle. * Select points or curves in a (screen-space) rectangle.

View File

@ -31,6 +31,7 @@
#include "BLI_math_bits.h" #include "BLI_math_bits.h"
#include "BLI_rect.h" #include "BLI_rect.h"
#include "BLI_string.h" #include "BLI_string.h"
#include "BLI_task.hh"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BLI_vector.hh" #include "BLI_vector.hh"
@ -2985,9 +2986,14 @@ static bool ed_wpaint_vertex_select_pick(bContext *C,
return changed || found; return changed || found;
} }
struct ClosestCurveDataBlock {
Curves *curves_id = nullptr;
blender::ed::curves::FindClosestData elem = {};
};
/** /**
* Cursor selection for the Curves object. * Cursor selection for all Curves objects in edit mode.
* *
* \returns true if the selection changed. * \returns true if the selection changed.
*/ */
static bool ed_curves_select_pick(bContext &C, const int mval[2], const SelectPick_Params &params) static bool ed_curves_select_pick(bContext &C, const int mval[2], const SelectPick_Params &params)
@ -2999,35 +3005,81 @@ static bool ed_curves_select_pick(bContext &C, const int mval[2], const SelectPi
ED_view3d_viewcontext_init(&C, &vc, depsgraph); ED_view3d_viewcontext_init(&C, &vc, depsgraph);
uint bases_len; uint bases_len;
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( Base **bases_ptr = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
vc.scene, vc.view_layer, vc.v3d, &bases_len); vc.scene, vc.view_layer, vc.v3d, &bases_len);
Span<Base *> bases(bases_ptr, bases_len);
bool changed = false; Curves &active_curves_id = *static_cast<Curves *>(vc.obedit->data);
ed::curves::FindClosestData closest_data; const eAttrDomain selection_domain = eAttrDomain(active_curves_id.selection_domain);
for (uint base_index = 0; base_index < bases_len; base_index++) {
Base *base = bases[base_index];
Object *curves_ob = base->object;
Curves &curves_id = *static_cast<Curves *>(curves_ob->data);
bke::CurvesGeometry &curves = curves_id.geometry.wrap();
if (ed::curves::select_pick(vc, const ClosestCurveDataBlock closest = threading::parallel_reduce(
*curves_ob, bases.index_range(),
curves, 1L,
eAttrDomain(curves_id.selection_domain), ClosestCurveDataBlock(),
params, [&](const IndexRange range, const ClosestCurveDataBlock &init) {
mval, ClosestCurveDataBlock new_closest = init;
closest_data)) { for (Base *base : bases.slice(range)) {
changed = true; Object &curves_ob = *base->object;
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
* generic attribute for now. */ std::optional<ed::curves::FindClosestData> new_closest_elem =
DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY); ed::curves::closest_elem_find_screen_space(vc,
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &curves_id); curves_ob,
} curves_id.geometry.wrap(),
selection_domain,
mval,
new_closest.elem);
if (new_closest_elem) {
new_closest.elem = *new_closest_elem;
new_closest.curves_id = &curves_id;
}
}
return new_closest;
},
[](const ClosestCurveDataBlock &a, const ClosestCurveDataBlock &b) {
return (a.elem.distance < b.elem.distance) ? a : b;
});
std::atomic<bool> deselected = false;
if (params.deselect_all || params.sel_op == SEL_OP_SET) {
threading::parallel_for(bases.index_range(), 1L, [&](const IndexRange range) {
for (Base *base : bases.slice(range)) {
Curves &curves_id = *static_cast<Curves *>(base->object->data);
bke::CurvesGeometry &curves = curves_id.geometry.wrap();
if (ed::curves::has_anything_selected(curves)) {
bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
ed::curves::fill_selection_false(selection.span);
selection.finish();
deselected = true;
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
* generic attribute for now. */
DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &curves_id);
}
}
});
} }
MEM_freeN(bases); if (!closest.curves_id) {
MEM_freeN(bases_ptr);
return deselected;
}
return changed; bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute(
closest.curves_id->geometry.wrap(), selection_domain, CD_PROP_BOOL);
ed::curves::apply_selection_operation_at_index(
selection.span, closest.elem.index, params.sel_op);
selection.finish();
/* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a
* generic attribute for now. */
DEG_id_tag_update(&closest.curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(&C, NC_GEOM | ND_DATA, closest.curves_id);
MEM_freeN(bases_ptr);
return true;
} }
static int view3d_select_exec(bContext *C, wmOperator *op) static int view3d_select_exec(bContext *C, wmOperator *op)
@ -3081,7 +3133,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
if (obedit && enumerate) { if (obedit && enumerate) {
/* Enumerate makes no sense in edit-mode unless also explicitly picking objects or bones. /* Enumerate makes no sense in edit-mode unless also explicitly picking objects or bones.
* Pass the event through so the event may be handled by loop-select for e.g. see: #100204. */ * Pass the event through so the event may be handled by loop-select for e.g. see: #100204.
*/
if (obedit->type != OB_ARMATURE) { if (obedit->type != OB_ARMATURE) {
return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED; return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED;
} }