When a change happens which invalidates view layers the syncing will be postponed until the first usage.
This will improve importing or adding many objects in a single operation/script.
`BKE_view_layer_need_resync_tag` is used to tag the view layer to be out of sync. Before accessing
`BKE_view_layer_active_base_get`, `BKE_view_layer_active_object_get`, `BKE_view_layer_active_collection`
or `BKE_view_layer_object_bases` the caller should call `BKE_view_layer_synced_ensure`.
Having two functions ensures that partial syncing could be added as smaller patches in the future. Tagging a
view layer out of sync could be replaced with a partial sync. Eventually the number of full resyncs could be
reduced. After all tagging has been replaced with partial syncs the ensure_sync could be phased out.
This patch has been added to discuss the details and consequences of the current approach. For clarity
the call to BKE_view_layer_ensure_sync is placed close to the getters.
In the future this could be placed in more strategical places to reduce the number of calls or improve
performance. Finding those strategical places isn't that clear. When multiple operations are grouped
in a single script you might want to always check for resync.
Some areas found that can be improved. This list isn't complete.
These areas aren't addressed by this patch as these changes would be hard to detect to the reviewer.
The idea is to add changes to these areas as a separate patch. It might be that the initial commit would reduce
performance compared to master, but will be fixed by the additional patches.
**Object duplication**
During object duplication the syncing is temporarily disabled. With this patch this isn't useful as when disabled
the view_layer is accessed to locate bases. This can be improved by first locating the source bases, then duplicate
and sync and locate the new bases. Will be solved in a separate patch for clarity reasons ({D15886}).
**Object add**
`BKE_object_add` not only adds a new object, but also selects and activates the new base. This requires the
view_layer to be resynced. Some callers reverse the selection and activation (See `get_new_constraint_target`).
We should make the selection and activation optional. This would make it possible to add multiple objects
without having to resync per object.
**Postpone Activate Base**
Setting the basact is done in many locations. They follow a rule as after an action find the base and set
the basact. Finding the base could require a resync. The idea is to store in the view_layer the object which
base will be set in the basact during the next sync, reducing the times resyncing needs to happen.
Reviewed By: mont29
Maniphest Tasks: T73411
Differential Revision: https://developer.blender.org/D15885
703 lines
18 KiB
C
703 lines
18 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
|
|
|
|
/** \file
|
|
* \ingroup edlattice
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_bitmap.h"
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_math.h"
|
|
#include "BLI_rand.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "DNA_curve_types.h"
|
|
#include "DNA_lattice_types.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "RNA_access.h"
|
|
#include "RNA_define.h"
|
|
#include "RNA_enum_types.h"
|
|
|
|
#include "BKE_context.h"
|
|
#include "BKE_lattice.h"
|
|
#include "BKE_layer.h"
|
|
#include "BKE_report.h"
|
|
|
|
#include "ED_lattice.h"
|
|
#include "ED_object.h"
|
|
#include "ED_screen.h"
|
|
#include "ED_select_utils.h"
|
|
#include "ED_view3d.h"
|
|
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
|
|
#include "DEG_depsgraph.h"
|
|
|
|
#include "lattice_intern.h"
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Utility Functions
|
|
* \{ */
|
|
|
|
static void bpoint_select_set(BPoint *bp, bool select)
|
|
{
|
|
if (select) {
|
|
if (!bp->hide) {
|
|
bp->f1 |= SELECT;
|
|
}
|
|
}
|
|
else {
|
|
bp->f1 &= ~SELECT;
|
|
}
|
|
}
|
|
|
|
bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len)
|
|
{
|
|
bool changed_multi = false;
|
|
for (uint base_index = 0; base_index < bases_len; base_index++) {
|
|
Base *base_iter = bases[base_index];
|
|
Object *ob_iter = base_iter->object;
|
|
changed_multi |= ED_lattice_flags_set(ob_iter, 0);
|
|
DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT);
|
|
}
|
|
return changed_multi;
|
|
}
|
|
|
|
bool ED_lattice_deselect_all_multi(struct bContext *C)
|
|
{
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
|
ViewContext vc;
|
|
ED_view3d_viewcontext_init(C, &vc, depsgraph);
|
|
uint bases_len = 0;
|
|
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
|
|
vc.scene, vc.view_layer, vc.v3d, &bases_len);
|
|
bool changed_multi = ED_lattice_deselect_all_multi_ex(bases, bases_len);
|
|
MEM_freeN(bases);
|
|
return changed_multi;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Select Random Operator
|
|
* \{ */
|
|
|
|
static int lattice_select_random_exec(bContext *C, wmOperator *op)
|
|
{
|
|
const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT);
|
|
const float randfac = RNA_float_get(op->ptr, "ratio");
|
|
const int seed = WM_operator_properties_select_random_seed_increment_get(op);
|
|
|
|
const Scene *scene = CTX_data_scene(C);
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
|
uint objects_len = 0;
|
|
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
|
|
scene, view_layer, CTX_wm_view3d(C), &objects_len);
|
|
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
|
Object *obedit = objects[ob_index];
|
|
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
|
|
int seed_iter = seed;
|
|
|
|
/* This gives a consistent result regardless of object order. */
|
|
if (ob_index) {
|
|
seed_iter += BLI_ghashutil_strhash_p(obedit->id.name);
|
|
}
|
|
|
|
int a = lt->pntsu * lt->pntsv * lt->pntsw;
|
|
int elem_map_len = 0;
|
|
BPoint **elem_map = MEM_mallocN(sizeof(*elem_map) * a, __func__);
|
|
BPoint *bp = lt->def;
|
|
|
|
while (a--) {
|
|
if (!bp->hide) {
|
|
elem_map[elem_map_len++] = bp;
|
|
}
|
|
bp++;
|
|
}
|
|
|
|
BLI_array_randomize(elem_map, sizeof(*elem_map), elem_map_len, seed_iter);
|
|
const int count_select = elem_map_len * randfac;
|
|
for (int i = 0; i < count_select; i++) {
|
|
bpoint_select_set(elem_map[i], select);
|
|
}
|
|
MEM_freeN(elem_map);
|
|
|
|
if (select == false) {
|
|
lt->actbp = LT_ACTBP_NONE;
|
|
}
|
|
|
|
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
|
}
|
|
MEM_freeN(objects);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void LATTICE_OT_select_random(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Select Random";
|
|
ot->description = "Randomly select UVW control points";
|
|
ot->idname = "LATTICE_OT_select_random";
|
|
|
|
/* api callbacks */
|
|
ot->exec = lattice_select_random_exec;
|
|
ot->poll = ED_operator_editlattice;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
/* props */
|
|
WM_operator_properties_select_random(ot);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Select Mirror Operator
|
|
* \{ */
|
|
|
|
static void ed_lattice_select_mirrored(Lattice *lt, const int axis, const bool extend)
|
|
{
|
|
const int tot = lt->pntsu * lt->pntsv * lt->pntsw;
|
|
|
|
bool flip_uvw[3] = {false};
|
|
flip_uvw[axis] = true;
|
|
|
|
/* we could flip this too */
|
|
if (!extend) {
|
|
lt->actbp = LT_ACTBP_NONE;
|
|
}
|
|
|
|
/* store "original" selection */
|
|
BLI_bitmap *selpoints = BLI_BITMAP_NEW(tot, __func__);
|
|
BKE_lattice_bitmap_from_flag(lt, selpoints, SELECT, false, false);
|
|
|
|
/* actual (de)selection */
|
|
for (int i = 0; i < tot; i++) {
|
|
const int i_flip = BKE_lattice_index_flip(lt, i, flip_uvw[0], flip_uvw[1], flip_uvw[2]);
|
|
BPoint *bp = <->def[i];
|
|
if (!bp->hide) {
|
|
if (BLI_BITMAP_TEST(selpoints, i_flip)) {
|
|
bp->f1 |= SELECT;
|
|
}
|
|
else {
|
|
if (!extend) {
|
|
bp->f1 &= ~SELECT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
MEM_freeN(selpoints);
|
|
}
|
|
|
|
static int lattice_select_mirror_exec(bContext *C, wmOperator *op)
|
|
{
|
|
const int axis_flag = RNA_enum_get(op->ptr, "axis");
|
|
const bool extend = RNA_boolean_get(op->ptr, "extend");
|
|
|
|
const Scene *scene = CTX_data_scene(C);
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
|
uint objects_len = 0;
|
|
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
|
|
scene, view_layer, CTX_wm_view3d(C), &objects_len);
|
|
|
|
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
|
Object *obedit = objects[ob_index];
|
|
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
|
|
|
|
for (int axis = 0; axis < 3; axis++) {
|
|
if ((1 << axis) & axis_flag) {
|
|
ed_lattice_select_mirrored(lt, axis, extend);
|
|
}
|
|
}
|
|
|
|
/* TODO: only notify changes. */
|
|
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
|
}
|
|
MEM_freeN(objects);
|
|
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void LATTICE_OT_select_mirror(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Select Mirror";
|
|
ot->description = "Select mirrored lattice points";
|
|
ot->idname = "LATTICE_OT_select_mirror";
|
|
|
|
/* api callbacks */
|
|
ot->exec = lattice_select_mirror_exec;
|
|
ot->poll = ED_operator_editlattice;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
/* props */
|
|
RNA_def_enum_flag(ot->srna, "axis", rna_enum_axis_flag_xyz_items, (1 << 0), "Axis", "");
|
|
|
|
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Select More/Less Operator
|
|
* \{ */
|
|
|
|
static bool lattice_test_bitmap_uvw(
|
|
Lattice *lt, const BLI_bitmap *selpoints, int u, int v, int w, const bool selected)
|
|
{
|
|
if ((u < 0 || u >= lt->pntsu) || (v < 0 || v >= lt->pntsv) || (w < 0 || w >= lt->pntsw)) {
|
|
return false;
|
|
}
|
|
|
|
int i = BKE_lattice_index_from_uvw(lt, u, v, w);
|
|
if (lt->def[i].hide == 0) {
|
|
return (BLI_BITMAP_TEST(selpoints, i) != 0) == selected;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static int lattice_select_more_less(bContext *C, const bool select)
|
|
{
|
|
const Scene *scene = CTX_data_scene(C);
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
|
uint objects_len;
|
|
bool changed = false;
|
|
|
|
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
|
|
scene, view_layer, CTX_wm_view3d(C), &objects_len);
|
|
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
|
Object *obedit = objects[ob_index];
|
|
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
|
|
BPoint *bp;
|
|
const int tot = lt->pntsu * lt->pntsv * lt->pntsw;
|
|
int u, v, w;
|
|
BLI_bitmap *selpoints;
|
|
|
|
lt->actbp = LT_ACTBP_NONE;
|
|
|
|
selpoints = BLI_BITMAP_NEW(tot, __func__);
|
|
BKE_lattice_bitmap_from_flag(lt, selpoints, SELECT, false, false);
|
|
|
|
bp = lt->def;
|
|
for (w = 0; w < lt->pntsw; w++) {
|
|
for (v = 0; v < lt->pntsv; v++) {
|
|
for (u = 0; u < lt->pntsu; u++) {
|
|
if ((bp->hide == 0) && (((bp->f1 & SELECT) == 0) == select)) {
|
|
if (lattice_test_bitmap_uvw(lt, selpoints, u + 1, v, w, select) ||
|
|
lattice_test_bitmap_uvw(lt, selpoints, u - 1, v, w, select) ||
|
|
lattice_test_bitmap_uvw(lt, selpoints, u, v + 1, w, select) ||
|
|
lattice_test_bitmap_uvw(lt, selpoints, u, v - 1, w, select) ||
|
|
lattice_test_bitmap_uvw(lt, selpoints, u, v, w + 1, select) ||
|
|
lattice_test_bitmap_uvw(lt, selpoints, u, v, w - 1, select)) {
|
|
SET_FLAG_FROM_TEST(bp->f1, select, SELECT);
|
|
}
|
|
}
|
|
bp++;
|
|
}
|
|
}
|
|
}
|
|
|
|
MEM_freeN(selpoints);
|
|
|
|
changed = true;
|
|
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
|
}
|
|
MEM_freeN(objects);
|
|
|
|
return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
|
|
}
|
|
|
|
static int lattice_select_more_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
return lattice_select_more_less(C, true);
|
|
}
|
|
|
|
static int lattice_select_less_exec(bContext *C, wmOperator *UNUSED(op))
|
|
{
|
|
return lattice_select_more_less(C, false);
|
|
}
|
|
|
|
void LATTICE_OT_select_more(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Select More";
|
|
ot->description = "Select vertex directly linked to already selected ones";
|
|
ot->idname = "LATTICE_OT_select_more";
|
|
|
|
/* api callbacks */
|
|
ot->exec = lattice_select_more_exec;
|
|
ot->poll = ED_operator_editlattice;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
}
|
|
|
|
void LATTICE_OT_select_less(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Select Less";
|
|
ot->description = "Deselect vertices at the boundary of each selection region";
|
|
ot->idname = "LATTICE_OT_select_less";
|
|
|
|
/* api callbacks */
|
|
ot->exec = lattice_select_less_exec;
|
|
ot->poll = ED_operator_editlattice;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Select All Operator
|
|
* \{ */
|
|
|
|
bool ED_lattice_flags_set(Object *obedit, int flag)
|
|
{
|
|
Lattice *lt = obedit->data;
|
|
BPoint *bp;
|
|
int a;
|
|
bool changed = false;
|
|
|
|
bp = lt->editlatt->latt->def;
|
|
|
|
a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
|
|
|
|
if (lt->editlatt->latt->actbp != LT_ACTBP_NONE) {
|
|
lt->editlatt->latt->actbp = LT_ACTBP_NONE;
|
|
changed = true;
|
|
}
|
|
|
|
while (a--) {
|
|
if (bp->hide == 0) {
|
|
if (bp->f1 != flag) {
|
|
bp->f1 = flag;
|
|
changed = true;
|
|
}
|
|
}
|
|
bp++;
|
|
}
|
|
return changed;
|
|
}
|
|
|
|
static int lattice_select_all_exec(bContext *C, wmOperator *op)
|
|
{
|
|
const Scene *scene = CTX_data_scene(C);
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
|
int action = RNA_enum_get(op->ptr, "action");
|
|
|
|
uint objects_len = 0;
|
|
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
|
|
scene, view_layer, CTX_wm_view3d(C), &objects_len);
|
|
|
|
if (action == SEL_TOGGLE) {
|
|
action = SEL_SELECT;
|
|
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
|
Object *obedit = objects[ob_index];
|
|
Lattice *lt = obedit->data;
|
|
if (BKE_lattice_is_any_selected(lt->editlatt->latt)) {
|
|
action = SEL_DESELECT;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool changed_multi = false;
|
|
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
|
Object *obedit = objects[ob_index];
|
|
Lattice *lt;
|
|
BPoint *bp;
|
|
int a;
|
|
bool changed = false;
|
|
|
|
switch (action) {
|
|
case SEL_SELECT:
|
|
changed = ED_lattice_flags_set(obedit, 1);
|
|
break;
|
|
case SEL_DESELECT:
|
|
changed = ED_lattice_flags_set(obedit, 0);
|
|
break;
|
|
case SEL_INVERT:
|
|
lt = obedit->data;
|
|
bp = lt->editlatt->latt->def;
|
|
a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
|
|
lt->editlatt->latt->actbp = LT_ACTBP_NONE;
|
|
|
|
while (a--) {
|
|
if (bp->hide == 0) {
|
|
bp->f1 ^= SELECT;
|
|
changed = true;
|
|
}
|
|
bp++;
|
|
}
|
|
break;
|
|
}
|
|
if (changed) {
|
|
changed_multi = true;
|
|
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
|
}
|
|
}
|
|
MEM_freeN(objects);
|
|
|
|
if (changed_multi) {
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
void LATTICE_OT_select_all(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "(De)select All";
|
|
ot->description = "Change selection of all UVW control points";
|
|
ot->idname = "LATTICE_OT_select_all";
|
|
|
|
/* api callbacks */
|
|
ot->exec = lattice_select_all_exec;
|
|
ot->poll = ED_operator_editlattice;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
WM_operator_properties_select_all(ot);
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Select Ungrouped Verts Operator
|
|
* \{ */
|
|
|
|
static int lattice_select_ungrouped_exec(bContext *C, wmOperator *op)
|
|
{
|
|
const Scene *scene = CTX_data_scene(C);
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
|
uint objects_len;
|
|
const bool is_extend = RNA_boolean_get(op->ptr, "extend");
|
|
bool changed = false;
|
|
|
|
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
|
|
scene, view_layer, CTX_wm_view3d(C), &objects_len);
|
|
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
|
Object *obedit = objects[ob_index];
|
|
Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
|
|
MDeformVert *dv;
|
|
BPoint *bp;
|
|
int a, tot;
|
|
|
|
if (BLI_listbase_is_empty(<->vertex_group_names) || lt->dvert == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (!is_extend) {
|
|
ED_lattice_flags_set(obedit, 0);
|
|
}
|
|
|
|
dv = lt->dvert;
|
|
tot = lt->pntsu * lt->pntsv * lt->pntsw;
|
|
|
|
for (a = 0, bp = lt->def; a < tot; a++, bp++, dv++) {
|
|
if (bp->hide == 0) {
|
|
if (dv->dw == NULL) {
|
|
bp->f1 |= SELECT;
|
|
}
|
|
}
|
|
}
|
|
|
|
changed = true;
|
|
DEG_id_tag_update(obedit->data, ID_RECALC_SELECT);
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
|
|
}
|
|
MEM_freeN(objects);
|
|
|
|
if (!changed) {
|
|
BKE_report(op->reports, RPT_ERROR, "No weights/vertex groups on object(s)");
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
|
|
void LATTICE_OT_select_ungrouped(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Select Ungrouped";
|
|
ot->idname = "LATTICE_OT_select_ungrouped";
|
|
ot->description = "Select vertices without a group";
|
|
|
|
/* api callbacks */
|
|
ot->exec = lattice_select_ungrouped_exec;
|
|
ot->poll = ED_operator_editlattice;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Select Picking API
|
|
*
|
|
* Here actual select happens,
|
|
* Gets called via generic mouse select operator.
|
|
* \{ */
|
|
|
|
struct NearestLatticeVert_UserData {
|
|
BPoint *bp;
|
|
float dist;
|
|
/** When true, the existing selection gets a disadvantage. */
|
|
bool select;
|
|
float mval_fl[2];
|
|
bool is_changed;
|
|
};
|
|
|
|
static void findnearestLattvert__doClosest(void *user_data, BPoint *bp, const float screen_co[2])
|
|
{
|
|
struct NearestLatticeVert_UserData *data = user_data;
|
|
float dist_test = len_manhattan_v2v2(data->mval_fl, screen_co);
|
|
|
|
if ((bp->f1 & SELECT) && data->select) {
|
|
dist_test += 5.0f;
|
|
}
|
|
|
|
if (dist_test < data->dist) {
|
|
data->dist = dist_test;
|
|
data->bp = bp;
|
|
data->is_changed = true;
|
|
}
|
|
}
|
|
|
|
static BPoint *findnearestLattvert(ViewContext *vc, bool select, Base **r_base)
|
|
{
|
|
struct NearestLatticeVert_UserData data = {NULL};
|
|
|
|
data.dist = ED_view3d_select_dist_px();
|
|
data.select = select;
|
|
data.mval_fl[0] = vc->mval[0];
|
|
data.mval_fl[1] = vc->mval[1];
|
|
|
|
uint bases_len;
|
|
Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(
|
|
vc->scene, vc->view_layer, vc->v3d, &bases_len);
|
|
for (uint base_index = 0; base_index < bases_len; base_index++) {
|
|
Base *base = bases[base_index];
|
|
data.is_changed = false;
|
|
|
|
ED_view3d_viewcontext_init_object(vc, base->object);
|
|
ED_view3d_init_mats_rv3d(base->object, vc->rv3d);
|
|
lattice_foreachScreenVert(
|
|
vc, findnearestLattvert__doClosest, &data, V3D_PROJ_TEST_CLIP_DEFAULT);
|
|
|
|
if (data.is_changed) {
|
|
*r_base = base;
|
|
}
|
|
}
|
|
MEM_freeN(bases);
|
|
return data.bp;
|
|
}
|
|
|
|
bool ED_lattice_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params)
|
|
{
|
|
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
|
|
ViewContext vc;
|
|
BPoint *bp = NULL;
|
|
Base *basact = NULL;
|
|
bool changed = false;
|
|
|
|
ED_view3d_viewcontext_init(C, &vc, depsgraph);
|
|
vc.mval[0] = mval[0];
|
|
vc.mval[1] = mval[1];
|
|
|
|
bp = findnearestLattvert(&vc, true, &basact);
|
|
bool found = (bp != NULL);
|
|
|
|
if (params->sel_op == SEL_OP_SET) {
|
|
if ((found && params->select_passthrough) && (bp->f1 & SELECT)) {
|
|
found = false;
|
|
}
|
|
else if (found || params->deselect_all) {
|
|
/* Deselect everything. */
|
|
uint objects_len = 0;
|
|
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
|
|
vc.scene, vc.view_layer, vc.v3d, &objects_len);
|
|
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
|
|
Object *ob = objects[ob_index];
|
|
if (ED_lattice_flags_set(ob, 0)) {
|
|
DEG_id_tag_update(ob->data, ID_RECALC_SELECT);
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
|
|
}
|
|
}
|
|
MEM_freeN(objects);
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
ED_view3d_viewcontext_init_object(&vc, basact->object);
|
|
Lattice *lt = ((Lattice *)vc.obedit->data)->editlatt->latt;
|
|
|
|
switch (params->sel_op) {
|
|
case SEL_OP_ADD: {
|
|
bp->f1 |= SELECT;
|
|
break;
|
|
}
|
|
case SEL_OP_SUB: {
|
|
bp->f1 &= ~SELECT;
|
|
break;
|
|
}
|
|
case SEL_OP_XOR: {
|
|
bp->f1 ^= SELECT; /* swap */
|
|
break;
|
|
}
|
|
case SEL_OP_SET: {
|
|
bp->f1 |= SELECT;
|
|
break;
|
|
}
|
|
case SEL_OP_AND: {
|
|
BLI_assert_unreachable(); /* Doesn't make sense for picking. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (bp->f1 & SELECT) {
|
|
lt->actbp = bp - lt->def;
|
|
}
|
|
else {
|
|
lt->actbp = LT_ACTBP_NONE;
|
|
}
|
|
|
|
BKE_view_layer_synced_ensure(vc.scene, vc.view_layer);
|
|
if (BKE_view_layer_active_base_get(vc.view_layer) != basact) {
|
|
ED_object_base_activate(C, basact);
|
|
}
|
|
|
|
DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT);
|
|
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
|
|
|
|
changed = true;
|
|
}
|
|
|
|
return changed || found;
|
|
}
|
|
|
|
/** \} */
|