2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2004 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup edmesh
|
2013-06-04 01:23:51 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "DNA_mesh_types.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
2013-06-04 01:23:51 +00:00
|
|
|
#include "DNA_windowmanager_types.h"
|
|
|
|
|
|
2014-11-28 15:50:43 +01:00
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
|
# include "DNA_meshdata_types.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-06-04 01:23:51 +00:00
|
|
|
#include "BLI_linklist.h"
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_vector.h"
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2023-11-16 11:41:55 +01:00
|
|
|
#include "BKE_context.hh"
|
|
|
|
|
#include "BKE_customdata.hh"
|
|
|
|
|
#include "BKE_editmesh.hh"
|
2024-01-23 15:18:09 -05:00
|
|
|
#include "BKE_layer.hh"
|
2024-03-21 23:18:49 +01:00
|
|
|
#include "BKE_mesh_types.hh"
|
2024-02-10 18:34:29 +01:00
|
|
|
#include "BKE_report.hh"
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_mesh.hh"
|
|
|
|
|
#include "ED_object.hh"
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "ED_screen.hh"
|
2023-08-05 02:57:52 +02:00
|
|
|
#include "ED_select_utils.hh"
|
|
|
|
|
#include "ED_uvedit.hh"
|
|
|
|
|
#include "ED_view3d.hh"
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2023-08-10 22:40:27 +02:00
|
|
|
#include "RNA_access.hh"
|
|
|
|
|
#include "RNA_define.hh"
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2023-08-04 23:11:22 +02:00
|
|
|
#include "WM_api.hh"
|
|
|
|
|
#include "WM_types.hh"
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2023-12-05 23:01:12 +01:00
|
|
|
#include "bmesh.hh"
|
|
|
|
|
#include "bmesh_tools.hh"
|
2013-08-23 04:22:07 +00:00
|
|
|
|
2023-09-22 03:18:17 +02:00
|
|
|
#include "DEG_depsgraph.hh"
|
2017-08-16 12:45:11 +10:00
|
|
|
|
2024-01-24 11:30:39 -05:00
|
|
|
#include "mesh_intern.hh" /* own include */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2024-01-24 18:18:14 +01:00
|
|
|
using blender::Vector;
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Path Select Struct & Properties
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2019-05-21 11:13:45 +10:00
|
|
|
enum {
|
|
|
|
|
EDGE_MODE_SELECT = 0,
|
|
|
|
|
EDGE_MODE_TAG_SEAM = 1,
|
|
|
|
|
EDGE_MODE_TAG_SHARP = 2,
|
|
|
|
|
EDGE_MODE_TAG_CREASE = 3,
|
|
|
|
|
EDGE_MODE_TAG_BEVEL = 4,
|
|
|
|
|
EDGE_MODE_TAG_FREESTYLE = 5,
|
|
|
|
|
};
|
|
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
struct PathSelectParams {
|
2019-01-15 23:24:20 +11:00
|
|
|
/** ensure the active element is the last selected item (handy for picking) */
|
|
|
|
|
bool track_active;
|
2015-12-27 22:38:12 +11:00
|
|
|
bool use_topology_distance;
|
|
|
|
|
bool use_face_step;
|
2016-03-31 04:21:02 +11:00
|
|
|
bool use_fill;
|
2015-12-27 18:05:53 +11:00
|
|
|
char edge_mode;
|
2023-07-20 11:30:25 +10:00
|
|
|
CheckerIntervalParams interval_params;
|
2015-12-27 18:05:53 +11:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void path_select_properties(wmOperatorType *ot)
|
|
|
|
|
{
|
2019-05-21 11:13:45 +10:00
|
|
|
static const EnumPropertyItem edge_tag_items[] = {
|
|
|
|
|
{EDGE_MODE_SELECT, "SELECT", 0, "Select", ""},
|
|
|
|
|
{EDGE_MODE_TAG_SEAM, "SEAM", 0, "Tag Seam", ""},
|
|
|
|
|
{EDGE_MODE_TAG_SHARP, "SHARP", 0, "Tag Sharp", ""},
|
|
|
|
|
{EDGE_MODE_TAG_CREASE, "CREASE", 0, "Tag Crease", ""},
|
|
|
|
|
{EDGE_MODE_TAG_BEVEL, "BEVEL", 0, "Tag Bevel", ""},
|
|
|
|
|
{EDGE_MODE_TAG_FREESTYLE, "FREESTYLE", 0, "Tag Freestyle Edge Mark", ""},
|
2023-07-05 20:03:41 +02:00
|
|
|
{0, nullptr, 0, nullptr, nullptr},
|
2019-05-21 11:13:45 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RNA_def_enum(ot->srna,
|
|
|
|
|
"edge_mode",
|
|
|
|
|
edge_tag_items,
|
|
|
|
|
EDGE_MODE_SELECT,
|
|
|
|
|
"Edge Tag",
|
|
|
|
|
"The edge flag to tag when selecting the shortest path");
|
|
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
RNA_def_boolean(ot->srna,
|
2015-12-27 22:38:12 +11:00
|
|
|
"use_face_step",
|
|
|
|
|
false,
|
|
|
|
|
"Face Stepping",
|
|
|
|
|
"Traverse connected faces (includes diagonals and edge-rings)");
|
|
|
|
|
RNA_def_boolean(ot->srna,
|
|
|
|
|
"use_topology_distance",
|
|
|
|
|
false,
|
|
|
|
|
"Topology Distance",
|
2015-12-27 18:05:53 +11:00
|
|
|
"Find the minimum number of steps, ignoring spatial distance");
|
2016-03-31 04:21:02 +11:00
|
|
|
RNA_def_boolean(ot->srna,
|
|
|
|
|
"use_fill",
|
|
|
|
|
false,
|
|
|
|
|
"Fill Region",
|
|
|
|
|
"Select all paths between the source/destination elements");
|
2015-12-27 18:05:53 +11:00
|
|
|
WM_operator_properties_checker_interval(ot, true);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 11:13:45 +10:00
|
|
|
static void path_select_params_from_op(wmOperator *op,
|
|
|
|
|
ToolSettings *ts,
|
2023-07-20 11:30:25 +10:00
|
|
|
PathSelectParams *op_params)
|
2015-12-27 18:05:53 +11:00
|
|
|
{
|
2019-05-21 11:13:45 +10:00
|
|
|
{
|
|
|
|
|
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "edge_mode");
|
|
|
|
|
if (RNA_property_is_set(op->ptr, prop)) {
|
|
|
|
|
op_params->edge_mode = RNA_property_enum_get(op->ptr, prop);
|
|
|
|
|
if (op->flag & OP_IS_INVOKE) {
|
|
|
|
|
ts->edge_mode = op_params->edge_mode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
op_params->edge_mode = ts->edge_mode;
|
|
|
|
|
RNA_property_enum_set(op->ptr, prop, op_params->edge_mode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
op_params->track_active = false;
|
2015-12-27 22:38:12 +11:00
|
|
|
op_params->use_face_step = RNA_boolean_get(op->ptr, "use_face_step");
|
2016-03-31 04:21:02 +11:00
|
|
|
op_params->use_fill = RNA_boolean_get(op->ptr, "use_fill");
|
2015-12-27 22:38:12 +11:00
|
|
|
op_params->use_topology_distance = RNA_boolean_get(op->ptr, "use_topology_distance");
|
2015-12-27 18:05:53 +11:00
|
|
|
WM_operator_properties_checker_interval_from_op(op, &op_params->interval_params);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-21 11:13:45 +10:00
|
|
|
static bool path_select_poll_property(const bContext *C,
|
2023-07-05 20:03:41 +02:00
|
|
|
wmOperator * /*op*/,
|
2019-05-21 11:13:45 +10:00
|
|
|
const PropertyRNA *prop)
|
|
|
|
|
{
|
|
|
|
|
const char *prop_id = RNA_property_identifier(prop);
|
|
|
|
|
if (STREQ(prop_id, "edge_mode")) {
|
|
|
|
|
const Scene *scene = CTX_data_scene(C);
|
|
|
|
|
ToolSettings *ts = scene->toolsettings;
|
|
|
|
|
if ((ts->selectmode & SCE_SELECT_EDGE) == 0) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-04 01:23:51 +00:00
|
|
|
struct UserData {
|
|
|
|
|
BMesh *bm;
|
2023-12-08 16:40:06 -05:00
|
|
|
Mesh *mesh;
|
2023-05-19 14:31:31 +02:00
|
|
|
int cd_offset;
|
2023-07-20 11:30:25 +10:00
|
|
|
const PathSelectParams *op_params;
|
2013-06-04 01:23:51 +00:00
|
|
|
};
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
2013-06-04 01:23:51 +00:00
|
|
|
/* -------------------------------------------------------------------- */
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \name Vert Path
|
|
|
|
|
* \{ */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* callbacks */
|
2023-07-05 20:03:41 +02:00
|
|
|
static bool verttag_filter_cb(BMVert *v, void * /*user_data_v*/)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
|
|
|
|
return !BM_elem_flag_test(v, BM_ELEM_HIDDEN);
|
|
|
|
|
}
|
2023-07-05 20:03:41 +02:00
|
|
|
static bool verttag_test_cb(BMVert *v, void * /*user_data_v*/)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
|
|
|
|
return BM_elem_flag_test_bool(v, BM_ELEM_SELECT);
|
|
|
|
|
}
|
|
|
|
|
static void verttag_set_cb(BMVert *v, bool val, void *user_data_v)
|
|
|
|
|
{
|
2023-07-20 11:30:25 +10:00
|
|
|
UserData *user_data = static_cast<UserData *>(user_data_v);
|
2013-06-04 01:23:51 +00:00
|
|
|
BM_vert_select_set(user_data->bm, v, val);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
static void mouse_mesh_shortest_path_vert(Scene * /*scene*/,
|
2018-02-13 20:35:29 +11:00
|
|
|
Object *obedit,
|
2023-07-20 11:30:25 +10:00
|
|
|
const PathSelectParams *op_params,
|
2015-12-27 18:05:53 +11:00
|
|
|
BMVert *v_act,
|
|
|
|
|
BMVert *v_dst)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
2015-12-27 18:05:53 +11:00
|
|
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
2013-06-24 04:51:56 +00:00
|
|
|
BMesh *bm = em->bm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-05-19 14:31:31 +02:00
|
|
|
int cd_offset = -1;
|
|
|
|
|
switch (op_params->edge_mode) {
|
|
|
|
|
case EDGE_MODE_SELECT:
|
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
|
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE:
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
2023-06-13 20:23:39 +02:00
|
|
|
cd_offset = CustomData_get_offset_named(&bm->edata, CD_PROP_FLOAT, "crease_edge");
|
2023-05-19 14:31:31 +02:00
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
|
|
|
|
cd_offset = CustomData_get_offset_named(&bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
UserData user_data = {bm, static_cast<Mesh *>(obedit->data), cd_offset, op_params};
|
2023-07-05 20:03:41 +02:00
|
|
|
LinkNode *path = nullptr;
|
2016-04-01 23:27:31 +11:00
|
|
|
bool is_path_ordered = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (v_act && (v_act != v_dst)) {
|
2016-04-01 23:27:31 +11:00
|
|
|
if (op_params->use_fill) {
|
|
|
|
|
path = BM_mesh_calc_path_region_vert(
|
|
|
|
|
bm, (BMElem *)v_act, (BMElem *)v_dst, verttag_filter_cb, &user_data);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
is_path_ordered = true;
|
2023-07-05 20:03:41 +02:00
|
|
|
BMCalcPathParams params{};
|
|
|
|
|
params.use_topology_distance = op_params->use_topology_distance;
|
|
|
|
|
params.use_step_face = op_params->use_face_step;
|
|
|
|
|
path = BM_mesh_calc_path_vert(bm, v_act, v_dst, ¶ms, verttag_filter_cb, &user_data);
|
2016-04-01 23:27:31 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-01 23:27:31 +11:00
|
|
|
if (path) {
|
2015-12-27 18:05:53 +11:00
|
|
|
if (op_params->track_active) {
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_select_history_remove(bm, v_act);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
BMVert *v_dst_last = v_dst;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (path) {
|
|
|
|
|
/* toggle the flag */
|
|
|
|
|
bool all_set = true;
|
|
|
|
|
LinkNode *node;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
node = path;
|
|
|
|
|
do {
|
|
|
|
|
if (!verttag_test_cb((BMVert *)node->link, &user_data)) {
|
|
|
|
|
all_set = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} while ((node = node->next));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-09-04 22:46:24 +10:00
|
|
|
int depth = -1;
|
2015-12-27 18:05:53 +11:00
|
|
|
node = path;
|
|
|
|
|
do {
|
2016-04-01 23:27:31 +11:00
|
|
|
if ((is_path_ordered == false) ||
|
|
|
|
|
WM_operator_properties_checker_interval_test(&op_params->interval_params, depth))
|
|
|
|
|
{
|
2013-06-04 01:23:51 +00:00
|
|
|
verttag_set_cb((BMVert *)node->link, !all_set, &user_data);
|
2016-04-01 23:27:31 +11:00
|
|
|
if (is_path_ordered) {
|
2023-07-05 20:03:41 +02:00
|
|
|
v_dst_last = static_cast<BMVert *>(node->link);
|
2016-04-01 23:27:31 +11:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2016-03-05 09:16:12 +11:00
|
|
|
} while ((void)depth++, (node = node->next));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
BLI_linklist_free(path, nullptr);
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
|
|
|
|
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 */
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
EDBM_selectmode_flush(em);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (op_params->track_active) {
|
2013-06-04 01:23:51 +00:00
|
|
|
/* even if this is selected it may not be in the selection list */
|
2015-12-27 18:05:53 +11:00
|
|
|
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);
|
|
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
EDBMUpdate_Params params{};
|
2023-12-14 12:08:21 +11:00
|
|
|
params.calc_looptris = false;
|
2023-07-05 20:03:41 +02:00
|
|
|
params.calc_normals = false;
|
|
|
|
|
params.is_destructive = false;
|
|
|
|
|
EDBM_update(static_cast<Mesh *>(obedit->data), ¶ms);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \name Edge Path
|
|
|
|
|
* \{ */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* callbacks */
|
2023-07-05 20:03:41 +02:00
|
|
|
static bool edgetag_filter_cb(BMEdge *e, void * /*user_data_v*/)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
|
|
|
|
return !BM_elem_flag_test(e, BM_ELEM_HIDDEN);
|
|
|
|
|
}
|
|
|
|
|
static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
|
|
|
|
|
{
|
2023-07-20 11:30:25 +10:00
|
|
|
UserData *user_data = static_cast<UserData *>(user_data_v);
|
2015-12-27 18:05:53 +11:00
|
|
|
const char edge_mode = user_data->op_params->edge_mode;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
switch (edge_mode) {
|
2013-06-04 01:23:51 +00:00
|
|
|
case EDGE_MODE_SELECT:
|
|
|
|
|
return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false;
|
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
2013-06-24 05:26:42 +00:00
|
|
|
return BM_elem_flag_test(e, BM_ELEM_SEAM) ? true : false;
|
2013-06-04 01:23:51 +00:00
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
|
return BM_elem_flag_test(e, BM_ELEM_SMOOTH) ? false : true;
|
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
2023-05-19 14:31:31 +02:00
|
|
|
return BM_ELEM_CD_GET_FLOAT(e, user_data->cd_offset);
|
2013-06-04 01:23:51 +00:00
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE: {
|
2023-05-19 14:31:31 +02:00
|
|
|
BMesh *bm = user_data->bm;
|
2023-07-05 20:03:41 +02:00
|
|
|
FreestyleEdge *fed = static_cast<FreestyleEdge *>(
|
|
|
|
|
CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE));
|
2014-04-01 11:34:00 +11:00
|
|
|
return (!fed) ? false : (fed->flag & FREESTYLE_EDGE_MARK) ? true : false;
|
2014-03-19 12:46:33 +11:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
#endif
|
|
|
|
|
}
|
2023-07-22 11:36:59 +10:00
|
|
|
return false;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
|
static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
|
|
|
|
|
{
|
2023-07-20 11:30:25 +10:00
|
|
|
UserData *user_data = static_cast<UserData *>(user_data_v);
|
2015-12-27 18:05:53 +11:00
|
|
|
const char edge_mode = user_data->op_params->edge_mode;
|
2013-06-04 01:23:51 +00:00
|
|
|
BMesh *bm = user_data->bm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
switch (edge_mode) {
|
2013-06-04 01:23:51 +00:00
|
|
|
case EDGE_MODE_SELECT:
|
|
|
|
|
BM_edge_select_set(bm, e, val);
|
|
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
|
|
|
|
BM_elem_flag_set(e, BM_ELEM_SEAM, val);
|
|
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
|
BM_elem_flag_set(e, BM_ELEM_SMOOTH, !val);
|
|
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
2023-05-19 14:31:31 +02:00
|
|
|
BM_ELEM_CD_SET_FLOAT(e, user_data->cd_offset, (val) ? 1.0f : 0.0f);
|
2013-06-04 01:23:51 +00:00
|
|
|
break;
|
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE: {
|
|
|
|
|
FreestyleEdge *fed;
|
2023-07-05 20:03:41 +02:00
|
|
|
fed = static_cast<FreestyleEdge *>(
|
|
|
|
|
CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE));
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!val) {
|
2013-06-04 01:23:51 +00:00
|
|
|
fed->flag &= ~FREESTYLE_EDGE_MARK;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2013-06-04 01:23:51 +00:00
|
|
|
fed->flag |= FREESTYLE_EDGE_MARK;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-08 16:40:06 -05:00
|
|
|
static void edgetag_ensure_cd_flag(Mesh *mesh, const char edge_mode)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
2024-03-21 23:18:49 +01:00
|
|
|
BMesh *bm = mesh->runtime->edit_mesh->bm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-02-13 20:35:29 +11:00
|
|
|
switch (edge_mode) {
|
2013-06-04 01:23:51 +00:00
|
|
|
case EDGE_MODE_TAG_CREASE:
|
2023-06-13 20:23:39 +02:00
|
|
|
if (!CustomData_has_layer_named(&bm->edata, CD_PROP_FLOAT, "crease_edge")) {
|
|
|
|
|
BM_data_layer_add_named(bm, &bm->edata, CD_PROP_FLOAT, "crease_edge");
|
2022-09-23 09:02:05 -05:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
2023-05-19 14:31:31 +02:00
|
|
|
if (!CustomData_has_layer_named(&bm->edata, CD_PROP_FLOAT, "bevel_weight_edge")) {
|
|
|
|
|
BM_data_layer_add_named(bm, &bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
|
Mesh: Move bevel weight out of MVert and MEdge
As described in T95966, the goal is to move to a "struct of arrays"
approach rather than gathering an arbitrary set of data in hard-coded
structs. This has performance benefits, but also code complexity
benefits (this patch removes plenty of code, though the boilerplate
for the new operators outweighs that here).
To mirror the internal change, the options for storing mesh bevel
weights are converted into operators that add or remove the layer,
like for some other layers.
The most complex change is to the solidify modifier, where bevel
weights had special handling. Other than that, most changes are
removing clearing of the weights, boilerplate for the add/remove
operators, and removing the manual transfer of bevel weights
in bmesh - mesh conversion.
Eventually bevel weights can become a fully generic attribute,
but for now this patch aims to avoid most functional changes.
Bevel weights are still written and read from the mesh in the old way,
so neither forward nor backward compatibility are affected. As described
in T95965, writing in the old format will be done until 4.0.
Differential Revision: https://developer.blender.org/D14077
2022-09-09 08:29:07 -05:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
break;
|
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE:
|
|
|
|
|
if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
|
|
|
|
|
BM_data_layer_add(bm, &bm->edata, CD_FREESTYLE_EDGE);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-06 13:54:52 +11:00
|
|
|
/* Mesh shortest path select, uses previously-selected edge. */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* since you want to create paths with multiple selects, it doesn't have extend option */
|
2023-07-20 11:30:25 +10:00
|
|
|
static void mouse_mesh_shortest_path_edge(
|
|
|
|
|
Scene *scene, Object *obedit, const PathSelectParams *op_params, BMEdge *e_act, BMEdge *e_dst)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
2015-12-27 18:05:53 +11:00
|
|
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
2013-06-24 04:51:56 +00:00
|
|
|
BMesh *bm = em->bm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-05-19 14:31:31 +02:00
|
|
|
int cd_offset = -1;
|
|
|
|
|
switch (op_params->edge_mode) {
|
|
|
|
|
case EDGE_MODE_SELECT:
|
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
|
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE:
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
2023-06-13 20:23:39 +02:00
|
|
|
cd_offset = CustomData_get_offset_named(&bm->edata, CD_PROP_FLOAT, "crease_edge");
|
2023-05-19 14:31:31 +02:00
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
|
|
|
|
cd_offset = CustomData_get_offset_named(&bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
UserData user_data = {bm, static_cast<Mesh *>(obedit->data), cd_offset, op_params};
|
2023-07-05 20:03:41 +02:00
|
|
|
LinkNode *path = nullptr;
|
2016-04-01 23:27:31 +11:00
|
|
|
bool is_path_ordered = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
edgetag_ensure_cd_flag(static_cast<Mesh *>(obedit->data), op_params->edge_mode);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (e_act && (e_act != e_dst)) {
|
2016-04-01 23:27:31 +11:00
|
|
|
if (op_params->use_fill) {
|
|
|
|
|
path = BM_mesh_calc_path_region_edge(
|
|
|
|
|
bm, (BMElem *)e_act, (BMElem *)e_dst, edgetag_filter_cb, &user_data);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
is_path_ordered = true;
|
2023-07-05 20:03:41 +02:00
|
|
|
BMCalcPathParams params{};
|
|
|
|
|
params.use_topology_distance = op_params->use_topology_distance;
|
|
|
|
|
params.use_step_face = op_params->use_face_step;
|
|
|
|
|
path = BM_mesh_calc_path_edge(bm, e_act, e_dst, ¶ms, edgetag_filter_cb, &user_data);
|
2016-04-01 23:27:31 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-04-01 23:27:31 +11:00
|
|
|
if (path) {
|
2015-12-27 18:05:53 +11:00
|
|
|
if (op_params->track_active) {
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_select_history_remove(bm, e_act);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
BMEdge *e_dst_last = e_dst;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (path) {
|
|
|
|
|
/* toggle the flag */
|
|
|
|
|
bool all_set = true;
|
|
|
|
|
LinkNode *node;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
node = path;
|
|
|
|
|
do {
|
|
|
|
|
if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) {
|
|
|
|
|
all_set = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} while ((node = node->next));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-09-04 22:46:24 +10:00
|
|
|
int depth = -1;
|
2015-12-27 18:05:53 +11:00
|
|
|
node = path;
|
|
|
|
|
do {
|
2016-04-01 23:27:31 +11:00
|
|
|
if ((is_path_ordered == false) ||
|
|
|
|
|
WM_operator_properties_checker_interval_test(&op_params->interval_params, depth))
|
|
|
|
|
{
|
2013-06-04 01:23:51 +00:00
|
|
|
edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data);
|
2016-04-01 23:27:31 +11:00
|
|
|
if (is_path_ordered) {
|
2023-07-05 20:03:41 +02:00
|
|
|
e_dst_last = static_cast<BMEdge *>(node->link);
|
2016-04-01 23:27:31 +11:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2016-03-05 09:16:12 +11:00
|
|
|
} while ((void)depth++, (node = node->next));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
BLI_linklist_free(path, nullptr);
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const bool is_act = !edgetag_test_cb(e_dst, &user_data);
|
2023-07-05 20:03:41 +02:00
|
|
|
edgetag_ensure_cd_flag(static_cast<Mesh *>(obedit->data), op_params->edge_mode);
|
2015-12-27 18:05:53 +11:00
|
|
|
edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (op_params->edge_mode != EDGE_MODE_SELECT) {
|
|
|
|
|
if (op_params->track_active) {
|
2013-06-24 05:24:27 +00:00
|
|
|
/* simple rules - last edge is _always_ active and selected */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (e_act) {
|
2013-06-24 05:24:27 +00:00
|
|
|
BM_edge_select_set(bm, e_act, false);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
BM_edge_select_set(bm, e_dst_last, true);
|
|
|
|
|
BM_select_history_store(bm, e_dst_last);
|
2013-06-24 05:24:27 +00:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
EDBM_selectmode_flush(em);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (op_params->track_active) {
|
2013-06-04 01:23:51 +00:00
|
|
|
/* even if this is selected it may not be in the selection list */
|
2015-12-27 18:05:53 +11:00
|
|
|
if (op_params->edge_mode == EDGE_MODE_SELECT) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (edgetag_test_cb(e_dst_last, &user_data) == 0) {
|
2015-12-27 18:05:53 +11:00
|
|
|
BM_select_history_remove(bm, e_dst_last);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2015-12-27 18:05:53 +11:00
|
|
|
BM_select_history_store(bm, e_dst_last);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2013-06-24 05:24:27 +00:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
EDBMUpdate_Params params{};
|
2023-12-14 12:08:21 +11:00
|
|
|
params.calc_looptris = false;
|
2023-07-05 20:03:41 +02:00
|
|
|
params.calc_normals = false;
|
|
|
|
|
params.is_destructive = false;
|
|
|
|
|
EDBM_update(static_cast<Mesh *>(obedit->data), ¶ms);
|
2019-05-21 18:07:47 +02:00
|
|
|
|
|
|
|
|
if (op_params->edge_mode == EDGE_MODE_TAG_SEAM) {
|
2024-01-24 18:18:14 +01:00
|
|
|
ED_uvedit_live_unwrap(scene, {obedit});
|
2019-05-21 18:07:47 +02:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \name Face Path
|
|
|
|
|
* \{ */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* callbacks */
|
2023-07-05 20:03:41 +02:00
|
|
|
static bool facetag_filter_cb(BMFace *f, void * /*user_data_v*/)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
|
|
|
|
return !BM_elem_flag_test(f, BM_ELEM_HIDDEN);
|
|
|
|
|
}
|
2023-07-05 20:03:41 +02:00
|
|
|
// static bool facetag_test_cb(Scene * /*scene*/, BMesh * /*bm*/, BMFace *f)
|
|
|
|
|
static bool facetag_test_cb(BMFace *f, void * /*user_data_v*/)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
|
|
|
|
return BM_elem_flag_test_bool(f, BM_ELEM_SELECT);
|
|
|
|
|
}
|
2023-07-05 20:03:41 +02:00
|
|
|
// static void facetag_set_cb(BMesh *bm, Scene * /*scene*/, BMFace *f, const bool val)
|
2013-06-04 01:23:51 +00:00
|
|
|
static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
|
|
|
|
|
{
|
2023-07-20 11:30:25 +10:00
|
|
|
UserData *user_data = static_cast<UserData *>(user_data_v);
|
2013-06-04 01:23:51 +00:00
|
|
|
BM_face_select_set(user_data->bm, f, val);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
static void mouse_mesh_shortest_path_face(Scene * /*scene*/,
|
2018-02-13 20:35:29 +11:00
|
|
|
Object *obedit,
|
2023-07-20 11:30:25 +10:00
|
|
|
const PathSelectParams *op_params,
|
2015-12-27 18:05:53 +11:00
|
|
|
BMFace *f_act,
|
|
|
|
|
BMFace *f_dst)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
2015-12-27 18:05:53 +11:00
|
|
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
2013-06-24 04:51:56 +00:00
|
|
|
BMesh *bm = em->bm;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-05-19 14:31:31 +02:00
|
|
|
int cd_offset = -1;
|
|
|
|
|
switch (op_params->edge_mode) {
|
|
|
|
|
case EDGE_MODE_SELECT:
|
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
|
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE:
|
|
|
|
|
#endif
|
|
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
2023-06-13 20:23:39 +02:00
|
|
|
cd_offset = CustomData_get_offset_named(&bm->edata, CD_PROP_FLOAT, "crease_edge");
|
2023-05-19 14:31:31 +02:00
|
|
|
break;
|
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
|
|
|
|
cd_offset = CustomData_get_offset_named(&bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
UserData user_data = {bm, static_cast<Mesh *>(obedit->data), cd_offset, op_params};
|
2023-07-05 20:03:41 +02:00
|
|
|
LinkNode *path = nullptr;
|
2016-04-01 23:27:31 +11:00
|
|
|
bool is_path_ordered = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (f_act) {
|
2016-04-01 23:27:31 +11:00
|
|
|
if (op_params->use_fill) {
|
|
|
|
|
path = BM_mesh_calc_path_region_face(
|
|
|
|
|
bm, (BMElem *)f_act, (BMElem *)f_dst, facetag_filter_cb, &user_data);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
is_path_ordered = true;
|
2023-07-05 20:03:41 +02:00
|
|
|
BMCalcPathParams params{};
|
|
|
|
|
params.use_topology_distance = op_params->use_topology_distance;
|
|
|
|
|
params.use_step_face = op_params->use_face_step;
|
|
|
|
|
path = BM_mesh_calc_path_face(bm, f_act, f_dst, ¶ms, facetag_filter_cb, &user_data);
|
2016-04-01 23:27:31 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (f_act != f_dst) {
|
2016-04-01 23:27:31 +11:00
|
|
|
if (path) {
|
2015-12-27 18:05:53 +11:00
|
|
|
if (op_params->track_active) {
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_select_history_remove(bm, f_act);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
BMFace *f_dst_last = f_dst;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if (path) {
|
|
|
|
|
/* toggle the flag */
|
|
|
|
|
bool all_set = true;
|
|
|
|
|
LinkNode *node;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
node = path;
|
|
|
|
|
do {
|
|
|
|
|
if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
|
|
|
|
|
all_set = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} while ((node = node->next));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-09-04 22:46:24 +10:00
|
|
|
int depth = -1;
|
2015-12-27 18:05:53 +11:00
|
|
|
node = path;
|
|
|
|
|
do {
|
2016-04-01 23:27:31 +11:00
|
|
|
if ((is_path_ordered == false) ||
|
|
|
|
|
WM_operator_properties_checker_interval_test(&op_params->interval_params, depth))
|
|
|
|
|
{
|
2013-06-04 01:23:51 +00:00
|
|
|
facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
|
2016-04-01 23:27:31 +11:00
|
|
|
if (is_path_ordered) {
|
2023-07-05 20:03:41 +02:00
|
|
|
f_dst_last = static_cast<BMFace *>(node->link);
|
2016-04-01 23:27:31 +11:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2016-03-05 09:16:12 +11:00
|
|
|
} while ((void)depth++, (node = node->next));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
BLI_linklist_free(path, nullptr);
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
|
|
|
|
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 */
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
EDBM_selectmode_flush(em);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
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);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2015-12-27 18:05:53 +11:00
|
|
|
BM_select_history_store(bm, f_dst_last);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
BM_mesh_active_face_set(bm, f_dst_last);
|
2025-01-28 17:25:41 +11:00
|
|
|
|
|
|
|
|
if (f_dst_last->mat_nr != obedit->actcol - 1) {
|
|
|
|
|
obedit->actcol = f_dst_last->mat_nr + 1;
|
|
|
|
|
em->mat_nr = f_dst_last->mat_nr;
|
|
|
|
|
WM_main_add_notifier(NC_MATERIAL | ND_SHADING_LINKS, nullptr);
|
|
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
EDBMUpdate_Params params{};
|
2023-12-14 12:08:21 +11:00
|
|
|
params.calc_looptris = false;
|
2023-07-05 20:03:41 +02:00
|
|
|
params.calc_normals = false;
|
|
|
|
|
params.is_destructive = false;
|
|
|
|
|
EDBM_update(static_cast<Mesh *>(obedit->data), ¶ms);
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \name Main Operator for vert/edge/face tag
|
|
|
|
|
* \{ */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
static bool edbm_shortest_path_pick_ex(Scene *scene,
|
2018-02-13 20:35:29 +11:00
|
|
|
Object *obedit,
|
2023-07-20 11:30:25 +10:00
|
|
|
const PathSelectParams *op_params,
|
2015-12-27 18:05:53 +11:00
|
|
|
BMElem *ele_src,
|
|
|
|
|
BMElem *ele_dst)
|
|
|
|
|
{
|
2018-12-14 11:55:29 +11:00
|
|
|
bool ok = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
if (ELEM(nullptr, ele_src, ele_dst) || (ele_src->head.htype != ele_dst->head.htype)) {
|
2015-12-27 18:05:53 +11:00
|
|
|
/* pass */
|
|
|
|
|
}
|
|
|
|
|
else if (ele_src->head.htype == BM_VERT) {
|
2018-02-13 20:35:29 +11:00
|
|
|
mouse_mesh_shortest_path_vert(scene, obedit, op_params, (BMVert *)ele_src, (BMVert *)ele_dst);
|
2018-12-14 11:55:29 +11:00
|
|
|
ok = true;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
else if (ele_src->head.htype == BM_EDGE) {
|
2018-02-13 20:35:29 +11:00
|
|
|
mouse_mesh_shortest_path_edge(scene, obedit, op_params, (BMEdge *)ele_src, (BMEdge *)ele_dst);
|
2018-12-14 11:55:29 +11:00
|
|
|
ok = true;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2015-12-27 18:05:53 +11:00
|
|
|
else if (ele_src->head.htype == BM_FACE) {
|
2018-02-13 20:35:29 +11:00
|
|
|
mouse_mesh_shortest_path_face(scene, obedit, op_params, (BMFace *)ele_src, (BMFace *)ele_dst);
|
2018-12-14 11:55:29 +11:00
|
|
|
ok = true;
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-14 11:55:29 +11:00
|
|
|
if (ok) {
|
2023-07-05 20:03:41 +02:00
|
|
|
DEG_id_tag_update(static_cast<ID *>(obedit->data), ID_RECALC_SELECT);
|
2018-12-14 11:55:29 +11:00
|
|
|
WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-12-14 11:55:29 +11:00
|
|
|
return ok;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
static int edbm_shortest_path_pick_exec(bContext *C, wmOperator *op);
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2018-04-06 12:07:27 +02:00
|
|
|
static BMElem *edbm_elem_find_nearest(ViewContext *vc, const char htype)
|
2015-12-27 18:05:53 +11:00
|
|
|
{
|
|
|
|
|
BMEditMesh *em = vc->em;
|
|
|
|
|
float dist = ED_view3d_select_dist_px();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
if ((em->selectmode & SCE_SELECT_VERTEX) && (htype == BM_VERT)) {
|
2018-04-06 12:07:27 +02:00
|
|
|
return (BMElem *)EDBM_vert_find_nearest(vc, &dist);
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2020-07-03 15:19:52 +02:00
|
|
|
if ((em->selectmode & SCE_SELECT_EDGE) && (htype == BM_EDGE)) {
|
2018-04-06 12:07:27 +02:00
|
|
|
return (BMElem *)EDBM_edge_find_nearest(vc, &dist);
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2020-07-03 15:19:52 +02:00
|
|
|
if ((em->selectmode & SCE_SELECT_FACE) && (htype == BM_FACE)) {
|
2018-04-06 12:07:27 +02:00
|
|
|
return (BMElem *)EDBM_face_find_nearest(vc, &dist);
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
return nullptr;
|
2015-12-27 18:05:53 +11:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2016-05-12 07:09:08 +10:00
|
|
|
static BMElem *edbm_elem_active_elem_or_face_get(BMesh *bm)
|
|
|
|
|
{
|
|
|
|
|
BMElem *ele = BM_mesh_active_elem_get(bm);
|
|
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
if ((ele == nullptr) && bm->act_face && BM_elem_flag_test(bm->act_face, BM_ELEM_SELECT)) {
|
2016-05-12 07:09:08 +10:00
|
|
|
ele = (BMElem *)bm->act_face;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ele;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
2015-12-27 18:05:53 +11:00
|
|
|
if (RNA_struct_property_is_set(op->ptr, "index")) {
|
|
|
|
|
return edbm_shortest_path_pick_exec(C, op);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
BMVert *eve = nullptr;
|
|
|
|
|
BMEdge *eed = nullptr;
|
|
|
|
|
BMFace *efa = nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-01 16:33:04 +11:00
|
|
|
bool track_active = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-10-17 10:34:59 +02:00
|
|
|
ViewContext vc = em_setup_viewcontext(C);
|
2013-06-04 01:23:51 +00:00
|
|
|
copy_v2_v2_int(vc.mval, event->mval);
|
2022-09-14 21:33:51 +02:00
|
|
|
BKE_view_layer_synced_ensure(vc.scene, vc.view_layer);
|
|
|
|
|
Base *basact = BKE_view_layer_active_base_get(vc.view_layer);
|
2021-03-29 16:45:37 +11:00
|
|
|
BMEditMesh *em = vc.em;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-02-04 21:17:14 +11:00
|
|
|
view3d_operator_needs_gpu(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-09-10 15:42:40 +10:00
|
|
|
{
|
|
|
|
|
int base_index = -1;
|
2024-01-24 18:18:14 +01:00
|
|
|
Vector<Base *> bases = BKE_view_layer_array_from_bases_in_edit_mode(
|
|
|
|
|
vc.scene, vc.view_layer, vc.v3d);
|
|
|
|
|
if (EDBM_unified_findnearest(&vc, bases, &base_index, &eve, &eed, &efa)) {
|
2018-09-10 15:42:40 +10:00
|
|
|
basact = bases[base_index];
|
|
|
|
|
ED_view3d_viewcontext_init_object(&vc, basact->object);
|
|
|
|
|
em = vc.em;
|
|
|
|
|
}
|
2018-08-21 13:19:02 -03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-08-21 13:27:06 -03:00
|
|
|
/* If nothing is selected, let's select the picked vertex/edge/face. */
|
|
|
|
|
if ((vc.em->bm->totvertsel == 0) && (eve || eed || efa)) {
|
2020-09-19 14:32:41 +10:00
|
|
|
/* TODO(dfelinto): right now we try to find the closest element twice.
|
2018-08-21 13:27:06 -03:00
|
|
|
* The ideal is to refactor EDBM_select_pick so it doesn't
|
2020-09-19 14:32:41 +10:00
|
|
|
* have to pick the nearest vert/edge/face again. */
|
2023-07-05 20:03:41 +02:00
|
|
|
SelectPick_Params params{};
|
|
|
|
|
params.sel_op = SEL_OP_ADD;
|
2022-03-15 21:03:04 +11:00
|
|
|
EDBM_select_pick(C, event->mval, ¶ms);
|
2018-08-21 13:27:06 -03:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
PathSelectParams op_params;
|
2019-05-21 11:13:45 +10:00
|
|
|
path_select_params_from_op(op, vc.scene->toolsettings, &op_params);
|
|
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
BMElem *ele_src, *ele_dst;
|
2016-05-12 07:09:08 +10:00
|
|
|
if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
|
2018-04-06 12:07:27 +02:00
|
|
|
!(ele_dst = edbm_elem_find_nearest(&vc, ele_src->head.htype)))
|
|
|
|
|
{
|
2016-03-01 16:33:04 +11:00
|
|
|
/* special case, toggle edge tags even when we don't have a path */
|
2019-05-21 11:13:45 +10:00
|
|
|
if (((em->selectmode & SCE_SELECT_EDGE) && (op_params.edge_mode != EDGE_MODE_SELECT)) &&
|
2016-03-01 16:33:04 +11:00
|
|
|
/* check if we only have a destination edge */
|
2023-07-05 20:03:41 +02:00
|
|
|
((ele_src == nullptr) && (ele_dst = edbm_elem_find_nearest(&vc, BM_EDGE))))
|
2018-04-06 12:07:27 +02:00
|
|
|
{
|
2016-03-01 16:33:04 +11:00
|
|
|
ele_src = ele_dst;
|
|
|
|
|
track_active = false;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2016-03-01 16:33:04 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-03-01 16:33:04 +11:00
|
|
|
op_params.track_active = track_active;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-02-13 20:35:29 +11:00
|
|
|
if (!edbm_shortest_path_pick_ex(vc.scene, vc.obedit, &op_params, ele_src, ele_dst)) {
|
2015-12-27 18:05:53 +11:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-09-14 21:33:51 +02:00
|
|
|
BKE_view_layer_synced_ensure(vc.scene, vc.view_layer);
|
|
|
|
|
if (BKE_view_layer_active_base_get(vc.view_layer) != basact) {
|
2024-03-28 01:30:38 +01:00
|
|
|
blender::ed::object::base_activate(C, basact);
|
2018-08-21 13:19:02 -03:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
/* to support redo */
|
2015-12-28 21:26:02 +11:00
|
|
|
BM_mesh_elem_index_ensure(em->bm, ele_dst->head.htype);
|
2015-12-27 18:05:53 +11:00
|
|
|
int index = EDBM_elem_to_index_any(em, ele_dst);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
RNA_int_set(op->ptr, "index", index);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
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;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
const int index = RNA_int_get(op->ptr, "index");
|
|
|
|
|
if (index < 0 || index >= (bm->totvert + bm->totedge + bm->totface)) {
|
|
|
|
|
return OPERATOR_CANCELLED;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
BMElem *ele_src, *ele_dst;
|
2016-05-12 07:09:08 +10:00
|
|
|
if (!(ele_src = edbm_elem_active_elem_or_face_get(em->bm)) ||
|
2015-12-27 18:05:53 +11:00
|
|
|
!(ele_dst = EDBM_elem_from_index_any(em, index)))
|
|
|
|
|
{
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-20 11:30:25 +10:00
|
|
|
PathSelectParams op_params;
|
2019-05-21 11:13:45 +10:00
|
|
|
path_select_params_from_op(op, scene->toolsettings, &op_params);
|
2015-12-27 18:05:53 +11:00
|
|
|
op_params.track_active = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-02-13 20:35:29 +11:00
|
|
|
if (!edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst)) {
|
2015-12-27 18:05:53 +11:00
|
|
|
return OPERATOR_CANCELLED;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
return OPERATOR_FINISHED;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MESH_OT_shortest_path_pick(wmOperatorType *ot)
|
|
|
|
|
{
|
2015-12-27 18:05:53 +11:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
2013-06-04 01:23:51 +00:00
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Pick Shortest Path";
|
|
|
|
|
ot->idname = "MESH_OT_shortest_path_pick";
|
|
|
|
|
ot->description = "Select shortest path between two selections";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->invoke = edbm_shortest_path_pick_invoke;
|
2015-12-27 18:05:53 +11:00
|
|
|
ot->exec = edbm_shortest_path_pick_exec;
|
2013-06-04 01:23:51 +00:00
|
|
|
ot->poll = ED_operator_editmesh_region_view3d;
|
2019-05-21 11:13:45 +10:00
|
|
|
ot->poll_property = path_select_poll_property;
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
/* properties */
|
2015-12-27 18:05:53 +11:00
|
|
|
path_select_properties(ot);
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2015-12-27 18:05:53 +11:00
|
|
|
/* 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);
|
|
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \} */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2018-03-16 20:46:14 +11:00
|
|
|
/** \name Select Path Between Existing Selection
|
|
|
|
|
* \{ */
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
2015-12-27 18:05:53 +11:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
2018-05-24 19:22:28 +02:00
|
|
|
bool found_valid_elements = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-24 19:22:28 +02:00
|
|
|
ViewLayer *view_layer = CTX_data_view_layer(C);
|
2024-01-24 18:18:14 +01:00
|
|
|
Vector<Object *> objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
|
|
|
|
|
scene, view_layer, CTX_wm_view3d(C));
|
|
|
|
|
for (Object *obedit : objects) {
|
2018-05-24 19:22:28 +02:00
|
|
|
BMEditMesh *em = BKE_editmesh_from_object(obedit);
|
|
|
|
|
BMesh *bm = em->bm;
|
|
|
|
|
BMIter iter;
|
|
|
|
|
BMEditSelection *ese_src, *ese_dst;
|
2023-07-05 20:03:41 +02:00
|
|
|
BMElem *ele_src = nullptr, *ele_dst = nullptr, *ele;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-24 19:22:28 +02:00
|
|
|
if ((em->bm->totvertsel == 0) && (em->bm->totedgesel == 0) && (em->bm->totfacesel == 0)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-24 19:22:28 +02:00
|
|
|
/* first try to find vertices in edit selection */
|
2023-07-05 20:03:41 +02:00
|
|
|
ese_src = static_cast<BMEditSelection *>(bm->selected.last);
|
2018-05-24 19:22:28 +02:00
|
|
|
if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) {
|
|
|
|
|
ele_src = ese_src->ele;
|
|
|
|
|
ele_dst = ese_dst->ele;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* if selection history isn't available, find two selected elements */
|
2023-07-05 20:03:41 +02:00
|
|
|
ele_src = ele_dst = nullptr;
|
2018-05-24 19:22:28 +02:00
|
|
|
if ((em->selectmode & SCE_SELECT_VERTEX) && (bm->totvertsel >= 2)) {
|
|
|
|
|
BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
|
|
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
|
2023-07-05 20:03:41 +02:00
|
|
|
if (ele_src == nullptr) {
|
2018-05-24 19:22:28 +02:00
|
|
|
ele_src = ele;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2023-07-05 20:03:41 +02:00
|
|
|
else if (ele_dst == nullptr) {
|
2018-05-24 19:22:28 +02:00
|
|
|
ele_dst = ele;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2018-05-24 19:22:28 +02:00
|
|
|
break;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-05-24 19:22:28 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
if ((ele_dst == nullptr) && (em->selectmode & SCE_SELECT_EDGE) && (bm->totedgesel >= 2)) {
|
|
|
|
|
ele_src = nullptr;
|
2018-05-24 19:22:28 +02:00
|
|
|
BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
|
|
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
|
2023-07-05 20:03:41 +02:00
|
|
|
if (ele_src == nullptr) {
|
2018-05-24 19:22:28 +02:00
|
|
|
ele_src = ele;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2023-07-05 20:03:41 +02:00
|
|
|
else if (ele_dst == nullptr) {
|
2018-05-24 19:22:28 +02:00
|
|
|
ele_dst = ele;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2018-05-24 19:22:28 +02:00
|
|
|
break;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2018-05-24 19:22:28 +02:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-07-05 20:03:41 +02:00
|
|
|
if ((ele_dst == nullptr) && (em->selectmode & SCE_SELECT_FACE) && (bm->totfacesel >= 2)) {
|
|
|
|
|
ele_src = nullptr;
|
2018-05-24 19:22:28 +02:00
|
|
|
BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
|
|
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
|
2023-07-05 20:03:41 +02:00
|
|
|
if (ele_src == nullptr) {
|
2018-05-24 19:22:28 +02:00
|
|
|
ele_src = ele;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2023-07-05 20:03:41 +02:00
|
|
|
else if (ele_dst == nullptr) {
|
2018-05-24 19:22:28 +02:00
|
|
|
ele_dst = ele;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2018-05-24 19:22:28 +02:00
|
|
|
break;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-24 19:22:28 +02:00
|
|
|
if (ele_src && ele_dst) {
|
2023-07-20 11:30:25 +10:00
|
|
|
PathSelectParams op_params;
|
2019-05-21 11:13:45 +10:00
|
|
|
path_select_params_from_op(op, scene->toolsettings, &op_params);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-24 19:22:28 +02:00
|
|
|
edbm_shortest_path_pick_ex(scene, obedit, &op_params, ele_src, ele_dst);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-24 19:22:28 +02:00
|
|
|
found_valid_elements = true;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2018-05-24 19:22:28 +02:00
|
|
|
if (!found_valid_elements) {
|
|
|
|
|
BKE_report(
|
|
|
|
|
op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected");
|
2013-06-04 01:23:51 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2018-05-24 19:22:28 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MESH_OT_shortest_path_select(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Select Shortest Path";
|
|
|
|
|
ot->idname = "MESH_OT_shortest_path_select";
|
2017-10-19 11:09:27 +11:00
|
|
|
ot->description = "Selected shortest path between two vertices/edges/faces";
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec = edbm_shortest_path_select_exec;
|
|
|
|
|
ot->poll = ED_operator_editmesh;
|
2019-05-21 11:13:45 +10:00
|
|
|
ot->poll_property = path_select_poll_property;
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
/* properties */
|
2015-12-27 18:05:53 +11:00
|
|
|
path_select_properties(ot);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
2018-03-16 20:46:14 +11:00
|
|
|
|
|
|
|
|
/** \} */
|