Curves: Add select pick operator #104406
|
@ -9,11 +9,13 @@
|
|||
#include "BLI_rand.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_crazyspace.hh"
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
#include "ED_curves.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_select_utils.h"
|
||||
#include "ED_view3d.h"
|
||||
|
||||
namespace blender::ed::curves {
|
||||
|
||||
|
@ -283,4 +285,137 @@ void select_random(bke::CurvesGeometry &curves,
|
|||
selection.finish();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper struct for `find_closest_point_to_screen_co`.
|
||||
*/
|
||||
struct FindClosestPointData {
|
||||
int index = -1;
|
||||
float distance = FLT_MAX;
|
||||
};
|
||||
|
||||
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,
|
||||
FindClosestPointData &closest_data)
|
||||
{
|
||||
float4x4 projection;
|
||||
ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr());
|
||||
|
||||
const bke::crazyspace::GeometryDeformation deformation =
|
||||
bke::crazyspace::get_evaluated_curves_deformation(depsgraph, object);
|
||||
|
||||
const float radius_sq = pow2f(radius);
|
||||
auto [min_point_index, min_distance] = threading::parallel_reduce(
|
||||
curves.points_range(),
|
||||
1024,
|
||||
FindClosestPointData(),
|
||||
[&](const IndexRange point_range, const FindClosestPointData &init) {
|
||||
FindClosestPointData best_match = init;
|
||||
for (const int point_i : point_range) {
|
||||
const float3 pos = deformation.positions[point_i];
|
||||
|
||||
/* Find the position of the point in screen space. */
|
||||
float2 pos_proj;
|
||||
ED_view3d_project_float_v2_m4(region, pos, pos_proj, projection.ptr());
|
||||
|
||||
const float distance_proj_sq = math::distance_squared(pos_proj, mouse_pos);
|
||||
filedescriptor marked this conversation as resolved
|
||||
if (distance_proj_sq > radius_sq ||
|
||||
distance_proj_sq > best_match.distance * best_match.distance) {
|
||||
/* Ignore the point because it's too far away or there is already a better point. */
|
||||
continue;
|
||||
}
|
||||
|
||||
FindClosestPointData better_candidate;
|
||||
better_candidate.index = point_i;
|
||||
better_candidate.distance = std::sqrt(distance_proj_sq);
|
||||
|
||||
best_match = better_candidate;
|
||||
}
|
||||
return best_match;
|
||||
},
|
||||
[](const FindClosestPointData &a, const FindClosestPointData &b) {
|
||||
return std::min(a.distance, b.distance);
|
||||
});
|
||||
|
||||
if (min_point_index > 0) {
|
||||
closest_data.index = min_point_index;
|
||||
closest_data.distance = min_distance;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool select_pick(const ViewContext &vc,
|
||||
bke::CurvesGeometry &curves,
|
||||
const eAttrDomain selection_domain,
|
||||
const SelectPick_Params ¶ms,
|
||||
const int2 mval)
|
||||
{
|
||||
FindClosestPointData closest_point;
|
||||
bool found = find_closest_point_to_screen_co(*vc.depsgraph,
|
||||
vc.region,
|
||||
vc.rv3d,
|
||||
*vc.obact,
|
||||
curves,
|
||||
float2(mval),
|
||||
ED_view3d_select_dist_px(),
|
||||
closest_point);
|
||||
|
||||
bool changed = false;
|
||||
if (params.sel_op == SEL_OP_SET) {
|
||||
if (found || params.deselect_all) {
|
||||
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
|
||||
curves, selection_domain, CD_PROP_BOOL);
|
||||
fill_selection_false(selection.span);
|
||||
selection.finish();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
|
||||
curves, selection_domain, CD_PROP_BOOL);
|
||||
|
||||
int elem_index = closest_point.index;
|
||||
if (selection_domain == ATTR_DOMAIN_CURVE) {
|
||||
/* Find the curve index for the found point. */
|
||||
auto it = std::upper_bound(
|
||||
curves.offsets().begin(), curves.offsets().end(), closest_point.index);
|
||||
BLI_assert(it != curves.offsets().end());
|
||||
elem_index = std::distance(curves.offsets().begin(), it) - 1;
|
||||
}
|
||||
|
||||
selection.span.type().to_static_type_tag<bool, float>([&](auto type_tag) {
|
||||
using T = typename decltype(type_tag)::type;
|
||||
if constexpr (std::is_void_v<T>) {
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
else {
|
||||
MutableSpan<T> selection_typed = selection.span.typed<T>();
|
||||
switch (params.sel_op) {
|
||||
case SEL_OP_ADD:
|
||||
case SEL_OP_SET:
|
||||
selection_typed[elem_index] = T(1);
|
||||
break;
|
||||
case SEL_OP_SUB:
|
||||
selection_typed[elem_index] = T(0);
|
||||
break;
|
||||
case SEL_OP_XOR:
|
||||
selection_typed[elem_index] = T(1 - selection_typed[elem_index]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
selection.finish();
|
||||
}
|
||||
|
||||
return changed || found;
|
||||
}
|
||||
|
||||
} // namespace blender::ed::curves
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
struct bContext;
|
||||
struct Curves;
|
||||
struct UndoType;
|
||||
struct SelectPick_Params;
|
||||
struct ViewContext;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -134,6 +136,17 @@ void select_random(bke::CurvesGeometry &curves,
|
|||
const eAttrDomain selection_domain,
|
||||
uint32_t random_seed,
|
||||
float probability);
|
||||
|
||||
/**
|
||||
* Select point or curve under the cursor.
|
||||
*/
|
||||
bool select_pick(const ViewContext &vc,
|
||||
bke::CurvesGeometry &curves,
|
||||
const eAttrDomain selection_domain,
|
||||
const SelectPick_Params ¶ms,
|
||||
const int2 mval);
|
||||
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::ed::curves
|
||||
|
|
|
@ -73,6 +73,7 @@ set(SRC
|
|||
)
|
||||
|
||||
set(LIB
|
||||
bf_editor_curves
|
||||
bf_editor_lattice
|
||||
bf_editor_mesh
|
||||
)
|
||||
|
|
|
@ -69,6 +69,7 @@
|
|||
|
||||
#include "ED_armature.h"
|
||||
#include "ED_curve.h"
|
||||
#include "ED_curves.h"
|
||||
#include "ED_gpencil.h"
|
||||
#include "ED_lattice.h"
|
||||
#include "ED_mball.h"
|
||||
|
@ -2968,10 +2969,15 @@ static bool ed_wpaint_vertex_select_pick(bContext *C,
|
|||
|
||||
static int view3d_select_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
using namespace blender;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
Object *obact = CTX_data_active_object(C);
|
||||
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
ViewContext vc;
|
||||
ED_view3d_viewcontext_init(C, &vc, depsgraph);
|
||||
|
||||
SelectPick_Params params{};
|
||||
ED_select_pick_params_from_operator(op->ptr, ¶ms);
|
||||
|
||||
|
@ -3021,10 +3027,6 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
|
|||
}
|
||||
else if (obedit->type == OB_ARMATURE) {
|
||||
if (enumerate) {
|
||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
||||
ViewContext vc;
|
||||
ED_view3d_viewcontext_init(C, &vc, depsgraph);
|
||||
|
||||
GPUSelectResult buffer[MAXPICKELEMS];
|
||||
const int hits = mixed_bones_object_selectbuffer(
|
||||
&vc, buffer, ARRAY_SIZE(buffer), mval, VIEW3D_SELECT_FILTER_NOP, false, true, false);
|
||||
|
@ -3047,6 +3049,19 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
|
|||
else if (obedit->type == OB_FONT) {
|
||||
changed = ED_curve_editfont_select_pick(C, mval, ¶ms);
|
||||
}
|
||||
else if (obedit->type == OB_CURVES) {
|
||||
Curves &curves_id = *static_cast<Curves *>(obact->data);
|
||||
bke::CurvesGeometry &curves = curves_id.geometry.wrap();
|
||||
changed = ed::curves::select_pick(
|
||||
vc, curves, eAttrDomain(curves_id.selection_domain), params, mval);
|
||||
if (changed) {
|
||||
/* 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);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
|
||||
changed = PE_mouse_particles(C, mval, ¶ms);
|
||||
|
@ -3535,8 +3550,7 @@ static bool do_mesh_box_select(ViewContext *vc,
|
|||
}
|
||||
if (ts->selectmode & SCE_SELECT_EDGE) {
|
||||
/* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */
|
||||
struct BoxSelectUserData_ForMeshEdge cb_data {
|
||||
};
|
||||
struct BoxSelectUserData_ForMeshEdge cb_data {};
|
||||
cb_data.data = &data;
|
||||
cb_data.esel = use_zbuf ? esel : nullptr;
|
||||
cb_data.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
|
||||
|
|
Loading…
Reference in New Issue
distance_proj_sq
feels a bit more consistent/natural IMO