BMesh Path Select: Add checker-select options
Allows to quickly select alternate elems in a path (matching checker-deselect options). - adds redo support to MESH_OT_shortest_path_pick, allowing for other options. - de-duplicates code between 2x path select operators. - expose 'Topology Distance' property for path picking. - remove unused 'extend' property.
This commit is contained in:
@@ -53,6 +53,7 @@
|
|||||||
#include "RNA_access.h"
|
#include "RNA_access.h"
|
||||||
#include "RNA_define.h"
|
#include "RNA_define.h"
|
||||||
|
|
||||||
|
#include "WM_api.h"
|
||||||
#include "WM_types.h"
|
#include "WM_types.h"
|
||||||
|
|
||||||
#include "bmesh.h"
|
#include "bmesh.h"
|
||||||
@@ -60,10 +61,33 @@
|
|||||||
|
|
||||||
#include "mesh_intern.h" /* own include */
|
#include "mesh_intern.h" /* own include */
|
||||||
|
|
||||||
|
struct PathSelectParams {
|
||||||
|
bool track_active; /* ensure the active element is the last selected item (handy for picking) */
|
||||||
|
bool topology_distance;
|
||||||
|
char edge_mode;
|
||||||
|
struct CheckerIntervalParams interval_params;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void path_select_properties(wmOperatorType *ot)
|
||||||
|
{
|
||||||
|
RNA_def_boolean(
|
||||||
|
ot->srna, "topology_distance", false, "Topology Distance",
|
||||||
|
"Find the minimum number of steps, ignoring spatial distance");
|
||||||
|
WM_operator_properties_checker_interval(ot, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void path_select_params_from_op(wmOperator *op, struct PathSelectParams *op_params)
|
||||||
|
{
|
||||||
|
op_params->edge_mode = EDGE_MODE_SELECT;
|
||||||
|
op_params->track_active = false;
|
||||||
|
op_params->topology_distance = RNA_boolean_get(op->ptr, "topology_distance");
|
||||||
|
WM_operator_properties_checker_interval_from_op(op, &op_params->interval_params);
|
||||||
|
}
|
||||||
|
|
||||||
struct UserData {
|
struct UserData {
|
||||||
BMesh *bm;
|
BMesh *bm;
|
||||||
Mesh *me;
|
Mesh *me;
|
||||||
Scene *scene;
|
const struct PathSelectParams *op_params;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
@@ -84,70 +108,72 @@ static void verttag_set_cb(BMVert *v, bool val, void *user_data_v)
|
|||||||
BM_vert_select_set(user_data->bm, v, val);
|
BM_vert_select_set(user_data->bm, v, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mouse_mesh_shortest_path_vert(ViewContext *vc)
|
static void mouse_mesh_shortest_path_vert(
|
||||||
|
Scene *scene, const struct PathSelectParams *op_params,
|
||||||
|
BMVert *v_act, BMVert *v_dst)
|
||||||
{
|
{
|
||||||
/* unlike edge/face versions, this uses a bmesh operator */
|
Object *obedit = scene->obedit;
|
||||||
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
BMEditMesh *em = vc->em;
|
|
||||||
BMesh *bm = em->bm;
|
BMesh *bm = em->bm;
|
||||||
BMVert *v_dst;
|
|
||||||
float dist = ED_view3d_select_dist_px();
|
|
||||||
const bool use_length = true;
|
|
||||||
|
|
||||||
v_dst = EDBM_vert_find_nearest(vc, &dist);
|
struct UserData user_data = {bm, obedit->data, op_params};
|
||||||
if (v_dst) {
|
LinkNode *path = NULL;
|
||||||
struct UserData user_data = {bm, vc->obedit->data, vc->scene};
|
|
||||||
LinkNode *path = NULL;
|
|
||||||
BMVert *v_act = BM_mesh_active_vert_get(bm);
|
|
||||||
|
|
||||||
if (v_act && (v_act != v_dst)) {
|
if (v_act && (v_act != v_dst)) {
|
||||||
if ((path = BM_mesh_calc_path_vert(bm, v_act, v_dst, use_length,
|
if ((path = BM_mesh_calc_path_vert(
|
||||||
verttag_filter_cb, &user_data)))
|
bm, v_act, v_dst, !op_params->topology_distance,
|
||||||
{
|
verttag_filter_cb, &user_data)))
|
||||||
|
{
|
||||||
|
if (op_params->track_active) {
|
||||||
BM_select_history_remove(bm, v_act);
|
BM_select_history_remove(bm, v_act);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (path) {
|
BMVert *v_dst_last = v_dst;
|
||||||
/* toggle the flag */
|
|
||||||
bool all_set = true;
|
|
||||||
LinkNode *node;
|
|
||||||
|
|
||||||
node = path;
|
if (path) {
|
||||||
do {
|
/* toggle the flag */
|
||||||
if (!verttag_test_cb((BMVert *)node->link, &user_data)) {
|
bool all_set = true;
|
||||||
all_set = false;
|
LinkNode *node;
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while ((node = node->next));
|
|
||||||
|
|
||||||
node = path;
|
node = path;
|
||||||
do {
|
do {
|
||||||
|
if (!verttag_test_cb((BMVert *)node->link, &user_data)) {
|
||||||
|
all_set = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while ((node = node->next));
|
||||||
|
|
||||||
|
int depth = 1;
|
||||||
|
node = path;
|
||||||
|
do {
|
||||||
|
if (WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) {
|
||||||
verttag_set_cb((BMVert *)node->link, !all_set, &user_data);
|
verttag_set_cb((BMVert *)node->link, !all_set, &user_data);
|
||||||
} while ((node = node->next));
|
v_dst_last = node->link;
|
||||||
|
}
|
||||||
|
} while (depth++, (node = node->next));
|
||||||
|
|
||||||
BLI_linklist_free(path, NULL);
|
BLI_linklist_free(path, NULL);
|
||||||
}
|
|
||||||
else {
|
|
||||||
const bool is_act = !verttag_test_cb(v_dst, &user_data);
|
|
||||||
verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */
|
|
||||||
}
|
|
||||||
|
|
||||||
EDBM_selectmode_flush(em);
|
|
||||||
|
|
||||||
/* even if this is selected it may not be in the selection list */
|
|
||||||
if (BM_elem_flag_test(v_dst, BM_ELEM_SELECT) == 0)
|
|
||||||
BM_select_history_remove(bm, v_dst);
|
|
||||||
else
|
|
||||||
BM_select_history_store(bm, v_dst);
|
|
||||||
|
|
||||||
EDBM_update_generic(em, false, false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
const bool is_act = !verttag_test_cb(v_dst, &user_data);
|
||||||
|
verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EDBM_selectmode_flush(em);
|
||||||
|
|
||||||
|
if (op_params->track_active) {
|
||||||
|
/* even if this is selected it may not be in the selection list */
|
||||||
|
if (BM_elem_flag_test(v_dst_last, BM_ELEM_SELECT) == 0) {
|
||||||
|
BM_select_history_remove(bm, v_dst_last);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BM_select_history_store(bm, v_dst_last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EDBM_update_generic(em, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -163,10 +189,10 @@ static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
|
|||||||
static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
|
static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
|
||||||
{
|
{
|
||||||
struct UserData *user_data = user_data_v;
|
struct UserData *user_data = user_data_v;
|
||||||
Scene *scene = user_data->scene;
|
const char edge_mode = user_data->op_params->edge_mode;
|
||||||
BMesh *bm = user_data->bm;
|
BMesh *bm = user_data->bm;
|
||||||
|
|
||||||
switch (scene->toolsettings->edge_mode) {
|
switch (edge_mode) {
|
||||||
case EDGE_MODE_SELECT:
|
case EDGE_MODE_SELECT:
|
||||||
return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false;
|
return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false;
|
||||||
case EDGE_MODE_TAG_SEAM:
|
case EDGE_MODE_TAG_SEAM:
|
||||||
@@ -190,10 +216,10 @@ static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
|
|||||||
static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
|
static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
|
||||||
{
|
{
|
||||||
struct UserData *user_data = user_data_v;
|
struct UserData *user_data = user_data_v;
|
||||||
Scene *scene = user_data->scene;
|
const char edge_mode = user_data->op_params->edge_mode;
|
||||||
BMesh *bm = user_data->bm;
|
BMesh *bm = user_data->bm;
|
||||||
|
|
||||||
switch (scene->toolsettings->edge_mode) {
|
switch (edge_mode) {
|
||||||
case EDGE_MODE_SELECT:
|
case EDGE_MODE_SELECT:
|
||||||
BM_edge_select_set(bm, e, val);
|
BM_edge_select_set(bm, e, val);
|
||||||
break;
|
break;
|
||||||
@@ -250,106 +276,109 @@ static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me)
|
|||||||
/* mesh shortest path select, uses prev-selected edge */
|
/* mesh shortest path select, uses prev-selected edge */
|
||||||
|
|
||||||
/* since you want to create paths with multiple selects, it doesn't have extend option */
|
/* since you want to create paths with multiple selects, it doesn't have extend option */
|
||||||
static bool mouse_mesh_shortest_path_edge(ViewContext *vc)
|
static void mouse_mesh_shortest_path_edge(
|
||||||
|
Scene *scene, const struct PathSelectParams *op_params,
|
||||||
|
BMEdge *e_act, BMEdge *e_dst)
|
||||||
{
|
{
|
||||||
BMEditMesh *em = vc->em;
|
Object *obedit = scene->obedit;
|
||||||
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
BMesh *bm = em->bm;
|
BMesh *bm = em->bm;
|
||||||
BMEdge *e_dst;
|
|
||||||
float dist = ED_view3d_select_dist_px();
|
|
||||||
const bool use_length = true;
|
|
||||||
|
|
||||||
e_dst = EDBM_edge_find_nearest(vc, &dist);
|
struct UserData user_data = {bm, obedit->data, op_params};
|
||||||
if (e_dst) {
|
LinkNode *path = NULL;
|
||||||
const char edge_mode = vc->scene->toolsettings->edge_mode;
|
Mesh *me = obedit->data;
|
||||||
struct UserData user_data = {bm, vc->obedit->data, vc->scene};
|
|
||||||
LinkNode *path = NULL;
|
|
||||||
Mesh *me = vc->obedit->data;
|
|
||||||
BMEdge *e_act = BM_mesh_active_edge_get(bm);
|
|
||||||
|
|
||||||
edgetag_ensure_cd_flag(vc->scene, em->ob->data);
|
edgetag_ensure_cd_flag(scene, obedit->data);
|
||||||
|
|
||||||
if (e_act && (e_act != e_dst)) {
|
if (e_act && (e_act != e_dst)) {
|
||||||
if ((path = BM_mesh_calc_path_edge(bm, e_act, e_dst, use_length,
|
if ((path = BM_mesh_calc_path_edge(
|
||||||
edgetag_filter_cb, &user_data)))
|
bm, e_act, e_dst, !op_params->topology_distance,
|
||||||
{
|
edgetag_filter_cb, &user_data)))
|
||||||
|
{
|
||||||
|
if (op_params->track_active) {
|
||||||
BM_select_history_remove(bm, e_act);
|
BM_select_history_remove(bm, e_act);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (path) {
|
BMEdge *e_dst_last = e_dst;
|
||||||
/* toggle the flag */
|
|
||||||
bool all_set = true;
|
|
||||||
LinkNode *node;
|
|
||||||
|
|
||||||
node = path;
|
if (path) {
|
||||||
do {
|
/* toggle the flag */
|
||||||
if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) {
|
bool all_set = true;
|
||||||
all_set = false;
|
LinkNode *node;
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while ((node = node->next));
|
|
||||||
|
|
||||||
node = path;
|
node = path;
|
||||||
do {
|
do {
|
||||||
|
if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) {
|
||||||
|
all_set = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while ((node = node->next));
|
||||||
|
|
||||||
|
int depth = 1;
|
||||||
|
node = path;
|
||||||
|
do {
|
||||||
|
if (WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) {
|
||||||
edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data);
|
edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data);
|
||||||
} while ((node = node->next));
|
e_dst_last = node->link;
|
||||||
|
}
|
||||||
|
} while (depth++, (node = node->next));
|
||||||
|
|
||||||
BLI_linklist_free(path, NULL);
|
BLI_linklist_free(path, NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const bool is_act = !edgetag_test_cb(e_dst, &user_data);
|
const bool is_act = !edgetag_test_cb(e_dst, &user_data);
|
||||||
edgetag_ensure_cd_flag(vc->scene, vc->obedit->data);
|
edgetag_ensure_cd_flag(scene, obedit->data);
|
||||||
edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
|
edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (edge_mode != EDGE_MODE_SELECT) {
|
if (op_params->edge_mode != EDGE_MODE_SELECT) {
|
||||||
|
if (op_params->track_active) {
|
||||||
/* simple rules - last edge is _always_ active and selected */
|
/* simple rules - last edge is _always_ active and selected */
|
||||||
if (e_act)
|
if (e_act)
|
||||||
BM_edge_select_set(bm, e_act, false);
|
BM_edge_select_set(bm, e_act, false);
|
||||||
BM_edge_select_set(bm, e_dst, true);
|
BM_edge_select_set(bm, e_dst_last, true);
|
||||||
BM_select_history_store(bm, e_dst);
|
BM_select_history_store(bm, e_dst_last);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EDBM_selectmode_flush(em);
|
EDBM_selectmode_flush(em);
|
||||||
|
|
||||||
|
if (op_params->track_active) {
|
||||||
/* even if this is selected it may not be in the selection list */
|
/* even if this is selected it may not be in the selection list */
|
||||||
if (edge_mode == EDGE_MODE_SELECT) {
|
if (op_params->edge_mode == EDGE_MODE_SELECT) {
|
||||||
if (edgetag_test_cb(e_dst, &user_data) == 0)
|
if (edgetag_test_cb(e_dst_last, &user_data) == 0)
|
||||||
BM_select_history_remove(bm, e_dst);
|
BM_select_history_remove(bm, e_dst_last);
|
||||||
else
|
else
|
||||||
BM_select_history_store(bm, e_dst);
|
BM_select_history_store(bm, e_dst_last);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* force drawmode for mesh */
|
/* force drawmode for mesh */
|
||||||
switch (edge_mode) {
|
switch (op_params->edge_mode) {
|
||||||
|
|
||||||
case EDGE_MODE_TAG_SEAM:
|
case EDGE_MODE_TAG_SEAM:
|
||||||
me->drawflag |= ME_DRAWSEAMS;
|
me->drawflag |= ME_DRAWSEAMS;
|
||||||
ED_uvedit_live_unwrap(vc->scene, vc->obedit);
|
ED_uvedit_live_unwrap(scene, obedit);
|
||||||
break;
|
break;
|
||||||
case EDGE_MODE_TAG_SHARP:
|
case EDGE_MODE_TAG_SHARP:
|
||||||
me->drawflag |= ME_DRAWSHARP;
|
me->drawflag |= ME_DRAWSHARP;
|
||||||
break;
|
break;
|
||||||
case EDGE_MODE_TAG_CREASE:
|
case EDGE_MODE_TAG_CREASE:
|
||||||
me->drawflag |= ME_DRAWCREASES;
|
me->drawflag |= ME_DRAWCREASES;
|
||||||
break;
|
break;
|
||||||
case EDGE_MODE_TAG_BEVEL:
|
case EDGE_MODE_TAG_BEVEL:
|
||||||
me->drawflag |= ME_DRAWBWEIGHTS;
|
me->drawflag |= ME_DRAWBWEIGHTS;
|
||||||
break;
|
break;
|
||||||
#ifdef WITH_FREESTYLE
|
#ifdef WITH_FREESTYLE
|
||||||
case EDGE_MODE_TAG_FREESTYLE:
|
case EDGE_MODE_TAG_FREESTYLE:
|
||||||
me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
|
me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
EDBM_update_generic(em, false, false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EDBM_update_generic(em, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -374,72 +403,75 @@ static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
|
|||||||
BM_face_select_set(user_data->bm, f, val);
|
BM_face_select_set(user_data->bm, f, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mouse_mesh_shortest_path_face(ViewContext *vc)
|
static void mouse_mesh_shortest_path_face(
|
||||||
|
Scene *scene, const struct PathSelectParams *op_params,
|
||||||
|
BMFace *f_act, BMFace *f_dst)
|
||||||
{
|
{
|
||||||
BMEditMesh *em = vc->em;
|
Object *obedit = scene->obedit;
|
||||||
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
BMesh *bm = em->bm;
|
BMesh *bm = em->bm;
|
||||||
BMFace *f_dst;
|
|
||||||
float dist = ED_view3d_select_dist_px();
|
|
||||||
const bool use_length = true;
|
|
||||||
|
|
||||||
f_dst = EDBM_face_find_nearest(vc, &dist);
|
struct UserData user_data = {bm, obedit->data, op_params};
|
||||||
if (f_dst) {
|
LinkNode *path = NULL;
|
||||||
struct UserData user_data = {bm, vc->obedit->data, vc->scene};
|
|
||||||
LinkNode *path = NULL;
|
|
||||||
BMFace *f_act = BM_mesh_active_face_get(bm, false, true);
|
|
||||||
|
|
||||||
if (f_act) {
|
if (f_act) {
|
||||||
if (f_act != f_dst) {
|
if (f_act != f_dst) {
|
||||||
if ((path = BM_mesh_calc_path_face(bm, f_act, f_dst, use_length,
|
if ((path = BM_mesh_calc_path_face(
|
||||||
facetag_filter_cb, &user_data)))
|
bm, f_act, f_dst, !op_params->topology_distance,
|
||||||
{
|
facetag_filter_cb, &user_data)))
|
||||||
|
{
|
||||||
|
if (op_params->track_active) {
|
||||||
BM_select_history_remove(bm, f_act);
|
BM_select_history_remove(bm, f_act);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (path) {
|
BMFace *f_dst_last = f_dst;
|
||||||
/* toggle the flag */
|
|
||||||
bool all_set = true;
|
|
||||||
LinkNode *node;
|
|
||||||
|
|
||||||
node = path;
|
if (path) {
|
||||||
do {
|
/* toggle the flag */
|
||||||
if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
|
bool all_set = true;
|
||||||
all_set = false;
|
LinkNode *node;
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while ((node = node->next));
|
|
||||||
|
|
||||||
node = path;
|
node = path;
|
||||||
do {
|
do {
|
||||||
|
if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
|
||||||
|
all_set = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while ((node = node->next));
|
||||||
|
|
||||||
|
int depth = 1;
|
||||||
|
node = path;
|
||||||
|
do {
|
||||||
|
if (WM_operator_properties_checker_interval_test(&op_params->interval_params, depth)) {
|
||||||
facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
|
facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
|
||||||
} while ((node = node->next));
|
f_dst_last = node->link;
|
||||||
|
}
|
||||||
|
} while (depth++, (node = node->next));
|
||||||
|
|
||||||
BLI_linklist_free(path, NULL);
|
BLI_linklist_free(path, NULL);
|
||||||
}
|
|
||||||
else {
|
|
||||||
const bool is_act = !facetag_test_cb(f_dst, &user_data);
|
|
||||||
facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
|
|
||||||
}
|
|
||||||
|
|
||||||
EDBM_selectmode_flush(em);
|
|
||||||
|
|
||||||
/* even if this is selected it may not be in the selection list */
|
|
||||||
if (facetag_test_cb(f_dst, &user_data) == 0)
|
|
||||||
BM_select_history_remove(bm, f_dst);
|
|
||||||
else
|
|
||||||
BM_select_history_store(bm, f_dst);
|
|
||||||
|
|
||||||
BM_mesh_active_face_set(bm, f_dst);
|
|
||||||
|
|
||||||
EDBM_update_generic(em, false, false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
const bool is_act = !facetag_test_cb(f_dst, &user_data);
|
||||||
|
facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EDBM_selectmode_flush(em);
|
||||||
|
|
||||||
|
if (op_params->track_active) {
|
||||||
|
/* even if this is selected it may not be in the selection list */
|
||||||
|
if (facetag_test_cb(f_dst_last, &user_data) == 0) {
|
||||||
|
BM_select_history_remove(bm, f_dst_last);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BM_select_history_store(bm, f_dst_last);
|
||||||
|
}
|
||||||
|
BM_mesh_active_face_set(bm, f_dst_last);
|
||||||
|
}
|
||||||
|
|
||||||
|
EDBM_update_generic(em, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -447,54 +479,124 @@ static bool mouse_mesh_shortest_path_face(ViewContext *vc)
|
|||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Main Operator for vert/edge/face tag */
|
/* Main Operator for vert/edge/face tag */
|
||||||
|
|
||||||
static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
static bool edbm_shortest_path_pick_ex(
|
||||||
|
Scene *scene, const struct PathSelectParams *op_params,
|
||||||
|
BMElem *ele_src, BMElem *ele_dst)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (ELEM(NULL, ele_src, ele_dst) && (ele_src->head.htype != ele_dst->head.htype)) {
|
||||||
|
/* pass */
|
||||||
|
}
|
||||||
|
else if (ele_src->head.htype == BM_VERT) {
|
||||||
|
mouse_mesh_shortest_path_vert(scene, op_params, (BMVert *)ele_src, (BMVert *)ele_dst);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ele_src->head.htype == BM_EDGE) {
|
||||||
|
mouse_mesh_shortest_path_edge(scene, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (ele_src->head.htype == BM_FACE) {
|
||||||
|
mouse_mesh_shortest_path_face(scene, op_params, (BMFace *)ele_src, (BMFace *)ele_dst);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op);
|
||||||
|
|
||||||
|
static BMElem *edbm_elem_find_nearest(ViewContext *vc, const char htype)
|
||||||
|
{
|
||||||
|
BMEditMesh *em = vc->em;
|
||||||
|
float dist = ED_view3d_select_dist_px();
|
||||||
|
|
||||||
|
if ((em->selectmode & SCE_SELECT_VERTEX) && (htype == BM_VERT)) {
|
||||||
|
return (BMElem *)EDBM_vert_find_nearest(vc, &dist);
|
||||||
|
}
|
||||||
|
else if ((em->selectmode & SCE_SELECT_EDGE) && (htype == BM_EDGE)) {
|
||||||
|
return (BMElem *)EDBM_edge_find_nearest(vc, &dist);
|
||||||
|
}
|
||||||
|
else if ((em->selectmode & SCE_SELECT_FACE) && (htype == BM_FACE)) {
|
||||||
|
return (BMElem *)EDBM_face_find_nearest(vc, &dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||||
|
{
|
||||||
|
if (RNA_struct_property_is_set(op->ptr, "index")) {
|
||||||
|
return edbm_shortest_path_pick_exec(C, op);
|
||||||
|
}
|
||||||
|
|
||||||
ViewContext vc;
|
ViewContext vc;
|
||||||
BMEditMesh *em;
|
BMEditMesh *em;
|
||||||
BMElem *ele;
|
|
||||||
|
|
||||||
|
|
||||||
em_setup_viewcontext(C, &vc);
|
em_setup_viewcontext(C, &vc);
|
||||||
copy_v2_v2_int(vc.mval, event->mval);
|
copy_v2_v2_int(vc.mval, event->mval);
|
||||||
em = vc.em;
|
em = vc.em;
|
||||||
|
|
||||||
ele = BM_mesh_active_elem_get(em->bm);
|
view3d_operator_needs_opengl(C);
|
||||||
if (ele == NULL) {
|
|
||||||
|
BMElem *ele_src, *ele_dst;
|
||||||
|
if (!(ele_src = BM_mesh_active_elem_get(em->bm)) ||
|
||||||
|
!(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype)))
|
||||||
|
{
|
||||||
return OPERATOR_PASS_THROUGH;
|
return OPERATOR_PASS_THROUGH;
|
||||||
}
|
}
|
||||||
|
|
||||||
view3d_operator_needs_opengl(C);
|
struct PathSelectParams op_params;
|
||||||
|
path_select_params_from_op(op, &op_params);
|
||||||
|
op_params.track_active = true;
|
||||||
|
op_params.edge_mode = vc.scene->toolsettings->edge_mode;
|
||||||
|
|
||||||
if ((em->selectmode & SCE_SELECT_VERTEX) && (ele->head.htype == BM_VERT)) {
|
if (!edbm_shortest_path_pick_ex(vc.scene, &op_params, ele_src, ele_dst)) {
|
||||||
if (mouse_mesh_shortest_path_vert(&vc)) {
|
return OPERATOR_PASS_THROUGH;
|
||||||
return OPERATOR_FINISHED;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return OPERATOR_PASS_THROUGH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((em->selectmode & SCE_SELECT_EDGE) && (ele->head.htype == BM_EDGE)) {
|
|
||||||
if (mouse_mesh_shortest_path_edge(&vc)) {
|
|
||||||
return OPERATOR_FINISHED;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return OPERATOR_PASS_THROUGH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((em->selectmode & SCE_SELECT_FACE) && (ele->head.htype == BM_FACE)) {
|
|
||||||
if (mouse_mesh_shortest_path_face(&vc)) {
|
|
||||||
return OPERATOR_FINISHED;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return OPERATOR_PASS_THROUGH;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return OPERATOR_PASS_THROUGH;
|
/* to support redo */
|
||||||
|
int index = EDBM_elem_to_index_any(em, ele_dst);
|
||||||
|
|
||||||
|
RNA_int_set(op->ptr, "index", index);
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op)
|
||||||
|
{
|
||||||
|
Scene *scene = CTX_data_scene(C);
|
||||||
|
Object *obedit = CTX_data_edit_object(C);
|
||||||
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
||||||
|
BMesh *bm = em->bm;
|
||||||
|
|
||||||
|
const int index = RNA_int_get(op->ptr, "index");
|
||||||
|
if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
BMElem *ele_src, *ele_dst;
|
||||||
|
if (!(ele_src = BM_mesh_active_elem_get(em->bm)) ||
|
||||||
|
!(ele_dst = EDBM_elem_from_index_any(em, index)))
|
||||||
|
{
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PathSelectParams op_params;
|
||||||
|
path_select_params_from_op(op, &op_params);
|
||||||
|
op_params.track_active = true;
|
||||||
|
op_params.edge_mode = scene->toolsettings->edge_mode;
|
||||||
|
|
||||||
|
if (!edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst)) {
|
||||||
|
return OPERATOR_CANCELLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OPERATOR_FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MESH_OT_shortest_path_pick(wmOperatorType *ot)
|
void MESH_OT_shortest_path_pick(wmOperatorType *ot)
|
||||||
{
|
{
|
||||||
|
PropertyRNA *prop;
|
||||||
|
|
||||||
/* identifiers */
|
/* identifiers */
|
||||||
ot->name = "Pick Shortest Path";
|
ot->name = "Pick Shortest Path";
|
||||||
ot->idname = "MESH_OT_shortest_path_pick";
|
ot->idname = "MESH_OT_shortest_path_pick";
|
||||||
@@ -502,15 +604,19 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot)
|
|||||||
|
|
||||||
/* api callbacks */
|
/* api callbacks */
|
||||||
ot->invoke = edbm_shortest_path_pick_invoke;
|
ot->invoke = edbm_shortest_path_pick_invoke;
|
||||||
|
ot->exec = edbm_shortest_path_pick_exec;
|
||||||
ot->poll = ED_operator_editmesh_region_view3d;
|
ot->poll = ED_operator_editmesh_region_view3d;
|
||||||
|
|
||||||
/* flags */
|
/* flags */
|
||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
|
path_select_properties(ot);
|
||||||
}
|
|
||||||
|
|
||||||
|
/* use for redo */
|
||||||
|
prop = RNA_def_int(ot->srna, "index", -1, -1, INT_MAX, "", "", 0, INT_MAX);
|
||||||
|
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
@@ -518,6 +624,7 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot)
|
|||||||
|
|
||||||
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
|
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
|
||||||
{
|
{
|
||||||
|
Scene *scene = CTX_data_scene(C);
|
||||||
Object *ob = CTX_data_edit_object(C);
|
Object *ob = CTX_data_edit_object(C);
|
||||||
BMEditMesh *em = BKE_editmesh_from_object(ob);
|
BMEditMesh *em = BKE_editmesh_from_object(ob);
|
||||||
BMesh *bm = em->bm;
|
BMesh *bm = em->bm;
|
||||||
@@ -525,8 +632,6 @@ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
|
|||||||
BMEditSelection *ese_src, *ese_dst;
|
BMEditSelection *ese_src, *ese_dst;
|
||||||
BMElem *ele_src = NULL, *ele_dst = NULL, *ele;
|
BMElem *ele_src = NULL, *ele_dst = NULL, *ele;
|
||||||
|
|
||||||
const bool use_length = RNA_boolean_get(op->ptr, "use_length");
|
|
||||||
|
|
||||||
/* first try to find vertices in edit selection */
|
/* first try to find vertices in edit selection */
|
||||||
ese_src = bm->selected.last;
|
ese_src = bm->selected.last;
|
||||||
if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) {
|
if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) {
|
||||||
@@ -570,41 +675,10 @@ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ele_src && ele_dst) {
|
if (ele_src && ele_dst) {
|
||||||
LinkNode *path = NULL;
|
struct PathSelectParams op_params;
|
||||||
switch (ele_src->head.htype) {
|
path_select_params_from_op(op, &op_params);
|
||||||
case BM_VERT:
|
|
||||||
path = BM_mesh_calc_path_vert(
|
|
||||||
bm, (BMVert *)ele_src, (BMVert *)ele_dst, use_length,
|
|
||||||
BM_elem_cb_check_hflag_disabled_simple(BMVert *, BM_ELEM_HIDDEN));
|
|
||||||
break;
|
|
||||||
case BM_EDGE:
|
|
||||||
path = BM_mesh_calc_path_edge(
|
|
||||||
bm, (BMEdge *)ele_src, (BMEdge *)ele_dst, use_length,
|
|
||||||
BM_elem_cb_check_hflag_disabled_simple(BMEdge *, BM_ELEM_HIDDEN));
|
|
||||||
break;
|
|
||||||
case BM_FACE:
|
|
||||||
path = BM_mesh_calc_path_face(
|
|
||||||
bm, (BMFace *)ele_src, (BMFace *)ele_dst, use_length,
|
|
||||||
BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path) {
|
edbm_shortest_path_pick_ex(scene, &op_params, ele_src, ele_dst);
|
||||||
LinkNode *node = path;
|
|
||||||
|
|
||||||
do {
|
|
||||||
BM_elem_select_set(bm, node->link, true);
|
|
||||||
} while ((node = node->next));
|
|
||||||
|
|
||||||
BLI_linklist_free(path, NULL);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BKE_report(op->reports, RPT_WARNING, "Path can't be found");
|
|
||||||
return OPERATOR_CANCELLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
EDBM_selectmode_flush(em);
|
|
||||||
EDBM_update_generic(em, false, false);
|
|
||||||
|
|
||||||
return OPERATOR_FINISHED;
|
return OPERATOR_FINISHED;
|
||||||
}
|
}
|
||||||
@@ -629,5 +703,5 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot)
|
|||||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
RNA_def_boolean(ot->srna, "use_length", true, "Length", "Use length when measuring distance");
|
path_select_properties(ot);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user