Curves: Add select pick operator #104406
|
@ -9,11 +9,13 @@
|
||||||
#include "BLI_rand.hh"
|
#include "BLI_rand.hh"
|
||||||
|
|
||||||
#include "BKE_attribute.hh"
|
#include "BKE_attribute.hh"
|
||||||
|
#include "BKE_crazyspace.hh"
|
||||||
#include "BKE_curves.hh"
|
#include "BKE_curves.hh"
|
||||||
|
|
||||||
#include "ED_curves.h"
|
#include "ED_curves.h"
|
||||||
#include "ED_object.h"
|
#include "ED_object.h"
|
||||||
#include "ED_select_utils.h"
|
#include "ED_select_utils.h"
|
||||||
|
#include "ED_view3d.h"
|
||||||
|
|
||||||
namespace blender::ed::curves {
|
namespace blender::ed::curves {
|
||||||
|
|
||||||
|
@ -283,4 +285,137 @@ void select_random(bke::CurvesGeometry &curves,
|
||||||
selection.finish();
|
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
|
} // namespace blender::ed::curves
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
struct bContext;
|
struct bContext;
|
||||||
struct Curves;
|
struct Curves;
|
||||||
struct UndoType;
|
struct UndoType;
|
||||||
|
struct SelectPick_Params;
|
||||||
|
struct ViewContext;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -134,6 +136,17 @@ void select_random(bke::CurvesGeometry &curves,
|
||||||
const eAttrDomain selection_domain,
|
const eAttrDomain selection_domain,
|
||||||
uint32_t random_seed,
|
uint32_t random_seed,
|
||||||
float probability);
|
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
|
} // namespace blender::ed::curves
|
||||||
|
|
|
@ -73,6 +73,7 @@ set(SRC
|
||||||
)
|
)
|
||||||
|
|
||||||
set(LIB
|
set(LIB
|
||||||
|
bf_editor_curves
|
||||||
bf_editor_lattice
|
bf_editor_lattice
|
||||||
bf_editor_mesh
|
bf_editor_mesh
|
||||||
)
|
)
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
|
|
||||||
#include "ED_armature.h"
|
#include "ED_armature.h"
|
||||||
#include "ED_curve.h"
|
#include "ED_curve.h"
|
||||||
|
#include "ED_curves.h"
|
||||||
#include "ED_gpencil.h"
|
#include "ED_gpencil.h"
|
||||||
#include "ED_lattice.h"
|
#include "ED_lattice.h"
|
||||||
#include "ED_mball.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)
|
static int view3d_select_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
|
using namespace blender;
|
||||||
Scene *scene = CTX_data_scene(C);
|
Scene *scene = CTX_data_scene(C);
|
||||||
Object *obedit = CTX_data_edit_object(C);
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
Object *obact = CTX_data_active_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{};
|
SelectPick_Params params{};
|
||||||
ED_select_pick_params_from_operator(op->ptr, ¶ms);
|
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) {
|
else if (obedit->type == OB_ARMATURE) {
|
||||||
if (enumerate) {
|
if (enumerate) {
|
||||||
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
|
||||||
ViewContext vc;
|
|
||||||
ED_view3d_viewcontext_init(C, &vc, depsgraph);
|
|
||||||
|
|
||||||
GPUSelectResult buffer[MAXPICKELEMS];
|
GPUSelectResult buffer[MAXPICKELEMS];
|
||||||
const int hits = mixed_bones_object_selectbuffer(
|
const int hits = mixed_bones_object_selectbuffer(
|
||||||
&vc, buffer, ARRAY_SIZE(buffer), mval, VIEW3D_SELECT_FILTER_NOP, false, true, false);
|
&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) {
|
else if (obedit->type == OB_FONT) {
|
||||||
changed = ED_curve_editfont_select_pick(C, mval, ¶ms);
|
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) {
|
else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) {
|
||||||
changed = PE_mouse_particles(C, mval, ¶ms);
|
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) {
|
if (ts->selectmode & SCE_SELECT_EDGE) {
|
||||||
/* Does both use_zbuf and non-use_zbuf versions (need screen cos for both) */
|
/* 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.data = &data;
|
||||||
cb_data.esel = use_zbuf ? esel : nullptr;
|
cb_data.esel = use_zbuf ? esel : nullptr;
|
||||||
cb_data.backbuf_offset = use_zbuf ? DRW_select_buffer_context_offset_for_object_elem(
|
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