forked from blender/blender
main sync #3
@ -167,7 +167,7 @@ bool has_anything_selected(const VArray<bool> &varray, const IndexRange range_to
|
||||
bool has_anything_selected(const bke::CurvesGeometry &curves)
|
||||
{
|
||||
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)
|
||||
@ -321,9 +321,9 @@ void select_random(bke::CurvesGeometry &curves,
|
||||
selection.finish();
|
||||
}
|
||||
|
||||
static void apply_selection_operation_at_index(GMutableSpan selection,
|
||||
const int index,
|
||||
const eSelectOp sel_op)
|
||||
void apply_selection_operation_at_index(GMutableSpan selection,
|
||||
const int index,
|
||||
const eSelectOp sel_op)
|
||||
{
|
||||
if (selection.type().is<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,
|
||||
const ARegion *region,
|
||||
const RegionView3D *rv3d,
|
||||
const Object &object,
|
||||
const bke::CurvesGeometry &curves,
|
||||
float2 mouse_pos,
|
||||
float radius,
|
||||
FindClosestData &closest_data)
|
||||
static std::optional<FindClosestData> find_closest_point_to_screen_co(
|
||||
const Depsgraph &depsgraph,
|
||||
const ARegion *region,
|
||||
const RegionView3D *rv3d,
|
||||
const Object &object,
|
||||
const bke::CurvesGeometry &curves,
|
||||
float2 mouse_pos,
|
||||
float radius,
|
||||
const FindClosestData &initial_closest)
|
||||
{
|
||||
float4x4 projection;
|
||||
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);
|
||||
|
||||
const float radius_sq = pow2f(radius);
|
||||
closest_data = threading::parallel_reduce(
|
||||
const FindClosestData new_closest_data = threading::parallel_reduce(
|
||||
curves.points_range(),
|
||||
1024,
|
||||
closest_data,
|
||||
initial_closest,
|
||||
[&](const IndexRange point_range, const FindClosestData &init) {
|
||||
FindClosestData best_match = init;
|
||||
for (const int point_i : point_range) {
|
||||
@ -411,21 +412,23 @@ static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph,
|
||||
}
|
||||
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,
|
||||
const ARegion *region,
|
||||
const RegionView3D *rv3d,
|
||||
const Object &object,
|
||||
const bke::CurvesGeometry &curves,
|
||||
float2 mouse_pos,
|
||||
float radius,
|
||||
FindClosestData &closest_data)
|
||||
static std::optional<FindClosestData> find_closest_curve_to_screen_co(
|
||||
const Depsgraph &depsgraph,
|
||||
const ARegion *region,
|
||||
const RegionView3D *rv3d,
|
||||
const Object &object,
|
||||
const bke::CurvesGeometry &curves,
|
||||
float2 mouse_pos,
|
||||
float radius,
|
||||
const FindClosestData &initial_closest)
|
||||
{
|
||||
float4x4 projection;
|
||||
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 OffsetIndices points_by_curve = curves.points_by_curve();
|
||||
closest_data = threading::parallel_reduce(
|
||||
const FindClosestData new_closest_data = threading::parallel_reduce(
|
||||
curves.curves_range(),
|
||||
256,
|
||||
closest_data,
|
||||
initial_closest,
|
||||
[&](const IndexRange curves_range, const FindClosestData &init) {
|
||||
FindClosestData best_match = init;
|
||||
for (const int curve_i : curves_range) {
|
||||
@ -499,64 +502,44 @@ static bool find_closest_curve_to_screen_co(const Depsgraph &depsgraph,
|
||||
return b;
|
||||
});
|
||||
|
||||
if (closest_data.index >= 0) {
|
||||
return true;
|
||||
if (new_closest_data.distance < initial_closest.distance) {
|
||||
return new_closest_data;
|
||||
}
|
||||
|
||||
return false;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool select_pick(const ViewContext &vc,
|
||||
const Object &object,
|
||||
bke::CurvesGeometry &curves,
|
||||
const eAttrDomain selection_domain,
|
||||
const SelectPick_Params ¶ms,
|
||||
const int2 coord,
|
||||
FindClosestData initial)
|
||||
std::optional<FindClosestData> closest_elem_find_screen_space(
|
||||
const ViewContext &vc,
|
||||
const Object &object,
|
||||
bke::CurvesGeometry &curves,
|
||||
const eAttrDomain domain,
|
||||
const int2 coord,
|
||||
const FindClosestData &initial_closest)
|
||||
{
|
||||
FindClosestData closest = initial;
|
||||
|
||||
bool found = false;
|
||||
if (selection_domain == ATTR_DOMAIN_POINT) {
|
||||
found = find_closest_point_to_screen_co(*vc.depsgraph,
|
||||
vc.region,
|
||||
vc.rv3d,
|
||||
object,
|
||||
curves,
|
||||
float2(coord),
|
||||
ED_view3d_select_dist_px(),
|
||||
closest);
|
||||
switch (domain) {
|
||||
case ATTR_DOMAIN_POINT:
|
||||
return find_closest_point_to_screen_co(*vc.depsgraph,
|
||||
vc.region,
|
||||
vc.rv3d,
|
||||
object,
|
||||
curves,
|
||||
float2(coord),
|
||||
ED_view3d_select_dist_px(),
|
||||
initial_closest);
|
||||
case ATTR_DOMAIN_CURVE:
|
||||
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,
|
||||
|
@ -115,6 +115,9 @@ bke::GSpanAttributeWriter ensure_selection_attribute(bke::CurvesGeometry &curves
|
||||
eAttrDomain selection_domain,
|
||||
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.
|
||||
*
|
||||
@ -149,7 +152,7 @@ void select_random(bke::CurvesGeometry &curves,
|
||||
float probability);
|
||||
|
||||
/**
|
||||
* Helper struct for `select_pick`.
|
||||
* Helper struct for `closest_elem_find_screen_space`.
|
||||
*/
|
||||
struct FindClosestData {
|
||||
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,
|
||||
const Object &object,
|
||||
bke::CurvesGeometry &curves,
|
||||
eAttrDomain selection_domain,
|
||||
const SelectPick_Params ¶ms,
|
||||
int2 coord,
|
||||
FindClosestData initial = {});
|
||||
std::optional<FindClosestData> closest_elem_find_screen_space(const ViewContext &vc,
|
||||
const Object &object,
|
||||
bke::CurvesGeometry &curves,
|
||||
eAttrDomain domain,
|
||||
int2 coord,
|
||||
const FindClosestData &initial);
|
||||
|
||||
/**
|
||||
* Select points or curves in a (screen-space) rectangle.
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "BLI_math_bits.h"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
@ -2985,8 +2986,13 @@ static bool ed_wpaint_vertex_select_pick(bContext *C,
|
||||
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.
|
||||
*/
|
||||
@ -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);
|
||||
|
||||
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);
|
||||
Span<Base *> bases(bases_ptr, bases_len);
|
||||
|
||||
bool changed = false;
|
||||
ed::curves::FindClosestData closest_data;
|
||||
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();
|
||||
Curves &active_curves_id = *static_cast<Curves *>(vc.obedit->data);
|
||||
const eAttrDomain selection_domain = eAttrDomain(active_curves_id.selection_domain);
|
||||
|
||||
if (ed::curves::select_pick(vc,
|
||||
*curves_ob,
|
||||
curves,
|
||||
eAttrDomain(curves_id.selection_domain),
|
||||
params,
|
||||
mval,
|
||||
closest_data)) {
|
||||
changed = 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);
|
||||
}
|
||||
const ClosestCurveDataBlock closest = threading::parallel_reduce(
|
||||
bases.index_range(),
|
||||
1L,
|
||||
ClosestCurveDataBlock(),
|
||||
[&](const IndexRange range, const ClosestCurveDataBlock &init) {
|
||||
ClosestCurveDataBlock new_closest = init;
|
||||
for (Base *base : bases.slice(range)) {
|
||||
Object &curves_ob = *base->object;
|
||||
Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
|
||||
std::optional<ed::curves::FindClosestData> new_closest_elem =
|
||||
ed::curves::closest_elem_find_screen_space(vc,
|
||||
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)
|
||||
@ -3081,7 +3133,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
|
||||
|
||||
if (obedit && enumerate) {
|
||||
/* 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) {
|
||||
return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user