Multi-Object Editing

This adds initial multi-object editing support.

- Selected objects are used when entering edit & pose modes.
- Selection & tools work on all objects however many tools need porting
  See: T54641 for remaining tasks.

Indentation will be done separately.

See patch: D3101
This commit is contained in:
2018-04-16 16:27:55 +02:00
parent 80bb4254c6
commit bfc9d426bb
58 changed files with 3786 additions and 1486 deletions

View File

@@ -66,6 +66,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "DEG_depsgraph.h"
@@ -89,7 +90,10 @@
#include "uvedit_intern.h"
static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action);
static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit);
static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len);
static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action);
static void uv_select_all_perform_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len, int action);
static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
@@ -794,6 +798,21 @@ bool uv_find_nearest_edge(
return found;
}
bool uv_find_nearest_edge_multi(
Scene *scene, Image *ima, Object **objects, const uint objects_len,
const float co[2], UvNearestHit *hit_final)
{
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
if (uv_find_nearest_edge(scene, ima, obedit, co, hit_final)) {
hit_final->ob = obedit;
found = true;
}
}
return found;
}
bool uv_find_nearest_face(
Scene *scene, Image *ima, Object *obedit, const float co[2],
UvNearestHit *hit_final)
@@ -837,6 +856,21 @@ bool uv_find_nearest_face(
return found;
}
bool uv_find_nearest_face_multi(
Scene *scene, Image *ima, Object **objects, const uint objects_len,
const float co[2], UvNearestHit *hit_final)
{
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
if (uv_find_nearest_face(scene, ima, obedit, co, hit_final)) {
hit_final->ob = obedit;
found = true;
}
}
return found;
}
static bool uv_nearest_between(
const BMLoop *l, const float co[2],
const int cd_loop_uv_offset)
@@ -918,6 +952,21 @@ bool uv_find_nearest_vert(
return found;
}
bool uv_find_nearest_vert_multi(
Scene *scene, Image *ima, Object **objects, const uint objects_len,
float const co[2], const float penalty_dist, UvNearestHit *hit_final)
{
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
if (uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, hit_final)) {
hit_final->ob = obedit;
found = true;
}
}
return found;
}
bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2])
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
@@ -1043,9 +1092,10 @@ static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1,
}
static int uv_select_edgeloop(
Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, UvNearestHit *hit,
Scene *scene, Image *ima, Object *obedit, UvNearestHit *hit,
const float limit[2], const bool extend)
{
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMIter iter, liter;
BMLoop *l;
@@ -1064,7 +1114,7 @@ static int uv_select_edgeloop(
BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
if (!extend) {
uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
uv_select_all_perform(scene, ima, obedit, SEL_DESELECT);
}
BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
@@ -1147,10 +1197,17 @@ static int uv_select_edgeloop(
/** \name Select Linked
* \{ */
static void uv_select_linked(
Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float limit[2],
static void uv_select_linked_multi(
Scene *scene, Image *ima, Object **objects, const uint objects_len, const float limit[2],
UvNearestHit *hit_final, bool extend, bool select_faces)
{
/* loop over objects, or just use hit_final->ob */
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
if (hit_final && ob_index != 0) {
break;
}
Object *obedit = hit_final ? hit_final->ob : objects[ob_index];
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -1161,6 +1218,7 @@ static void uv_select_linked(
unsigned int a;
char *flag;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
@@ -1336,6 +1394,7 @@ static void uv_select_linked(
MEM_freeN(stack);
MEM_freeN(flag);
BM_uv_vert_map_free(vmap);
}
}
/* WATCH IT: this returns first selected UV,
@@ -1957,9 +2016,53 @@ static void UV_OT_weld(wmOperatorType *ot)
/** \name (De)Select All Operator
* \{ */
static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action)
static bool uv_select_is_any_selected(Scene *scene, Image *ima, Object *obedit)
{
ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
if (ts->uv_flag & UV_SYNC_SELECTION) {
return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel);
}
else {
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa)) {
continue;
}
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (luv->flag & MLOOPUV_VERTSEL) {
return true;
}
}
}
}
return false;
}
static bool uv_select_is_any_selected_multi(Scene *scene, Image *ima, Object **objects, const uint objects_len)
{
bool found = false;
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
if (uv_select_is_any_selected(scene, ima, obedit)) {
found = true;
break;
}
}
return found;
}
static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, int action)
{
ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -1967,8 +2070,11 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (ts->uv_flag & UV_SYNC_SELECTION) {
if (action == SEL_TOGGLE) {
action = uv_select_is_any_selected(scene, ima, obedit) ? SEL_DESELECT : SEL_SELECT;
}
if (ts->uv_flag & UV_SYNC_SELECTION) {
switch (action) {
case SEL_TOGGLE:
EDBM_select_toggle_all(em);
@@ -1986,24 +2092,6 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd
}
}
else {
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
if (luv->flag & MLOOPUV_VERTSEL) {
action = SEL_DESELECT;
break;
}
}
}
}
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!uvedit_face_visible_test(scene, obedit, ima, efa))
continue;
@@ -2027,18 +2115,38 @@ static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEd
}
}
static void uv_select_all_perform_multi(
Scene *scene, Image *ima, Object **objects, const uint objects_len, int action)
{
if (action == SEL_TOGGLE) {
action = uv_select_is_any_selected_multi(scene, ima, objects, objects_len) ? SEL_DESELECT : SEL_SELECT;
}
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
uv_select_all_perform(scene, ima, obedit, action);
}
}
static int uv_select_all_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
ViewLayer *view_layer = CTX_data_view_layer(C);
int action = RNA_enum_get(op->ptr, "action");
uv_select_all_perform(scene, ima, obedit, em, action);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
uv_select_all_perform_multi(scene, ima, objects, objects_len, action);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
MEM_SAFE_FREE(objects);
return OPERATOR_FINISHED;
}
@@ -2087,14 +2195,14 @@ static bool uv_sticky_select(float *limit, int hitv[], int v, float *hituv[], fl
return false;
}
static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop)
static int uv_mouse_select_multi(
bContext *C, Object **objects, uint objects_len,
const float co[2], bool extend, bool loop)
{
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
Object *obedit = CTX_data_edit_object(C);
Image *ima = CTX_data_edit_image(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
@@ -2105,8 +2213,6 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */
float limit[2], **hituv = NULL;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
/* notice 'limit' is the same no matter the zoom level, since this is like
* remove doubles and could annoying if it joined points when zoomed out.
* 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
@@ -2143,7 +2249,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
/* find nearest element */
if (loop) {
/* find edge */
if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2151,7 +2257,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_VERTEX) {
/* find vertex */
if (!uv_find_nearest_vert(scene, ima, obedit, co, penalty_dist, &hit)) {
if (!uv_find_nearest_vert_multi(scene, ima, objects, objects_len, co, penalty_dist, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2167,7 +2273,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_EDGE) {
/* find edge */
if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2185,10 +2291,13 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else if (selectmode == UV_SELECT_FACE) {
/* find face */
if (!uv_find_nearest_face(scene, ima, obedit, co, &hit)) {
if (!uv_find_nearest_face_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
BMEditMesh *em = BKE_editmesh_from_object(hit.ob);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
/* make active */
BM_mesh_active_face_set(em->bm, hit.efa);
@@ -2205,7 +2314,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
hitlen = hit.efa->len;
}
else if (selectmode == UV_SELECT_ISLAND) {
if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
return OPERATOR_CANCELLED;
}
@@ -2216,12 +2325,24 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
return OPERATOR_CANCELLED;
}
Object *obedit = hit.ob;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
/* do selection */
if (loop) {
flush = uv_select_edgeloop(scene, ima, obedit, em, &hit, limit, extend);
if (!extend) {
/* TODO(MULTI_EDIT): We only need to de-select non-active */
uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
}
flush = uv_select_edgeloop(scene, ima, obedit, &hit, limit, extend);
}
else if (selectmode == UV_SELECT_ISLAND) {
uv_select_linked(scene, ima, obedit, em, limit, &hit, extend, false);
if (!extend) {
/* TODO(MULTI_EDIT): We only need to de-select non-active */
uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
}
uv_select_linked_multi(scene, ima, objects, objects_len, limit, &hit, extend, false);
}
else if (extend) {
if (selectmode == UV_SELECT_VERTEX) {
@@ -2271,7 +2392,7 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
}
else {
/* deselect all */
uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
if (selectmode == UV_SELECT_VERTEX) {
/* select vertex */
@@ -2339,6 +2460,15 @@ static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loo
return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
}
static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop)
{
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_with_uvs(view_layer, &objects_len);
int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, loop);
MEM_freeN(objects);
return ret;
}
static int uv_select_exec(bContext *C, wmOperator *op)
{
@@ -2443,9 +2573,8 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
Object *obedit = CTX_data_edit_object(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
float limit[2];
int extend;
bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
@@ -2460,6 +2589,9 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
extend = RNA_boolean_get(op->ptr, "extend");
uvedit_pixel_to_float(sima, limit, 0.05f);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
if (pick) {
float co[2];
@@ -2475,15 +2607,32 @@ static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent
RNA_float_get_array(op->ptr, "location", co);
}
if (!uv_find_nearest_edge(scene, ima, obedit, co, &hit)) {
if (!uv_find_nearest_edge_multi(scene, ima, objects, objects_len, co, &hit)) {
MEM_SAFE_FREE(objects);
return OPERATOR_CANCELLED;
}
}
uv_select_linked(scene, ima, obedit, em, limit, pick ? &hit : NULL, extend, select_faces);
if (!extend) {
uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
}
DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
uv_select_linked_multi(scene, ima, objects, objects_len, limit, pick ? &hit : NULL, extend, select_faces);
/* weak!, but works */
Object **objects_free = objects;
if (pick) {
objects = &hit.ob;
objects_len = 1;
}
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
DEG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
MEM_SAFE_FREE(objects_free);
return OPERATOR_FINISHED;
}
@@ -2879,23 +3028,20 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
SpaceImage *sima = CTX_wm_space_image(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
Object *obedit = CTX_data_edit_object(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
MLoopUV *luv;
rctf rectf;
bool changed, pinned, select, extend;
bool pinned, select, extend;
const bool use_face_center = (
(ts->uv_flag & UV_SYNC_SELECTION) ?
(ts->selectmode == SCE_SELECT_FACE) :
(ts->uv_selectmode == UV_SELECT_FACE));
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
/* get rectangle from operator */
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
@@ -2905,8 +3051,22 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
extend = RNA_boolean_get(op->ptr, "extend");
pinned = RNA_boolean_get(op->ptr, "pinned");
bool changed_multi = false;
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
/* don't indent to avoid diff noise! */
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
BMEditMesh *em = BKE_editmesh_from_object(obedit);
bool changed = false;
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (!extend)
uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
/* do actual selection */
if (use_face_center && !pinned) {
@@ -2972,12 +3132,17 @@ static int uv_border_select_exec(bContext *C, wmOperator *op)
if (ts->uv_flag & UV_SYNC_SELECTION) {
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
}
return OPERATOR_FINISHED;
}
changed_multi |= changed;
}
MEM_SAFE_FREE(objects);
if (changed_multi) {
return OPERATOR_FINISHED;
}
return OPERATOR_CANCELLED;
}
}
static void UV_OT_select_border(wmOperatorType *ot)
{
@@ -3131,36 +3296,46 @@ static void UV_OT_circle_select(wmOperatorType *ot)
/** \name Lasso Select Operator
* \{ */
static bool do_lasso_select_mesh_uv(
bContext *C, const int mcords[][2], short moves,
const bool select, const bool extend)
static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves,
const bool select, const bool extend)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
ARegion *ar = CTX_wm_region(C);
Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
ToolSettings *ts = scene->toolsettings;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
ViewLayer *view_layer = CTX_data_view_layer(C);
const bool use_face_center = (
(ts->uv_flag & UV_SYNC_SELECTION) ?
(ts->selectmode == SCE_SELECT_FACE) :
(ts->uv_selectmode == UV_SELECT_FACE));
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
BMIter iter, liter;
BMFace *efa;
BMLoop *l;
int screen_uv[2];
bool changed = false;
bool changed_multi = false;
rcti rect;
BLI_lasso_boundbox(&rect, mcords, moves);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
/* don't indent to avoid diff noise! */
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
bool changed = false;
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
if (!extend && select) {
uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
uv_select_all_perform_multi(scene, ima, objects, objects_len, SEL_DESELECT);
}
if (use_face_center) { /* Face Center Sel */
@@ -3223,7 +3398,10 @@ static bool do_lasso_select_mesh_uv(
}
}
return changed;
changed_multi |= changed;
}
return changed_multi;
}
static int uv_lasso_select_exec(bContext *C, wmOperator *op)
@@ -4175,7 +4353,7 @@ static int uv_mark_seam_exec(bContext *C, wmOperator *op)
me->drawflag |= ME_DRAWSEAMS;
if (scene->toolsettings->edge_mode_live_unwrap)
ED_unwrap_lscm(scene, ob, false);
ED_unwrap_lscm(scene, ob, false, false);
DEG_id_tag_update(&me->id, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);