merge from master
[blender.git] / source / blender / editors / uvedit / uvedit_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Antony Riakiotakis.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/uvedit/uvedit_ops.c
29  *  \ingroup eduv
30  */
31
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <math.h>
36 #include <string.h>
37
38 #include "MEM_guardedalloc.h"
39
40 #include "DNA_object_types.h"
41 #include "DNA_material_types.h"
42 #include "DNA_mesh_types.h"
43 #include "DNA_meshdata_types.h"
44 #include "DNA_node_types.h"
45 #include "DNA_image_types.h"
46 #include "DNA_space_types.h"
47 #include "DNA_scene_types.h"
48
49 #include "BLI_utildefines.h"
50 #include "BLI_alloca.h"
51 #include "BLI_math.h"
52 #include "BLI_lasso_2d.h"
53 #include "BLI_blenlib.h"
54 #include "BLI_array.h"
55
56 #include "BLT_translation.h"
57
58 #include "BKE_context.h"
59 #include "BKE_customdata.h"
60 #include "BKE_image.h"
61 #include "BKE_library.h"
62 #include "BKE_main.h"
63 #include "BKE_material.h"
64 #include "BKE_mesh_mapping.h"
65 #include "BKE_node.h"
66 #include "BKE_report.h"
67 #include "BKE_scene.h"
68 #include "BKE_editmesh.h"
69
70 #include "DEG_depsgraph.h"
71
72 #include "ED_image.h"
73 #include "ED_mesh.h"
74 #include "ED_node.h"
75 #include "ED_uvedit.h"
76 #include "ED_object.h"
77 #include "ED_screen.h"
78 #include "ED_transform.h"
79
80 #include "RNA_access.h"
81 #include "RNA_define.h"
82
83 #include "WM_api.h"
84 #include "WM_types.h"
85
86 #include "UI_interface.h"
87 #include "UI_resources.h"
88 #include "UI_view2d.h"
89
90 #include "uvedit_intern.h"
91
92 static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action);
93 static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
94 static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select);
95
96 /************************* state testing ************************/
97
98 bool ED_uvedit_test(Object *obedit)
99 {
100         BMEditMesh *em;
101         int ret;
102
103         if (!obedit)
104                 return 0;
105         
106         if (obedit->type != OB_MESH)
107                 return 0;
108
109         em = BKE_editmesh_from_object(obedit);
110         ret = EDBM_uv_check(em);
111         
112         return ret;
113 }
114
115 static int ED_operator_uvedit_can_uv_sculpt(struct bContext *C)
116 {
117         SpaceImage *sima = CTX_wm_space_image(C);
118         ToolSettings *toolsettings = CTX_data_tool_settings(C);
119         Object *obedit = CTX_data_edit_object(C);
120
121         return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt);
122 }
123
124 static int UNUSED_FUNCTION(ED_operator_uvmap_mesh) (bContext *C)
125 {
126         Object *ob = CTX_data_active_object(C);
127
128         if (ob && ob->type == OB_MESH) {
129                 Mesh *me = ob->data;
130
131                 if (CustomData_get_layer(&me->fdata, CD_MTFACE) != NULL)
132                         return 1;
133         }
134
135         return 0;
136 }
137 /**************************** object active image *****************************/
138
139 static bool is_image_texture_node(bNode *node)
140 {
141         return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
142 }
143
144 bool ED_object_get_active_image(Object *ob, int mat_nr,
145                                 Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree)
146 {
147         Material *ma = give_current_material(ob, mat_nr);
148         bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
149         bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL;
150
151         if (node && is_image_texture_node(node)) {
152                 if (r_ima) *r_ima = (Image *)node->id;
153                 if (r_iuser) *r_iuser = NULL;
154                 if (r_node) *r_node = node;
155                 if (r_ntree) *r_ntree = ntree;
156                 return true;
157         }
158         
159         if (r_ima) *r_ima = NULL;
160         if (r_iuser) *r_iuser = NULL;
161         if (r_node) *r_node = node;
162         if (r_ntree) *r_ntree = ntree;
163
164         return false;
165 }
166
167 void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
168 {
169         Material *ma = give_current_material(ob, mat_nr);
170         bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
171
172         if (node && is_image_texture_node(node)) {
173                 node->id = &ima->id;
174                 ED_node_tag_update_nodetree(bmain, ma->nodetree, node);
175         }
176 }
177
178 /************************* assign image ************************/
179
180 //#define USE_SWITCH_ASPECT
181
182 void ED_uvedit_assign_image(Main *UNUSED(bmain), Scene *scene, Object *obedit, Image *ima, Image *previma)
183 {
184         BMEditMesh *em;
185         BMIter iter;
186         bool update = false;
187         const bool selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
188         
189         /* skip assigning these procedural images... */
190         if (ima && (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE))
191                 return;
192
193         /* verify we have a mesh we can work with */
194         if (!obedit || (obedit->type != OB_MESH))
195                 return;
196
197         em = BKE_editmesh_from_object(obedit);
198         if (!em || !em->bm->totface) {
199                 return;
200         }
201
202         if (BKE_scene_use_new_shading_nodes(scene)) {
203                 /* new shading system, do not assign anything */
204         }
205         else {
206                 BMFace *efa;
207
208                 int cd_loop_uv_offset;
209                 /* old shading system, assign image to selected faces */
210 #ifdef USE_SWITCH_ASPECT
211                 float prev_aspect[2], fprev_aspect;
212                 float aspect[2], faspect;
213
214                 ED_image_get_uv_aspect(previma, prev_aspect, prev_aspect + 1);
215                 ED_image_get_uv_aspect(ima, aspect, aspect + 1);
216
217                 fprev_aspect = prev_aspect[0] / prev_aspect[1];
218                 faspect = aspect[0] / aspect[1];
219 #endif
220
221                 /* ensure we have a uv map */
222                 if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
223                         BM_data_layer_add(em->bm, &em->bm->ldata, CD_MLOOPUV);
224                         /* make UVs all nice 0-1 */
225                         ED_mesh_uv_loop_reset_ex(obedit->data, CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPUV));
226                         update = true;
227                 }
228
229                 cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
230
231                 /* now assign to all visible faces */
232                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
233                         if (uvedit_face_visible_test(scene, obedit, previma, efa) &&
234                             (selected == true || uvedit_face_select_test(scene, efa, cd_loop_uv_offset)))
235                         {
236 #ifdef USE_SWITCH_ASPECT
237                                 if (ima) {
238                                         /* we also need to correct the aspect of uvs */
239                                         if (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) {
240                                                 /* do nothing */
241                                         }
242                                         else {
243                                                 BMIter liter;
244                                                 BMLoop *l;
245
246                                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
247                                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
248
249                                                         luv->uv[0] *= fprev_aspect;
250                                                         luv->uv[0] /= faspect;
251                                                 }
252                                         }
253                                 }
254 #endif
255                                 BKE_object_material_edit_image_set(obedit, efa->mat_nr, ima);
256
257                                 update = true;
258                         }
259                 }
260
261                 /* and update depdency graph */
262                 if (update) {
263                         DEG_id_tag_update(obedit->data, 0);
264                 }
265         }
266
267 }
268
269 /*********************** space conversion *********************/
270
271 static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
272 {
273         int width, height;
274
275         if (sima) {
276                 ED_space_image_get_size(sima, &width, &height);
277         }
278         else {
279                 width =  IMG_SIZE_FALLBACK;
280                 height = IMG_SIZE_FALLBACK;
281         }
282
283         dist[0] = pixeldist / width;
284         dist[1] = pixeldist / height;
285 }
286
287 /*************** visibility and selection utilities **************/
288
289 static void uvedit_vertex_select_tagged(BMEditMesh *em, Scene *scene, bool select, int cd_loop_uv_offset)
290 {
291         BMFace *efa;
292         BMLoop *l;
293         BMIter iter, liter;
294
295         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
296                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
297                         if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
298                                 uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
299                         }
300                 }
301         }
302 }
303
304 bool uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
305 {
306         ToolSettings *ts = scene->toolsettings;
307
308         if (ts->uv_flag & UV_SYNC_SELECTION)
309                 return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0);
310         else
311                 return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT));
312 }
313
314 bool uvedit_face_visible_test(Scene *scene, Object *obedit, Image *ima, BMFace *efa)
315 {
316         ToolSettings *ts = scene->toolsettings;
317
318         if (ts->uv_flag & UV_SHOW_SAME_IMAGE) {
319                 const Image *face_image = BKE_object_material_edit_image_get(obedit, efa->mat_nr);
320                 return (face_image == ima) ? uvedit_face_visible_nolocal(scene, efa) : false;
321         }
322         else {
323                 return uvedit_face_visible_nolocal(scene, efa);
324         }
325 }
326
327 bool uvedit_face_select_test(Scene *scene, BMFace *efa,
328                              const int cd_loop_uv_offset)
329 {
330         ToolSettings *ts = scene->toolsettings;
331         if (ts->uv_flag & UV_SYNC_SELECTION) {
332                 return (BM_elem_flag_test(efa, BM_ELEM_SELECT));
333         }
334         else {
335                 BMLoop *l;
336                 MLoopUV *luv;
337                 BMIter liter;
338
339                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
340                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
341                         if (!(luv->flag & MLOOPUV_VERTSEL))
342                                 return false;
343                 }
344
345                 return true;
346         }
347 }
348
349 bool uvedit_face_select_set(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const bool select,
350                             const bool do_history, const int cd_loop_uv_offset)
351 {
352         if (select) {
353                 return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset);
354         }
355         else {
356                 return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
357         }
358 }
359
360 bool uvedit_face_select_enable(Scene *scene, BMEditMesh *em, BMFace *efa, const bool do_history,
361                                const int cd_loop_uv_offset)
362 {
363         ToolSettings *ts = scene->toolsettings;
364
365         if (ts->uv_flag & UV_SYNC_SELECTION) {
366                 BM_face_select_set(em->bm, efa, true);
367                 if (do_history) {
368                         BM_select_history_store(em->bm, (BMElem *)efa);
369                 }
370         }
371         else {
372                 BMLoop *l;
373                 MLoopUV *luv;
374                 BMIter liter;
375
376                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
377                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
378                         luv->flag |= MLOOPUV_VERTSEL;
379                 }
380
381                 return true;
382         }
383
384         return false;
385 }
386
387 bool uvedit_face_select_disable(Scene *scene, BMEditMesh *em, BMFace *efa,
388                                 const int cd_loop_uv_offset)
389 {
390         ToolSettings *ts = scene->toolsettings;
391
392         if (ts->uv_flag & UV_SYNC_SELECTION) {
393                 BM_face_select_set(em->bm, efa, false);
394         }
395         else {
396                 BMLoop *l;
397                 MLoopUV *luv;
398                 BMIter liter;
399
400                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
401                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
402                         luv->flag &= ~MLOOPUV_VERTSEL;
403                 }
404
405                 return true;
406         }
407
408         return false;
409 }
410
411 bool uvedit_edge_select_test(Scene *scene, BMLoop *l,
412                              const int cd_loop_uv_offset)
413 {
414         ToolSettings *ts = scene->toolsettings;
415
416         if (ts->uv_flag & UV_SYNC_SELECTION) {
417                 if (ts->selectmode & SCE_SELECT_FACE) {
418                         return BM_elem_flag_test(l->f, BM_ELEM_SELECT);
419                 }
420                 else if (ts->selectmode == SCE_SELECT_EDGE) {
421                         return BM_elem_flag_test(l->e, BM_ELEM_SELECT);
422                 }
423                 else {
424                         return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && 
425                                BM_elem_flag_test(l->next->v, BM_ELEM_SELECT);
426                 }
427         }
428         else {
429                 MLoopUV *luv1, *luv2;
430
431                 luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
432                 luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
433
434                 return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
435         }
436 }
437
438 void uvedit_edge_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
439                             const bool do_history, const int cd_loop_uv_offset)
440
441 {
442         if (select) {
443                 uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
444         }
445         else {
446                 uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset);
447         }
448 }
449
450 void uvedit_edge_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l, const bool do_history,
451                                const int cd_loop_uv_offset)
452
453 {
454         ToolSettings *ts = scene->toolsettings;
455
456         if (ts->uv_flag & UV_SYNC_SELECTION) {
457                 if (ts->selectmode & SCE_SELECT_FACE)
458                         BM_face_select_set(em->bm, l->f, true);
459                 else if (ts->selectmode & SCE_SELECT_EDGE)
460                         BM_edge_select_set(em->bm, l->e, true);
461                 else {
462                         BM_vert_select_set(em->bm, l->e->v1, true);
463                         BM_vert_select_set(em->bm, l->e->v2, true);
464                 }
465
466                 if (do_history) {
467                         BM_select_history_store(em->bm, (BMElem *)l->e);
468                 }
469         }
470         else {
471                 MLoopUV *luv1, *luv2;
472
473                 luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
474                 luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
475                 
476                 luv1->flag |= MLOOPUV_VERTSEL;
477                 luv2->flag |= MLOOPUV_VERTSEL;
478         }
479 }
480
481 void uvedit_edge_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
482                                 const int cd_loop_uv_offset)
483
484 {
485         ToolSettings *ts = scene->toolsettings;
486
487         if (ts->uv_flag & UV_SYNC_SELECTION) {
488                 if (ts->selectmode & SCE_SELECT_FACE)
489                         BM_face_select_set(em->bm, l->f, false);
490                 else if (ts->selectmode & SCE_SELECT_EDGE)
491                         BM_edge_select_set(em->bm, l->e, false);
492                 else {
493                         BM_vert_select_set(em->bm, l->e->v1, false);
494                         BM_vert_select_set(em->bm, l->e->v2, false);
495                 }
496         }
497         else {
498                 MLoopUV *luv1, *luv2;
499
500                 luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
501                 luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
502                 
503                 luv1->flag &= ~MLOOPUV_VERTSEL;
504                 luv2->flag &= ~MLOOPUV_VERTSEL;
505         }
506 }
507
508 bool uvedit_uv_select_test(Scene *scene, BMLoop *l,
509                            const int cd_loop_uv_offset)
510 {
511         ToolSettings *ts = scene->toolsettings;
512
513         if (ts->uv_flag & UV_SYNC_SELECTION) {
514                 if (ts->selectmode & SCE_SELECT_FACE)
515                         return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT);
516                 else
517                         return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT);
518         }
519         else {
520                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
521                 return (luv->flag & MLOOPUV_VERTSEL) != 0;
522         }
523 }
524
525 void uvedit_uv_select_set(BMEditMesh *em, Scene *scene, BMLoop *l, const bool select,
526                           const bool do_history, const int cd_loop_uv_offset)
527 {
528         if (select) {
529                 uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset);
530         }
531         else {
532                 uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset);
533         }
534 }
535
536 void uvedit_uv_select_enable(BMEditMesh *em, Scene *scene, BMLoop *l,
537                              const bool do_history, const int cd_loop_uv_offset)
538 {
539         ToolSettings *ts = scene->toolsettings;
540
541         if (ts->uv_flag & UV_SYNC_SELECTION) {
542                 if (ts->selectmode & SCE_SELECT_FACE)
543                         BM_face_select_set(em->bm, l->f, true);
544                 else
545                         BM_vert_select_set(em->bm, l->v, true);
546
547                 if (do_history) {
548                         BM_select_history_remove(em->bm, (BMElem *)l->v);
549                 }
550         }
551         else {
552                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
553                 luv->flag |= MLOOPUV_VERTSEL;
554         }
555 }
556
557 void uvedit_uv_select_disable(BMEditMesh *em, Scene *scene, BMLoop *l,
558                               const int cd_loop_uv_offset)
559 {
560         ToolSettings *ts = scene->toolsettings;
561
562         if (ts->uv_flag & UV_SYNC_SELECTION) {
563                 if (ts->selectmode & SCE_SELECT_FACE)
564                         BM_face_select_set(em->bm, l->f, false);
565                 else
566                         BM_vert_select_set(em->bm, l->v, false);
567         }
568         else {
569                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
570                 luv->flag &= ~MLOOPUV_VERTSEL;
571         }
572 }
573
574 /*********************** live unwrap utilities ***********************/
575
576 void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
577 {
578         if (sima && (sima->flag & SI_LIVE_UNWRAP)) {
579                 ED_uvedit_live_unwrap_begin(scene, obedit);
580                 ED_uvedit_live_unwrap_re_solve();
581                 ED_uvedit_live_unwrap_end(0);
582         }
583 }
584
585 /*********************** geometric utilities ***********************/
586 void uv_poly_center(BMFace *f, float r_cent[2], const int cd_loop_uv_offset)
587 {
588         BMLoop *l;
589         MLoopUV *luv;
590         BMIter liter;
591
592         zero_v2(r_cent);
593
594         BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
595                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
596                 add_v2_v2(r_cent, luv->uv);
597         }
598
599         mul_v2_fl(r_cent, 1.0f / (float)f->len);
600 }
601
602 void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
603 {
604         int i;
605         for (i = 0; i < len; i++) {
606                 uv[i][0] = uv_orig[i][0] * aspx;
607                 uv[i][1] = uv_orig[i][1] * aspy;
608         }
609 }
610
611 bool ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float r_min[2], float r_max[2])
612 {
613         BMEditMesh *em = BKE_editmesh_from_object(obedit);
614         BMFace *efa;
615         BMLoop *l;
616         BMIter iter, liter;
617         MLoopUV *luv;
618         bool changed = false;
619
620         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
621
622         INIT_MINMAX2(r_min, r_max);
623
624         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
625                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
626                         continue;
627                 
628                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
629                         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
630                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
631                                 minmax_v2v2_v2(r_min, r_max, luv->uv);
632                                 changed = true;
633                         }
634                 }
635         }
636
637         return changed;
638 }
639
640 /* Be careful when using this, it bypasses all synchronization options */
641 void ED_uvedit_select_all(BMesh *bm)
642 {
643         BMFace *efa;
644         BMLoop *l;
645         BMIter iter, liter;
646         MLoopUV *luv;
647
648         const int cd_loop_uv_offset  = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
649
650         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
651                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
652                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
653                         luv->flag |= MLOOPUV_VERTSEL;
654                 }
655         }
656 }
657
658 static bool ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[2])
659 {
660         BMEditMesh *em = BKE_editmesh_from_object(obedit);
661         BMFace *efa;
662         BMLoop *l;
663         BMIter iter, liter;
664         MLoopUV *luv;
665         unsigned int sel = 0;
666
667         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
668
669         zero_v2(co);
670         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
671                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
672                         continue;
673                 
674                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
675                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
676                         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
677                                 add_v2_v2(co, luv->uv);
678                                 sel++;
679                         }
680                 }
681         }
682
683         mul_v2_fl(co, 1.0f / (float)sel);
684
685         return (sel != 0);
686 }
687
688 bool ED_uvedit_center(Scene *scene, Image *ima, Object *obedit, float cent[2], char mode)
689 {
690         bool changed = false;
691         
692         if (mode == V3D_AROUND_CENTER_BOUNDS) {  /* bounding box */
693                 float min[2], max[2];
694                 if (ED_uvedit_minmax(scene, ima, obedit, min, max)) {
695                         mid_v2_v2v2(cent, min, max);
696                         changed = true;
697                 }
698         }
699         else {
700                 if (ED_uvedit_median(scene, ima, obedit, cent)) {
701                         changed = true;
702                 }
703         }
704
705         return changed;
706 }
707
708 /************************** find nearest ****************************/
709
710 void uv_find_nearest_edge(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float co[2], NearestHit *hit)
711 {
712         BMFace *efa;
713         BMLoop *l;
714         BMIter iter, liter;
715         MLoopUV *luv, *luv_next;
716         float mindist_squared, dist_squared;
717         int i;
718
719         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
720
721         mindist_squared = 1e10f;
722         memset(hit, 0, sizeof(*hit));
723
724         BM_mesh_elem_index_ensure(em->bm, BM_VERT);
725         
726         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
727                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
728                         continue;
729                 
730                 BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
731                         luv      = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
732                         luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
733
734                         dist_squared = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv);
735
736                         if (dist_squared < mindist_squared) {
737                                 hit->efa = efa;
738                                 
739                                 hit->l = l;
740                                 hit->luv = luv;
741                                 hit->luv_next = luv_next;
742                                 hit->lindex = i;
743
744                                 mindist_squared = dist_squared;
745                         }
746                 }
747         }
748 }
749
750 static void uv_find_nearest_face(
751         Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, const float co[2], NearestHit *hit)
752 {
753         BMFace *efa;
754         BMIter iter;
755         float mindist, dist, cent[2];
756
757         const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
758
759         mindist = 1e10f;
760         memset(hit, 0, sizeof(*hit));
761
762         /*this will fill in hit.vert1 and hit.vert2*/
763         uv_find_nearest_edge(scene, ima, obedit, em, co, hit);
764         hit->l = NULL;
765         hit->luv = hit->luv_next = NULL;
766
767         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
768                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
769                         continue;
770
771                 uv_poly_center(efa, cent, cd_loop_uv_offset);
772
773                 dist = len_manhattan_v2v2(co, cent);
774
775                 if (dist < mindist) {
776                         hit->efa = efa;
777                         mindist = dist;
778                 }
779         }
780 }
781
782 static bool uv_nearest_between(const BMLoop *l, const float co[2],
783                                const int cd_loop_uv_offset)
784 {
785         const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv;
786         const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l,       cd_loop_uv_offset))->uv;
787         const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv;
788
789         return ((line_point_side_v2(uv_prev, uv_curr, co) >  0.0f) &&
790                 (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f));
791 }
792
793 void uv_find_nearest_vert(
794         Scene *scene, Image *ima, Object *obedit, BMEditMesh *em,
795         float const co[2], const float penalty[2], NearestHit *hit)
796 {
797         BMFace *efa;
798         BMLoop *l;
799         BMIter iter, liter;
800         MLoopUV *luv;
801         float mindist, dist;
802         int i;
803
804         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
805
806         /*this will fill in hit.vert1 and hit.vert2*/
807         uv_find_nearest_edge(scene, ima, obedit, em, co, hit);
808         hit->l = NULL;
809         hit->luv = hit->luv_next = NULL;
810
811         mindist = 1e10f;
812         memset(hit, 0, sizeof(*hit));
813         
814         BM_mesh_elem_index_ensure(em->bm, BM_VERT);
815
816         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
817                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
818                         continue;
819
820                 BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
821                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
822                         if (penalty && uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
823                                 dist = len_manhattan_v2v2(co, luv->uv) + len_manhattan_v2(penalty);
824                         else
825                                 dist = len_manhattan_v2v2(co, luv->uv);
826
827                         if (dist <= mindist) {
828                                 if (dist == mindist) {
829                                         if (!uv_nearest_between(l, co, cd_loop_uv_offset)) {
830                                                 continue;
831                                         }
832                                 }
833
834                                 mindist = dist;
835
836                                 hit->l = l;
837                                 hit->luv = luv;
838                                 hit->luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
839                                 hit->efa = efa;
840                                 hit->lindex = i;
841                         }
842                 }
843         }
844 }
845
846 bool ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, const float co[2], float r_uv[2])
847 {
848         BMEditMesh *em = BKE_editmesh_from_object(obedit);
849         BMFace *efa;
850         BMLoop *l;
851         BMIter iter, liter;
852         MLoopUV *luv;
853         float mindist, dist;
854         bool found = false;
855
856         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
857
858         mindist = 1e10f;
859         copy_v2_v2(r_uv, co);
860         
861         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
862                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
863                         continue;
864                 
865                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
866                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
867                         dist = len_manhattan_v2v2(co, luv->uv);
868
869                         if (dist <= mindist) {
870                                 mindist = dist;
871
872                                 copy_v2_v2(r_uv, luv->uv);
873                                 found = true;
874                         }
875                 }
876         }
877
878         return found;
879 }
880
881 /*********************** loop select ***********************/
882
883 static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first)
884 {
885         UvMapVert *iterv;
886         int count = 0;
887
888         for (iterv = first; iterv; iterv = iterv->next) {
889                 if (iterv->separate && iterv != first)
890                         break;
891
892                 count++;
893         }
894         
895         if (count < 5)
896                 first->flag = 1;
897 }
898
899 static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l)
900 {
901         UvMapVert *iterv, *first;
902         first = BM_uv_vert_map_at_index(vmap,  BM_elem_index_get(l->v));
903
904         for (iterv = first; iterv; iterv = iterv->next) {
905                 if (iterv->separate)
906                         first = iterv;
907                 if (iterv->f == BM_elem_index_get(efa))
908                         return first;
909         }
910         
911         return NULL;
912 }
913
914 static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface)
915 {
916         UvMapVert *iterv1, *iterv2;
917         BMFace *efa;
918         int tot = 0;
919
920         /* count number of faces this edge has */
921         for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
922                 if (iterv1->separate && iterv1 != first1)
923                         break;
924
925                 for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
926                         if (iterv2->separate && iterv2 != first2)
927                                 break;
928
929                         if (iterv1->f == iterv2->f) {
930                                 /* if face already tagged, don't do this edge */
931                                 efa = BM_face_at_index(em->bm, iterv1->f);
932                                 if (BM_elem_flag_test(efa, BM_ELEM_TAG))
933                                         return false;
934
935                                 tot++;
936                                 break;
937                         }
938                 }
939         }
940
941         if (*totface == 0) /* start edge */
942                 *totface = tot;
943         else if (tot != *totface) /* check for same number of faces as start edge */
944                 return false;
945
946         /* tag the faces */
947         for (iterv1 = first1; iterv1; iterv1 = iterv1->next) {
948                 if (iterv1->separate && iterv1 != first1)
949                         break;
950
951                 for (iterv2 = first2; iterv2; iterv2 = iterv2->next) {
952                         if (iterv2->separate && iterv2 != first2)
953                                 break;
954
955                         if (iterv1->f == iterv2->f) {
956                                 efa = BM_face_at_index(em->bm, iterv1->f);
957                                 BM_elem_flag_enable(efa, BM_ELEM_TAG);
958                                 break;
959                         }
960                 }
961         }
962
963         return true;
964 }
965
966 static int uv_select_edgeloop(
967         Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, NearestHit *hit,
968         const float limit[2], const bool extend)
969 {
970         BMFace *efa;
971         BMIter iter, liter;
972         BMLoop *l;
973         UvVertMap *vmap;
974         UvMapVert *iterv_curr;
975         UvMapVert *iterv_next;
976         int starttotf;
977         bool looking, select;
978
979         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
980
981         /* setup */
982         BM_mesh_elem_table_ensure(em->bm, BM_FACE);
983         vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
984
985         BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE);
986
987         if (!extend) {
988                 uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
989         }
990
991         BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
992
993         /* set flags for first face and verts */
994         iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
995         iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
996         uv_select_edgeloop_vertex_loop_flag(iterv_curr);
997         uv_select_edgeloop_vertex_loop_flag(iterv_next);
998
999         starttotf = 0;
1000         uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf);
1001
1002         /* sorry, first edge isn't even ok */
1003         looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0);
1004
1005         /* iterate */
1006         while (looking) {
1007                 looking = false;
1008
1009                 /* find correct valence edges which are not tagged yet, but connect to tagged one */
1010
1011                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1012                         if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, obedit, ima, efa)) {
1013                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1014                                         /* check face not hidden and not tagged */
1015                                         if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l)))
1016                                                 continue;
1017                                         if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next)))
1018                                                 continue;
1019
1020                                         /* check if vertex is tagged and has right valence */
1021                                         if (iterv_curr->flag || iterv_next->flag) {
1022                                                 if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) {
1023                                                         looking = true;
1024                                                         BM_elem_flag_enable(efa, BM_ELEM_TAG);
1025
1026                                                         uv_select_edgeloop_vertex_loop_flag(iterv_curr);
1027                                                         uv_select_edgeloop_vertex_loop_flag(iterv_next);
1028                                                         break;
1029                                                 }
1030                                         }
1031                                 }
1032                         }
1033                 }
1034         }
1035
1036         /* do the actual select/deselect */
1037         iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l);
1038         iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next);
1039         iterv_curr->flag = 1;
1040         iterv_next->flag = 1;
1041
1042         if (extend) {
1043                 select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset));
1044         }
1045         else {
1046                 select = true;
1047         }
1048         
1049         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1050                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1051                         iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l);
1052
1053                         if (iterv_curr->flag) {
1054                                 uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
1055                         }
1056                 }
1057         }
1058
1059         /* cleanup */
1060         BM_uv_vert_map_free(vmap);
1061
1062         return (select) ? 1 : -1;
1063 }
1064
1065 /*********************** linked select ***********************/
1066
1067 static void uv_select_linked(
1068         Scene *scene, Image *ima, Object *obedit, BMEditMesh *em,
1069         const float limit[2], NearestHit *hit, bool extend, bool select_faces)
1070 {
1071         BMFace *efa;
1072         BMLoop *l;
1073         BMIter iter, liter;
1074         MLoopUV *luv;
1075         UvVertMap *vmap;
1076         UvMapVert *vlist, *iterv, *startv;
1077         int i, stacksize = 0, *stack;
1078         unsigned int a;
1079         char *flag;
1080
1081         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1082
1083         BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */
1084
1085         /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320
1086          * this made *every* projection split the island into front/back islands.
1087          * Keep 'use_winding' to false, see: T50970.
1088          *
1089          * Better solve this by having a delimit option for select-linked operator,
1090          * keeping island-select working as is. */
1091         vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false);
1092
1093         if (vmap == NULL)
1094                 return;
1095
1096         stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack");
1097         flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag");
1098
1099         if (!hit) {
1100                 BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1101                         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
1102                                 if (select_faces) {
1103                                         if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1104                                                 stack[stacksize] = a;
1105                                                 stacksize++;
1106                                                 flag[a] = 1;
1107                                         }
1108                                 }
1109                                 else {
1110                                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1111                                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1112
1113                                                 if (luv->flag & MLOOPUV_VERTSEL) {
1114                                                         stack[stacksize] = a;
1115                                                         stacksize++;
1116                                                         flag[a] = 1;
1117
1118                                                         break;
1119                                                 }
1120                                         }
1121                                 }
1122                         }
1123                 }
1124         }
1125         else {
1126                 BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1127                         if (efa == hit->efa) {
1128                                 stack[stacksize] = a;
1129                                 stacksize++;
1130                                 flag[a] = 1;
1131                                 break;
1132                         }
1133                 }
1134         }
1135
1136         while (stacksize > 0) {
1137
1138                 stacksize--;
1139                 a = stack[stacksize];
1140
1141                 efa = BM_face_at_index(em->bm, a);
1142
1143                 BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1144
1145                         /* make_uv_vert_map_EM sets verts tmp.l to the indices */
1146                         vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
1147                         
1148                         startv = vlist;
1149
1150                         for (iterv = vlist; iterv; iterv = iterv->next) {
1151                                 if (iterv->separate)
1152                                         startv = iterv;
1153                                 if (iterv->f == a)
1154                                         break;
1155                         }
1156
1157                         for (iterv = startv; iterv; iterv = iterv->next) {
1158                                 if ((startv != iterv) && (iterv->separate))
1159                                         break;
1160                                 else if (!flag[iterv->f]) {
1161                                         flag[iterv->f] = 1;
1162                                         stack[stacksize] = iterv->f;
1163                                         stacksize++;
1164                                 }
1165                         }
1166                 }
1167         }
1168
1169         if (!extend) {
1170                 BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1171                         if (select_faces) {
1172                                 if (flag[a])
1173                                         BM_face_select_set(em->bm, efa, true);
1174                                 else
1175                                         BM_face_select_set(em->bm, efa, false);
1176                         }
1177                         else {
1178                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1179                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1180
1181                                         if (flag[a])
1182                                                 luv->flag |= MLOOPUV_VERTSEL;
1183                                         else
1184                                                 luv->flag &= ~MLOOPUV_VERTSEL;
1185                                 }
1186                         }
1187                 }
1188         }
1189         else {
1190                 BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1191                         if (!flag[a]) {
1192                                 continue;
1193                         }
1194
1195                         if (select_faces) {
1196                                 if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
1197                                         break;
1198                         }
1199                         else {
1200                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1201                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1202
1203                                         if (luv->flag & MLOOPUV_VERTSEL) {
1204                                                 break;
1205                                         }
1206                                 }
1207
1208                                 if (l) {
1209                                         break;
1210                                 }
1211                         }
1212                 }
1213
1214                 if (efa) {
1215                         BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1216                                 if (!flag[a]) {
1217                                         continue;
1218                                 }
1219
1220                                 if (select_faces) {
1221                                         BM_face_select_set(em->bm, efa, false);
1222                                 }
1223                                 else {
1224                                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1225                                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1226
1227                                                 luv->flag &= ~MLOOPUV_VERTSEL;
1228                                         }
1229                                 }
1230                         }
1231                 }
1232                 else {
1233                         BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) {
1234                                 if (!flag[a]) {
1235                                         continue;
1236                                 }
1237
1238                                 if (select_faces) {
1239                                         BM_face_select_set(em->bm, efa, true);
1240                                 }
1241                                 else {
1242                                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1243                                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1244
1245                                                 luv->flag |= MLOOPUV_VERTSEL;
1246                                         }
1247                                 }
1248                         }
1249                 }
1250         }
1251         
1252         MEM_freeN(stack);
1253         MEM_freeN(flag);
1254         BM_uv_vert_map_free(vmap);
1255 }
1256
1257 /* WATCH IT: this returns first selected UV,
1258  * not ideal in many cases since there could be multiple */
1259 static float *uv_sel_co_from_eve(Scene *scene, Object *obedit, Image *ima, BMEditMesh *em, BMVert *eve)
1260 {
1261         BMIter liter;
1262         BMLoop *l;
1263
1264         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1265
1266         BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
1267                 if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
1268                         continue;
1269
1270                 if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1271                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1272                         return luv->uv;
1273                 }
1274         }
1275
1276         return NULL;
1277 }
1278
1279 static int uv_select_more_less(bContext *C, const bool select)
1280 {
1281         Scene *scene = CTX_data_scene(C);
1282         Object *obedit = CTX_data_edit_object(C);
1283         Image *ima = CTX_data_edit_image(C);
1284         SpaceImage *sima = CTX_wm_space_image(C);
1285         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1286
1287         BMFace *efa;
1288         BMLoop *l;
1289         BMIter iter, liter;
1290         ToolSettings *ts = scene->toolsettings;
1291
1292         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1293
1294         if (ts->uv_flag & UV_SYNC_SELECTION) {
1295                 if (select) {
1296                         EDBM_select_more(em, true);
1297                 }
1298                 else {
1299                         EDBM_select_less(em, true);
1300                 }
1301
1302                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1303                 return OPERATOR_FINISHED;
1304         }
1305
1306         if (ts->uv_selectmode == UV_SELECT_FACE) {
1307
1308                 /* clear tags */
1309                 BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
1310
1311                 /* mark loops to be selected */
1312                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1313                         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
1314
1315 #define IS_SEL   1
1316 #define IS_UNSEL 2
1317
1318                                 int sel_state = 0;
1319
1320                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1321                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1322                                         if (luv->flag & MLOOPUV_VERTSEL) {
1323                                                 sel_state |= IS_SEL;
1324                                         }
1325                                         else {
1326                                                 sel_state |= IS_UNSEL;
1327                                         }
1328
1329                                         /* if we have a mixed selection, tag to grow it */
1330                                         if (sel_state == (IS_SEL | IS_UNSEL)) {
1331                                                 BM_elem_flag_enable(efa, BM_ELEM_TAG);
1332                                                 break;
1333                                         }
1334                                 }
1335
1336 #undef IS_SEL
1337 #undef IS_UNSEL
1338
1339                         }
1340                 }
1341
1342                 /* select tagged faces */
1343                 uv_select_flush_from_tag_face(sima, scene, obedit, select);
1344         }
1345         else {
1346
1347                 /* clear tags */
1348                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1349                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1350                                 BM_elem_flag_disable(l, BM_ELEM_TAG);
1351                         }
1352                 }
1353
1354                 /* mark loops to be selected */
1355                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1356                         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
1357                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1358
1359                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1360
1361                                         if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) {
1362                                                 BM_elem_flag_enable(l->next, BM_ELEM_TAG);
1363                                                 BM_elem_flag_enable(l->prev, BM_ELEM_TAG);
1364                                         }
1365                                 }
1366                         }
1367                 }
1368
1369                 /* select tagged loops */
1370                 uv_select_flush_from_tag_loop(sima, scene, obedit, select);
1371         }
1372
1373         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1374
1375         return OPERATOR_FINISHED;
1376 }
1377
1378 static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op))
1379 {
1380         return uv_select_more_less(C, true);
1381 }
1382
1383 static void UV_OT_select_more(wmOperatorType *ot)
1384 {
1385         /* identifiers */
1386         ot->name = "Select More";
1387         ot->description = "Select more UV vertices connected to initial selection";
1388         ot->idname = "UV_OT_select_more";
1389         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1390
1391         /* api callbacks */
1392         ot->exec = uv_select_more_exec;
1393         ot->poll = ED_operator_uvedit_space_image;
1394 }
1395
1396 static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op))
1397 {
1398         return uv_select_more_less(C, false);
1399 }
1400
1401 static void UV_OT_select_less(wmOperatorType *ot)
1402 {
1403         /* identifiers */
1404         ot->name = "Select Less";
1405         ot->description = "Deselect UV vertices at the boundary of each selection region";
1406         ot->idname = "UV_OT_select_less";
1407         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1408
1409         /* api callbacks */
1410         ot->exec = uv_select_less_exec;
1411         ot->poll = ED_operator_uvedit_space_image;
1412 }
1413
1414 /* ******************** align operator **************** */
1415
1416 static void uv_weld_align(bContext *C, int tool)
1417 {
1418         Object *obedit = CTX_data_edit_object(C);
1419         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1420         SpaceImage *sima;
1421         Scene *scene;
1422         Image *ima;
1423         float cent[2], min[2], max[2];
1424
1425         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1426
1427         scene = CTX_data_scene(C);
1428         ima = CTX_data_edit_image(C);
1429         sima = CTX_wm_space_image(C);
1430
1431         INIT_MINMAX2(min, max);
1432
1433         if (tool == 'a') {
1434                 BMIter iter, liter;
1435                 BMFace *efa;
1436                 BMLoop *l;
1437
1438                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1439                         if (!uvedit_face_visible_test(scene, obedit, ima, efa))
1440                                 continue;
1441
1442                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1443                                 if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1444                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1445                                         minmax_v2v2_v2(min, max, luv->uv);
1446                                 }
1447                         }
1448                 }
1449
1450                 tool = (max[0] - min[0] >= max[1] - min[1]) ? 'y' : 'x';
1451         }
1452
1453         ED_uvedit_center(scene, ima, obedit, cent, 0);
1454
1455         if (tool == 'x' || tool == 'w') {
1456                 BMIter iter, liter;
1457                 BMFace *efa;
1458                 BMLoop *l;
1459
1460                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1461                         if (!uvedit_face_visible_test(scene, obedit, ima, efa))
1462                                 continue;
1463
1464                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1465                                 if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1466                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1467                                         luv->uv[0] = cent[0];
1468                                 }
1469
1470                         }
1471                 }
1472         }
1473
1474         if (tool == 'y' || tool == 'w') {
1475                 BMIter iter, liter;
1476                 BMFace *efa;
1477                 BMLoop *l;
1478
1479                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1480                         if (!uvedit_face_visible_test(scene, obedit, ima, efa))
1481                                 continue;
1482
1483                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1484                                 if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1485                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1486                                         luv->uv[1] = cent[1];
1487                                 }
1488
1489                         }
1490                 }
1491         }
1492
1493         if (tool == 's' || tool == 't' || tool == 'u') {
1494                 BMEdge *eed;
1495                 BMLoop *l;
1496                 BMVert *eve;
1497                 BMVert *eve_start;
1498                 BMIter iter, liter, eiter;
1499
1500                 /* clear tag */
1501                 BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
1502
1503                 /* tag verts with a selected UV */
1504                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1505                         BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
1506                                 if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
1507                                         continue;
1508
1509                                 if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1510                                         BM_elem_flag_enable(eve, BM_ELEM_TAG);
1511                                         break;
1512                                 }
1513                         }
1514                 }
1515
1516                 /* flush vertex tags to edges */
1517                 BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
1518                         BM_elem_flag_set(eed, BM_ELEM_TAG, (BM_elem_flag_test(eed->v1, BM_ELEM_TAG) &&
1519                                                             BM_elem_flag_test(eed->v2, BM_ELEM_TAG)));
1520                 }
1521
1522                 /* find a vertex with only one tagged edge */
1523                 eve_start = NULL;
1524                 BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1525                         int tot_eed_tag = 0;
1526                         BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
1527                                 if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
1528                                         tot_eed_tag++;
1529                                 }
1530                         }
1531
1532                         if (tot_eed_tag == 1) {
1533                                 eve_start = eve;
1534                                 break;
1535                         }
1536                 }
1537
1538                 if (eve_start) {
1539                         BMVert **eve_line = NULL;
1540                         BMVert *eve_next = NULL;
1541                         BLI_array_declare(eve_line);
1542                         int i;
1543
1544                         eve = eve_start;
1545
1546                         /* walk over edges, building an array of verts in a line */
1547                         while (eve) {
1548                                 BLI_array_append(eve_line, eve);
1549                                 /* don't touch again */
1550                                 BM_elem_flag_disable(eve, BM_ELEM_TAG);
1551
1552                                 eve_next = NULL;
1553
1554                                 /* find next eve */
1555                                 BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
1556                                         if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
1557                                                 BMVert *eve_other = BM_edge_other_vert(eed, eve);
1558                                                 if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
1559                                                         /* this is a tagged vert we didnt walk over yet, step onto it */
1560                                                         eve_next = eve_other;
1561                                                         break;
1562                                                 }
1563                                         }
1564                                 }
1565
1566                                 eve = eve_next;
1567                         }
1568
1569                         /* now we have all verts, make into a line */
1570                         if (BLI_array_count(eve_line) > 2) {
1571
1572                                 /* we know the returns from these must be valid */
1573                                 const float *uv_start = uv_sel_co_from_eve(
1574                                         scene, obedit, ima, em, eve_line[0]);
1575                                 const float *uv_end   = uv_sel_co_from_eve(
1576                                         scene, obedit, ima, em, eve_line[BLI_array_count(eve_line) - 1]);
1577                                 /* For t & u modes */
1578                                 float a = 0.0f;
1579
1580                                 if (tool == 't') {
1581                                         if (uv_start[1] == uv_end[1])
1582                                                 tool = 's';
1583                                         else
1584                                                 a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
1585                                 }
1586                                 else if (tool == 'u') {
1587                                         if (uv_start[0] == uv_end[0])
1588                                                 tool = 's';
1589                                         else
1590                                                 a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
1591                                 }
1592
1593                                 /* go over all verts except for endpoints */
1594                                 for (i = 0; i < BLI_array_count(eve_line); i++) {
1595                                         BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
1596                                                 if (!uvedit_face_visible_test(scene, obedit, ima, l->f))
1597                                                         continue;
1598
1599                                                 if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1600                                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1601                                                         /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
1602                                                          * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
1603                                                          * Maybe this should be a BLI func? Or is it already existing?
1604                                                          * Could use interp_v2_v2v2, but not sure it's worth it here...*/
1605                                                         if (tool == 't')
1606                                                                 luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
1607                                                         else if (tool == 'u')
1608                                                                 luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
1609                                                         else
1610                                                                 closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
1611                                                 }
1612                                         }
1613                                 }
1614                         }
1615                         else {
1616                                 /* error - not a line, needs 3+ points  */
1617                         }
1618
1619                         if (eve_line) {
1620                                 MEM_freeN(eve_line);
1621                         }
1622                 }
1623                 else {
1624                         /* error - cant find an endpoint */
1625                 }
1626         }
1627
1628
1629         uvedit_live_unwrap_update(sima, scene, obedit);
1630         DEG_id_tag_update(obedit->data, 0);
1631         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1632 }
1633
1634 static int uv_align_exec(bContext *C, wmOperator *op)
1635 {
1636         uv_weld_align(C, RNA_enum_get(op->ptr, "axis"));
1637
1638         return OPERATOR_FINISHED;
1639 }
1640
1641 static void UV_OT_align(wmOperatorType *ot)
1642 {
1643         static const EnumPropertyItem axis_items[] = {
1644                 {'s', "ALIGN_S", 0, "Straighten", "Align UVs along the line defined by the endpoints"},
1645                 {'t', "ALIGN_T", 0, "Straighten X", "Align UVs along the line defined by the endpoints along the X axis"},
1646                 {'u', "ALIGN_U", 0, "Straighten Y", "Align UVs along the line defined by the endpoints along the Y axis"},
1647                 {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"},
1648                 {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
1649                 {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
1650                 {0, NULL, 0, NULL, NULL}};
1651
1652         /* identifiers */
1653         ot->name = "Align";
1654         ot->description = "Align selected UV vertices to an axis";
1655         ot->idname = "UV_OT_align";
1656         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1657         
1658         /* api callbacks */
1659         ot->exec = uv_align_exec;
1660         ot->poll = ED_operator_uvedit;
1661
1662         /* properties */
1663         RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
1664 }
1665 /* ******************** weld near operator **************** */
1666
1667 typedef struct UVvert {
1668         MLoopUV *uv_loop;
1669         bool weld;
1670 } UVvert;
1671
1672 static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
1673 {
1674         const float threshold = RNA_float_get(op->ptr, "threshold");
1675         const bool use_unselected = RNA_boolean_get(op->ptr, "use_unselected");
1676
1677         SpaceImage *sima;
1678         Scene *scene;
1679         Object *obedit = CTX_data_edit_object(C);
1680         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1681         Image *ima;
1682         int uv_a_index;
1683         int uv_b_index;
1684         float *uv_a;
1685         const float *uv_b;
1686
1687         BMIter iter, liter;
1688         BMFace *efa;
1689         BMLoop *l;
1690
1691         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1692
1693         sima = CTX_wm_space_image(C);
1694         scene = CTX_data_scene(C);
1695         ima = CTX_data_edit_image(C);
1696
1697         if (use_unselected == false) {
1698                 UVvert *vert_arr = NULL;
1699                 BLI_array_declare(vert_arr);
1700                 MLoopUV **loop_arr = NULL;
1701                 BLI_array_declare(loop_arr);
1702
1703                 /* TODO, use qsort as with MESH_OT_remove_doubles, this isn't optimal */
1704                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1705                         if (!uvedit_face_visible_test(scene, obedit, ima, efa))
1706                                 continue;
1707
1708                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1709                                 if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1710                                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1711                                         UVvert vert;
1712                                         vert.uv_loop = luv;
1713                                         vert.weld = false;
1714                                         BLI_array_append(vert_arr, vert);
1715                                 }
1716
1717                         }
1718                 }
1719
1720                 for (uv_a_index = 0; uv_a_index < BLI_array_count(vert_arr); uv_a_index++) {
1721                         if (vert_arr[uv_a_index].weld == false) {
1722                                 float uv_min[2];
1723                                 float uv_max[2];
1724
1725                                 BLI_array_clear(loop_arr);
1726                                 BLI_array_append(loop_arr, vert_arr[uv_a_index].uv_loop);
1727
1728                                 uv_a = vert_arr[uv_a_index].uv_loop->uv;
1729
1730                                 copy_v2_v2(uv_max, uv_a);
1731                                 copy_v2_v2(uv_min, uv_a);
1732
1733                                 vert_arr[uv_a_index].weld = true;
1734                                 for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_count(vert_arr); uv_b_index++) {
1735                                         uv_b = vert_arr[uv_b_index].uv_loop->uv;
1736                                         if ((vert_arr[uv_b_index].weld == false) &&
1737                                             (len_manhattan_v2v2(uv_a, uv_b) < threshold))
1738                                         {
1739                                                 minmax_v2v2_v2(uv_min, uv_max, uv_b);
1740                                                 BLI_array_append(loop_arr, vert_arr[uv_b_index].uv_loop);
1741                                                 vert_arr[uv_b_index].weld = true;
1742                                         }
1743                                 }
1744                                 if (BLI_array_count(loop_arr)) {
1745                                         float uv_mid[2];
1746                                         mid_v2_v2v2(uv_mid, uv_min, uv_max);
1747                                         for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr); uv_b_index++) {
1748                                                 copy_v2_v2(loop_arr[uv_b_index]->uv, uv_mid);
1749                                         }
1750                                 }
1751                         }
1752                 }
1753
1754                 BLI_array_free(vert_arr);
1755                 BLI_array_free(loop_arr);
1756         }
1757         else {
1758                 /* selected -> unselected
1759                  *
1760                  * No need to use 'UVvert' here */
1761                 MLoopUV **loop_arr = NULL;
1762                 BLI_array_declare(loop_arr);
1763                 MLoopUV **loop_arr_unselected = NULL;
1764                 BLI_array_declare(loop_arr_unselected);
1765
1766                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1767                         if (!uvedit_face_visible_test(scene, obedit, ima, efa))
1768                                 continue;
1769
1770                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1771                                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1772                                 if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1773                                         BLI_array_append(loop_arr, luv);
1774                                 }
1775                                 else {
1776                                         BLI_array_append(loop_arr_unselected, luv);
1777                                 }
1778                         }
1779                 }
1780
1781                 for (uv_a_index = 0; uv_a_index < BLI_array_count(loop_arr); uv_a_index++) {
1782                         float dist_best = FLT_MAX, dist;
1783                         const float *uv_best = NULL;
1784
1785                         uv_a = loop_arr[uv_a_index]->uv;
1786                         for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr_unselected); uv_b_index++) {
1787                                 uv_b = loop_arr_unselected[uv_b_index]->uv;
1788                                 dist = len_manhattan_v2v2(uv_a, uv_b);
1789                                 if ((dist < threshold) && (dist < dist_best)) {
1790                                         uv_best = uv_b;
1791                                         dist_best = dist;
1792                                 }
1793                         }
1794                         if (uv_best) {
1795                                 copy_v2_v2(uv_a, uv_best);
1796                         }
1797                 }
1798
1799                 BLI_array_free(loop_arr);
1800                 BLI_array_free(loop_arr_unselected);
1801         }
1802
1803         uvedit_live_unwrap_update(sima, scene, obedit);
1804         DEG_id_tag_update(obedit->data, 0);
1805         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1806
1807         return OPERATOR_FINISHED;
1808 }
1809
1810 static void UV_OT_remove_doubles(wmOperatorType *ot)
1811 {
1812         /* identifiers */
1813         ot->name = "Remove Doubles UV";
1814         ot->description = "Selected UV vertices that are within a radius of each other are welded together";
1815         ot->idname = "UV_OT_remove_doubles";
1816         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1817
1818         /* api callbacks */
1819         ot->exec = uv_remove_doubles_exec;
1820         ot->poll = ED_operator_uvedit;
1821
1822         RNA_def_float(ot->srna, "threshold", 0.02f, 0.0f, 10.0f,
1823                       "Merge Distance", "Maximum distance between welded vertices", 0.0f, 1.0f);
1824         RNA_def_boolean(ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
1825 }
1826 /* ******************** weld operator **************** */
1827
1828 static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op))
1829 {
1830         uv_weld_align(C, 'w');
1831
1832         return OPERATOR_FINISHED;
1833 }
1834
1835 static void UV_OT_weld(wmOperatorType *ot)
1836 {
1837         /* identifiers */
1838         ot->name = "Weld";
1839         ot->description = "Weld selected UV vertices together";
1840         ot->idname = "UV_OT_weld";
1841         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1842         
1843         /* api callbacks */
1844         ot->exec = uv_weld_exec;
1845         ot->poll = ED_operator_uvedit;
1846 }
1847
1848
1849 /* ******************** (de)select all operator **************** */
1850
1851 static void uv_select_all_perform(Scene *scene, Image *ima, Object *obedit, BMEditMesh *em, int action)
1852 {
1853         ToolSettings *ts = scene->toolsettings;
1854         BMFace *efa;
1855         BMLoop *l;
1856         BMIter iter, liter;
1857         MLoopUV *luv;
1858
1859         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1860
1861         if (ts->uv_flag & UV_SYNC_SELECTION) {
1862
1863                 switch (action) {
1864                         case SEL_TOGGLE:
1865                                 EDBM_select_toggle_all(em);
1866                                 break;
1867                         case SEL_SELECT:
1868                                 EDBM_flag_enable_all(em, BM_ELEM_SELECT);
1869                                 break;
1870                         case SEL_DESELECT:
1871                                 EDBM_flag_disable_all(em, BM_ELEM_SELECT);
1872                                 break;
1873                         case SEL_INVERT:
1874                                 EDBM_select_swap(em);
1875                                 EDBM_selectmode_flush(em);
1876                                 break;
1877                 }
1878         }
1879         else {
1880                 if (action == SEL_TOGGLE) {
1881                         action = SEL_SELECT;
1882                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1883                                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
1884                                         continue;
1885
1886                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1887                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1888
1889                                         if (luv->flag & MLOOPUV_VERTSEL) {
1890                                                 action = SEL_DESELECT;
1891                                                 break;
1892                                         }
1893                                 }
1894                         }
1895                 }
1896         
1897                 
1898                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1899                         if (!uvedit_face_visible_test(scene, obedit, ima, efa))
1900                                 continue;
1901
1902                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1903                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1904
1905                                 switch (action) {
1906                                         case SEL_SELECT:
1907                                                 luv->flag |= MLOOPUV_VERTSEL;
1908                                                 break;
1909                                         case SEL_DESELECT:
1910                                                 luv->flag &= ~MLOOPUV_VERTSEL;
1911                                                 break;
1912                                         case SEL_INVERT:
1913                                                 luv->flag ^= MLOOPUV_VERTSEL;
1914                                                 break;
1915                                 }
1916                         }
1917                 }
1918         }
1919 }
1920
1921 static int uv_select_all_exec(bContext *C, wmOperator *op)
1922 {
1923         Scene *scene = CTX_data_scene(C);
1924         Object *obedit = CTX_data_edit_object(C);
1925         Image *ima = CTX_data_edit_image(C);
1926         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1927
1928         int action = RNA_enum_get(op->ptr, "action");
1929
1930         uv_select_all_perform(scene, ima, obedit, em, action);
1931
1932         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
1933
1934         return OPERATOR_FINISHED;
1935 }
1936
1937 static void UV_OT_select_all(wmOperatorType *ot)
1938 {
1939         /* identifiers */
1940         ot->name = "(De)select All";
1941         ot->description = "Change selection of all UV vertices";
1942         ot->idname = "UV_OT_select_all";
1943         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1944         
1945         /* api callbacks */
1946         ot->exec = uv_select_all_exec;
1947         ot->poll = ED_operator_uvedit;
1948
1949         WM_operator_properties_select_all(ot);
1950 }
1951
1952 /* ******************** mouse select operator **************** */
1953
1954 static bool uv_sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky, int hitlen)
1955 {
1956         int i;
1957
1958         /* this function test if some vertex needs to selected
1959          * in addition to the existing ones due to sticky select */
1960         if (sticky == SI_STICKY_DISABLE)
1961                 return false;
1962
1963         for (i = 0; i < hitlen; i++) {
1964                 if (hitv[i] == v) {
1965                         if (sticky == SI_STICKY_LOC) {
1966                                 if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1])
1967                                         return true;
1968                         }
1969                         else if (sticky == SI_STICKY_VERTEX)
1970                                 return true;
1971                 }
1972         }
1973
1974         return false;
1975 }
1976
1977 static int uv_mouse_select(bContext *C, const float co[2], bool extend, bool loop)
1978 {
1979         SpaceImage *sima = CTX_wm_space_image(C);
1980         Scene *scene = CTX_data_scene(C);
1981         ToolSettings *ts = scene->toolsettings;
1982         Object *obedit = CTX_data_edit_object(C);
1983         Image *ima = CTX_data_edit_image(C);
1984         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1985         BMFace *efa;
1986         BMLoop *l;
1987         BMIter iter, liter;
1988         MLoopUV *luv;
1989         NearestHit hit;
1990         int i, selectmode, sticky, sync, *hitv = NULL;
1991         bool select = true;
1992         int flush = 0, hitlen = 0; /* 0 == don't flush, 1 == sel, -1 == desel;  only use when selection sync is enabled */
1993         float limit[2], **hituv = NULL;
1994         float penalty[2];
1995
1996         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1997
1998         /* notice 'limit' is the same no matter the zoom level, since this is like
1999          * remove doubles and could annoying if it joined points when zoomed out.
2000          * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
2001          * shift-selecting can consider an adjacent point close enough to add to
2002          * the selection rather than de-selecting the closest. */
2003
2004         uvedit_pixel_to_float(sima, limit, 0.05f);
2005         uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f));
2006
2007         /* retrieve operation mode */
2008         if (ts->uv_flag & UV_SYNC_SELECTION) {
2009                 sync = 1;
2010
2011                 if (ts->selectmode & SCE_SELECT_FACE)
2012                         selectmode = UV_SELECT_FACE;
2013                 else if (ts->selectmode & SCE_SELECT_EDGE)
2014                         selectmode = UV_SELECT_EDGE;
2015                 else
2016                         selectmode = UV_SELECT_VERTEX;
2017
2018                 sticky = SI_STICKY_DISABLE;
2019         }
2020         else {
2021                 sync = 0;
2022                 selectmode = ts->uv_selectmode;
2023                 sticky = (sima) ? sima->sticky : 1;
2024         }
2025
2026         /* find nearest element */
2027         if (loop) {
2028                 /* find edge */
2029                 uv_find_nearest_edge(scene, ima, obedit, em, co, &hit);
2030                 if (hit.efa == NULL) {
2031                         return OPERATOR_CANCELLED;
2032                 }
2033
2034                 hitlen = 0;
2035         }
2036         else if (selectmode == UV_SELECT_VERTEX) {
2037                 /* find vertex */
2038                 uv_find_nearest_vert(scene, ima, obedit, em, co, penalty, &hit);
2039                 if (hit.efa == NULL) {
2040                         return OPERATOR_CANCELLED;
2041                 }
2042
2043                 /* mark 1 vertex as being hit */
2044                 hitv  = BLI_array_alloca(hitv,  hit.efa->len);
2045                 hituv = BLI_array_alloca(hituv, hit.efa->len);
2046                 copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
2047
2048                 hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
2049                 hituv[hit.lindex] = hit.luv->uv;
2050
2051                 hitlen = hit.efa->len;
2052         }
2053         else if (selectmode == UV_SELECT_EDGE) {
2054                 /* find edge */
2055                 uv_find_nearest_edge(scene, ima, obedit, em, co, &hit);
2056                 if (hit.efa == NULL) {
2057                         return OPERATOR_CANCELLED;
2058                 }
2059
2060                 /* mark 2 edge vertices as being hit */
2061                 hitv  = BLI_array_alloca(hitv,  hit.efa->len);
2062                 hituv = BLI_array_alloca(hituv, hit.efa->len);
2063                 copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF);
2064
2065                 hitv[hit.lindex] = BM_elem_index_get(hit.l->v);
2066                 hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v);
2067                 hituv[hit.lindex] = hit.luv->uv;
2068                 hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv;
2069
2070                 hitlen = hit.efa->len;
2071         }
2072         else if (selectmode == UV_SELECT_FACE) {
2073                 /* find face */
2074                 uv_find_nearest_face(scene, ima, obedit, em, co, &hit);
2075                 if (hit.efa == NULL) {
2076                         return OPERATOR_CANCELLED;
2077                 }
2078                 
2079                 /* make active */
2080                 BM_mesh_active_face_set(em->bm, hit.efa);
2081
2082                 /* mark all face vertices as being hit */
2083
2084                 hitv  = BLI_array_alloca(hitv,  hit.efa->len);
2085                 hituv = BLI_array_alloca(hituv, hit.efa->len);
2086                 BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) {
2087                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2088                         hituv[i] = luv->uv;
2089                         hitv[i] = BM_elem_index_get(l->v);
2090                 }
2091                 
2092                 hitlen = hit.efa->len;
2093         }
2094         else if (selectmode == UV_SELECT_ISLAND) {
2095                 uv_find_nearest_edge(scene, ima, obedit, em, co, &hit);
2096
2097                 if (hit.efa == NULL) {
2098                         return OPERATOR_CANCELLED;
2099                 }
2100
2101                 hitlen = 0;
2102         }
2103         else {
2104                 hitlen = 0;
2105                 return OPERATOR_CANCELLED;
2106         }
2107
2108         /* do selection */
2109         if (loop) {
2110                 flush = uv_select_edgeloop(scene, ima, obedit, em, &hit, limit, extend);
2111         }
2112         else if (selectmode == UV_SELECT_ISLAND) {
2113                 uv_select_linked(scene, ima, obedit, em, limit, &hit, extend, false);
2114         }
2115         else if (extend) {
2116                 if (selectmode == UV_SELECT_VERTEX) {
2117                         /* (de)select uv vertex */
2118                         select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset);
2119                         uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
2120                         flush = 1;
2121                 }
2122                 else if (selectmode == UV_SELECT_EDGE) {
2123                         /* (de)select edge */
2124                         select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset));
2125                         uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset);
2126                         flush = 1;
2127                 }
2128                 else if (selectmode == UV_SELECT_FACE) {
2129                         /* (de)select face */
2130                         select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset));
2131                         uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset);
2132                         flush = -1;
2133                 }
2134
2135                 /* de-selecting an edge may deselect a face too - validate */
2136                 if (sync) {
2137                         if (select == false) {
2138                                 BM_select_history_validate(em->bm);
2139                         }
2140                 }
2141
2142                 /* (de)select sticky uv nodes */
2143                 if (sticky != SI_STICKY_DISABLE) {
2144
2145                         BM_mesh_elem_index_ensure(em->bm, BM_VERT);
2146
2147                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2148                                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
2149                                         continue;
2150
2151                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2152                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2153                                         if (uv_sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
2154                                                 uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
2155                                 }
2156                         }
2157
2158                         flush = select ? 1 : -1;
2159                 }
2160         }
2161         else {
2162                 /* deselect all */
2163                 uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
2164
2165                 if (selectmode == UV_SELECT_VERTEX) {
2166                         /* select vertex */
2167                         uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
2168                         flush = 1;
2169                 }
2170                 else if (selectmode == UV_SELECT_EDGE) {
2171                         /* select edge */
2172                         uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset);
2173                         flush = 1;
2174                 }
2175                 else if (selectmode == UV_SELECT_FACE) {
2176                         /* select face */
2177                         uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset);
2178                 }
2179
2180                 /* select sticky uvs */
2181                 if (sticky != SI_STICKY_DISABLE) {
2182                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2183                                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
2184                                         continue;
2185                                 
2186                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2187                                         if (sticky == SI_STICKY_DISABLE) continue;
2188                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2189
2190                                         if (uv_sticky_select(limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen))
2191                                                 uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset);
2192
2193                                         flush = 1;
2194                                 }
2195                         }
2196                 }
2197         }
2198
2199         if (sync) {
2200                 /* flush for mesh selection */
2201
2202                 /* before bmesh */
2203 #if 0
2204                 if (ts->selectmode != SCE_SELECT_FACE) {
2205                         if (flush == 1) EDBM_select_flush(em);
2206                         else if (flush == -1) EDBM_deselect_flush(em);
2207                 }
2208 #else
2209                 if (flush != 0) {
2210                         if (loop) {
2211                                 /* push vertex -> edge selection */
2212                                 if (select) {
2213                                         EDBM_select_flush(em);
2214                                 }
2215                                 else {
2216                                         EDBM_deselect_flush(em);
2217                                 }
2218                         }
2219                         else {
2220                                 EDBM_selectmode_flush(em);
2221                         }
2222                 }
2223 #endif
2224         }
2225
2226         DEG_id_tag_update(obedit->data, 0);
2227         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2228
2229         return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED;
2230 }
2231
2232 static int uv_select_exec(bContext *C, wmOperator *op)
2233 {
2234         float co[2];
2235         bool extend, loop;
2236
2237         RNA_float_get_array(op->ptr, "location", co);
2238         extend = RNA_boolean_get(op->ptr, "extend");
2239         loop = false;
2240
2241         return uv_mouse_select(C, co, extend, loop);
2242 }
2243
2244 static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2245 {
2246         ARegion *ar = CTX_wm_region(C);
2247         float co[2];
2248
2249         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2250         RNA_float_set_array(op->ptr, "location", co);
2251
2252         return uv_select_exec(C, op);
2253 }
2254
2255 static void UV_OT_select(wmOperatorType *ot)
2256 {
2257         /* identifiers */
2258         ot->name = "Select";
2259         ot->description = "Select UV vertices";
2260         ot->idname = "UV_OT_select";
2261         ot->flag = OPTYPE_UNDO;
2262         
2263         /* api callbacks */
2264         ot->exec = uv_select_exec;
2265         ot->invoke = uv_select_invoke;
2266         ot->poll = ED_operator_uvedit; /* requires space image */;
2267
2268         /* properties */
2269         RNA_def_boolean(ot->srna, "extend", 0,
2270                         "Extend", "Extend selection rather than clearing the existing selection");
2271         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
2272                              "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
2273 }
2274
2275 /* ******************** loop select operator **************** */
2276
2277 static int uv_select_loop_exec(bContext *C, wmOperator *op)
2278 {
2279         float co[2];
2280         bool extend, loop;
2281
2282         RNA_float_get_array(op->ptr, "location", co);
2283         extend = RNA_boolean_get(op->ptr, "extend");
2284         loop = true;
2285
2286         return uv_mouse_select(C, co, extend, loop);
2287 }
2288
2289 static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2290 {
2291         ARegion *ar = CTX_wm_region(C);
2292         float co[2];
2293
2294         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2295         RNA_float_set_array(op->ptr, "location", co);
2296
2297         return uv_select_loop_exec(C, op);
2298 }
2299
2300 static void UV_OT_select_loop(wmOperatorType *ot)
2301 {
2302         /* identifiers */
2303         ot->name = "Loop Select";
2304         ot->description = "Select a loop of connected UV vertices";
2305         ot->idname = "UV_OT_select_loop";
2306         ot->flag = OPTYPE_UNDO;
2307         
2308         /* api callbacks */
2309         ot->exec = uv_select_loop_exec;
2310         ot->invoke = uv_select_loop_invoke;
2311         ot->poll = ED_operator_uvedit; /* requires space image */;
2312
2313         /* properties */
2314         RNA_def_boolean(ot->srna, "extend", 0,
2315                         "Extend", "Extend selection rather than clearing the existing selection");
2316         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
2317                              "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
2318 }
2319
2320 /* ******************** linked select operator **************** */
2321
2322 static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, int pick)
2323 {
2324         SpaceImage *sima = CTX_wm_space_image(C);
2325         Scene *scene = CTX_data_scene(C);
2326         ToolSettings *ts = scene->toolsettings;
2327         Object *obedit = CTX_data_edit_object(C);
2328         Image *ima = CTX_data_edit_image(C);
2329         BMEditMesh *em = BKE_editmesh_from_object(obedit);
2330         float limit[2];
2331         int extend;
2332         bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE);
2333
2334         NearestHit hit, *hit_p = NULL;
2335
2336         if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) {
2337                 BKE_report(op->reports, RPT_ERROR, "Select linked only works in face select mode when sync selection is enabled");
2338                 return OPERATOR_CANCELLED;
2339         }
2340
2341         extend = RNA_boolean_get(op->ptr, "extend");
2342         uvedit_pixel_to_float(sima, limit, 0.05f);
2343
2344         if (pick) {
2345                 float co[2];
2346
2347                 if (event) {
2348                         /* invoke */
2349                         ARegion *ar = CTX_wm_region(C);
2350
2351                         UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
2352                         RNA_float_set_array(op->ptr, "location", co);
2353                 }
2354                 else {
2355                         /* exec */
2356                         RNA_float_get_array(op->ptr, "location", co);
2357                 }
2358
2359                 uv_find_nearest_edge(scene, ima, obedit, em, co, &hit);
2360                 hit_p = &hit;
2361         }
2362
2363         uv_select_linked(scene, ima, obedit, em, limit, hit_p, extend, select_faces);
2364
2365         DEG_id_tag_update(obedit->data, 0);
2366         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2367
2368         return OPERATOR_FINISHED;
2369 }
2370
2371 static int uv_select_linked_exec(bContext *C, wmOperator *op)
2372 {
2373         return uv_select_linked_internal(C, op, NULL, 0);
2374 }
2375
2376 static void UV_OT_select_linked(wmOperatorType *ot)
2377 {
2378         /* identifiers */
2379         ot->name = "Select Linked";
2380         ot->description = "Select all UV vertices linked to the active UV map";
2381         ot->idname = "UV_OT_select_linked";
2382         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2383         
2384         /* api callbacks */
2385         ot->exec = uv_select_linked_exec;
2386         ot->poll = ED_operator_uvedit;    /* requires space image */
2387
2388         /* properties */
2389         RNA_def_boolean(ot->srna, "extend", 0,
2390                         "Extend", "Extend selection rather than clearing the existing selection");
2391 }
2392
2393 static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
2394 {
2395         return uv_select_linked_internal(C, op, event, 1);
2396 }
2397
2398 static int uv_select_linked_pick_exec(bContext *C, wmOperator *op)
2399 {
2400         return uv_select_linked_internal(C, op, NULL, 1);
2401 }
2402
2403 static void UV_OT_select_linked_pick(wmOperatorType *ot)
2404 {
2405         /* identifiers */
2406         ot->name = "Select Linked Pick";
2407         ot->description = "Select all UV vertices linked under the mouse";
2408         ot->idname = "UV_OT_select_linked_pick";
2409         ot->flag = OPTYPE_UNDO;
2410
2411         /* api callbacks */
2412         ot->invoke = uv_select_linked_pick_invoke;
2413         ot->exec = uv_select_linked_pick_exec;
2414         ot->poll = ED_operator_uvedit; /* requires space image */;
2415
2416         /* properties */
2417         RNA_def_boolean(ot->srna, "extend", 0,
2418                         "Extend", "Extend selection rather than clearing the existing selection");
2419
2420         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
2421                              "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
2422 }
2423
2424 /* note: this is based on similar use case to MESH_OT_split(), which has a similar effect
2425  * but in this case they are not joined to begin with (only having the behavior of being joined)
2426  * so its best to call this uv_select_split() instead of just split(), but assigned to the same key
2427  * as MESH_OT_split - Campbell */
2428 static int uv_select_split_exec(bContext *C, wmOperator *op)
2429 {
2430         Scene *scene = CTX_data_scene(C);
2431         ToolSettings *ts = scene->toolsettings;
2432         Image *ima = CTX_data_edit_image(C);
2433         Object *obedit = CTX_data_edit_object(C);
2434         BMesh *bm = BKE_editmesh_from_object(obedit)->bm;
2435
2436         BMFace *efa;
2437         BMLoop *l;
2438         BMIter iter, liter;
2439         MLoopUV *luv;
2440         bool changed = false;
2441
2442         const int cd_loop_uv_offset  = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
2443
2444         if (ts->uv_flag & UV_SYNC_SELECTION) {
2445                 BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled");
2446                 return OPERATOR_CANCELLED;
2447         }
2448
2449
2450
2451         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2452                 bool is_sel = false;
2453                 bool is_unsel = false;
2454
2455                 if (!uvedit_face_visible_test(scene, obedit, ima, efa))
2456                         continue;
2457
2458                 /* are we all selected? */
2459                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2460                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2461
2462                         if (luv->flag & MLOOPUV_VERTSEL) {
2463                                 is_sel = true;
2464                         }
2465                         else {
2466                                 is_unsel = true;
2467                         }
2468
2469                         /* we have mixed selection, bail out */
2470                         if (is_sel && is_unsel) {
2471                                 break;
2472                         }
2473                 }
2474
2475                 if (is_sel && is_unsel) {
2476                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2477                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2478                                 luv->flag &= ~MLOOPUV_VERTSEL;
2479                         }
2480
2481                         changed = true;
2482                 }
2483         }
2484
2485         if (changed) {
2486                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
2487                 return OPERATOR_FINISHED;
2488         }
2489         else {
2490                 return OPERATOR_CANCELLED;
2491         }
2492 }
2493
2494
2495 static void UV_OT_select_split(wmOperatorType *ot)
2496 {
2497         /* identifiers */
2498         ot->name = "Select Split";
2499         ot->description = "Select only entirely selected faces";
2500         ot->idname = "UV_OT_select_split";
2501         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2502
2503         /* api callbacks */
2504         ot->exec = uv_select_split_exec;
2505         ot->poll = ED_operator_uvedit; /* requires space image */;
2506 }
2507
2508 static void uv_select_sync_flush(ToolSettings *ts, BMEditMesh *em, const short select)
2509 {
2510         /* bmesh API handles flushing but not on de-select */
2511         if (ts->uv_flag & UV_SYNC_SELECTION) {
2512                 if (ts->selectmode != SCE_SELECT_FACE) {
2513                         if (select == false) {
2514                                 EDBM_deselect_flush(em);
2515                         }
2516                         else {
2517                                 EDBM_select_flush(em);
2518                         }
2519                 }
2520
2521                 if (select == false) {
2522                         BM_select_history_validate(em->bm);
2523                 }
2524         }
2525 }
2526
2527
2528
2529 /* -------------------------------------------------------------------- */
2530 /* Utility functions to flush the uv-selection from tags */
2531
2532 /**
2533  * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face
2534  */
2535 static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, BMEditMesh *em, UvVertMap *vmap,
2536                                                          const unsigned int efa_index, BMLoop *l,
2537                                                          const bool select, const int cd_loop_uv_offset)
2538 {
2539         UvMapVert *start_vlist = NULL, *vlist_iter;
2540         BMFace *efa_vlist;
2541
2542         uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
2543
2544         vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v));
2545
2546         while (vlist_iter) {
2547                 if (vlist_iter->separate)
2548                         start_vlist = vlist_iter;
2549
2550                 if (efa_index == vlist_iter->f)
2551                         break;
2552
2553                 vlist_iter = vlist_iter->next;
2554         }
2555
2556         vlist_iter = start_vlist;
2557         while (vlist_iter) {
2558
2559                 if (vlist_iter != start_vlist && vlist_iter->separate)
2560                         break;
2561
2562                 if (efa_index != vlist_iter->f) {
2563                         BMLoop *l_other;
2564                         efa_vlist = BM_face_at_index(em->bm, vlist_iter->f);
2565                         /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */
2566
2567                         l_other = BM_iter_at_index(em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->tfindex);
2568
2569                         uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset);
2570                 }
2571                 vlist_iter = vlist_iter->next;
2572         }
2573 }
2574
2575 /**
2576  * Flush the selection from face tags based on sticky and selection modes.
2577  *
2578  * needed because settings the selection a face is done in a number of places but it also needs to respect
2579  * the sticky modes for the UV verts, so dealing with the sticky modes is best done in a separate function.
2580  *
2581  * \note! This function is very similar to #uv_select_flush_from_tag_loop, be sure to update both upon changing.
2582  */
2583 static void uv_select_flush_from_tag_face(SpaceImage *sima, Scene *scene, Object *obedit, const bool select)
2584 {
2585         /* Selecting UV Faces with some modes requires us to change 
2586          * the selection in other faces (depending on the sticky mode).
2587          * 
2588          * This only needs to be done when the Mesh is not used for
2589          * selection (so for sticky modes, vertex or location based). */
2590         
2591         ToolSettings *ts = scene->toolsettings;
2592         BMEditMesh *em = BKE_editmesh_from_object(obedit);
2593         BMFace *efa;
2594         BMLoop *l;
2595         BMIter iter, liter;
2596         const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2597         
2598         if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
2599                 /* Tag all verts as untouched, then touch the ones that have a face center
2600                  * in the loop and select all MLoopUV's that use a touched vert. */
2601                 BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
2602
2603                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2604                         if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2605                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2606                                         BM_elem_flag_enable(l->v, BM_ELEM_TAG);
2607                                 }
2608                         }
2609                 }
2610
2611                 /* now select tagged verts */
2612                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2613                         /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
2614
2615                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2616                                 if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
2617                                         uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
2618                                 }
2619                         }
2620                 }
2621         }
2622         else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
2623                 struct UvVertMap *vmap;
2624                 float limit[2];
2625                 unsigned int efa_index;
2626                 
2627                 uvedit_pixel_to_float(sima, limit, 0.05);
2628                 
2629                 BM_mesh_elem_table_ensure(em->bm, BM_FACE);
2630                 vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
2631                 if (vmap == NULL) {
2632                         return;
2633                 }
2634                 
2635                 BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
2636                         if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2637                                 /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
2638                                 
2639                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2640                                         uv_select_flush_from_tag_sticky_loc_internal(scene, em, vmap, efa_index, l,
2641                                                                                      select, cd_loop_uv_offset);
2642                                 }
2643                         }
2644                 }
2645                 BM_uv_vert_map_free(vmap);
2646                 
2647         }
2648         else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
2649                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2650                         if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
2651                                 uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset);
2652                         }
2653                 }
2654         }
2655 }
2656
2657
2658
2659 /**
2660  * Flush the selection from loop tags based on sticky and selection modes.
2661  *
2662  * needed because settings the selection a face is done in a number of places but it also needs to respect
2663  * the sticky modes for the UV verts, so dealing with the sticky modes is best done in a separate function.
2664  *
2665  * \note! This function is very similar to #uv_select_flush_from_tag_loop, be sure to update both upon changing.
2666  */
2667 static void uv_select_flush_from_tag_loop(SpaceImage *sima, Scene *scene, Object *obedit, const bool select)
2668 {
2669         /* Selecting UV Loops with some modes requires us to change
2670          * the selection in other faces (depending on the sticky mode).
2671          *
2672          * This only needs to be done when the Mesh is not used for
2673          * selection (so for sticky modes, vertex or location based). */
2674
2675         ToolSettings *ts = scene->toolsettings;
2676         BMEditMesh *em = BKE_editmesh_from_object(obedit);
2677         BMFace *efa;
2678         BMLoop *l;
2679         BMIter iter, liter;
2680
2681         const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2682
2683
2684         if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) {
2685                 /* Tag all verts as untouched, then touch the ones that have a face center
2686                  * in the loop and select all MLoopUV's that use a touched vert. */
2687                 BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
2688
2689                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2690                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2691                                 if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
2692                                         BM_elem_flag_enable(l->v, BM_ELEM_TAG);
2693                                 }
2694                         }
2695                 }
2696
2697                 /* now select tagged verts */
2698                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2699                         /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
2700
2701                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2702                                 if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
2703                                         uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
2704                                 }
2705                         }
2706                 }
2707         }
2708         else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) {
2709                 struct UvVertMap *vmap;
2710                 float limit[2];
2711                 unsigned int efa_index;
2712
2713                 uvedit_pixel_to_float(sima, limit, 0.05);
2714
2715                 BM_mesh_elem_table_ensure(em->bm, BM_FACE);
2716                 vmap = BM_uv_vert_map_create(em->bm, limit, false, false);
2717                 if (vmap == NULL) {
2718                         return;
2719                 }
2720
2721                 BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) {
2722                         /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */
2723
2724                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2725                                 if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
2726                                         uv_select_flush_from_tag_sticky_loc_internal(scene, em, vmap, efa_index, l,
2727                                                                                      select, cd_loop_uv_offset);
2728                                 }
2729                         }
2730                 }
2731                 BM_uv_vert_map_free(vmap);
2732
2733         }
2734         else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
2735                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2736                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2737                                 if (BM_elem_flag_test(l, BM_ELEM_TAG)) {
2738                                         uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
2739                                 }
2740                         }
2741                 }
2742         }
2743 }
2744
2745 /* ******************** border select operator **************** */
2746
2747 static int uv_border_select_exec(bContext *C, wmOperator *op)
2748 {
2749         SpaceImage *sima = CTX_wm_space_image(C);
2750         Scene *scene = CTX_data_scene(C);
2751         ToolSettings *ts = scene->toolsettings;
2752         Object *obedit = CTX_data_edit_object(C);
2753         Image *ima = CTX_data_edit_image(C);
2754         ARegion *ar = CTX_wm_region(C);
2755         BMEditMesh *em = BKE_editmesh_from_object(obedit);
2756         BMFace *efa;
2757         BMLoop *l;
2758         BMIter iter, liter;
2759         MLoopUV *luv;
2760         rctf rectf;
2761         bool changed, pinned, select, extend;
2762         const bool use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ?
2763                                     (ts->selectmode == SCE_SELECT_FACE) :
2764                                     (ts->uv_selectmode == UV_SELECT_FACE);
2765
2766         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2767
2768         /* get rectangle from operator */
2769         WM_operator_properties_border_to_rctf(op, &rectf);
2770         UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf);
2771
2772         /* figure out what to select/deselect */
2773         select = !RNA_boolean_get(op->ptr, "deselect");
2774         extend = RNA_boolean_get(op->ptr, "extend");
2775         pinned = RNA_boolean_get(op->ptr, "pinned");
2776
2777         if (!extend)
2778                 uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
2779
2780         /* do actual selection */
2781         if (use_face_center && !pinned) {
2782                 /* handle face selection mode */
2783                 float cent[2];
2784
2785                 changed = false;
2786
2787                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2788                         /* assume not touched */
2789                         BM_elem_flag_disable(efa, BM_ELEM_TAG);
2790
2791                         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
2792                                 uv_poly_center(efa, cent, cd_loop_uv_offset);
2793                                 if (BLI_rctf_isect_pt_v(&rectf, cent)) {
2794                                         BM_elem_flag_enable(efa, BM_ELEM_TAG);
2795                                         changed = true;
2796                                 }
2797                         }
2798                 }
2799
2800                 /* (de)selects all tagged faces and deals with sticky modes */
2801                 if (changed) {
2802                         uv_select_flush_from_tag_face(sima, scene, obedit, select);
2803                 }
2804         }
2805         else {
2806                 /* other selection modes */
2807                 changed = true;
2808                 BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
2809
2810                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2811                         if (!uvedit_face_visible_test(scene, obedit, ima, efa))
2812                                 continue;
2813                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2814                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2815
2816                                 if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) {
2817
2818                                         /* UV_SYNC_SELECTION - can't do pinned selection */
2819                                         if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
2820                                                 uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
2821                                                 BM_elem_flag_enable(l->v, BM_ELEM_TAG);
2822                                         }
2823                                 }
2824                                 else if (pinned) {
2825                                         if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) {
2826                                                 uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
2827                                                 BM_elem_flag_enable(l->v, BM_ELEM_TAG);
2828                                         }
2829                                 }
2830                         }
2831                 }
2832
2833                 if (sima->sticky == SI_STICKY_VERTEX) {
2834                         uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
2835                 }
2836         }
2837
2838         if (changed) {
2839                 uv_select_sync_flush(ts, em, select);
2840
2841                 if (ts->uv_flag & UV_SYNC_SELECTION) {
2842                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2843                 }
2844                 
2845                 return OPERATOR_FINISHED;
2846         }
2847
2848         return OPERATOR_CANCELLED;
2849
2850
2851 static void UV_OT_select_border(wmOperatorType *ot)
2852 {
2853         /* identifiers */
2854         ot->name = "Border Select";
2855         ot->description = "Select UV vertices using border selection";
2856         ot->idname = "UV_OT_select_border";
2857         
2858         /* api callbacks */
2859         ot->invoke = WM_gesture_border_invoke;
2860         ot->exec = uv_border_select_exec;
2861         ot->modal = WM_gesture_border_modal;
2862         ot->poll = ED_operator_uvedit_space_image; /* requires space image */;
2863         ot->cancel = WM_gesture_border_cancel;
2864         
2865         /* flags */
2866         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2867         
2868         /* properties */
2869         RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
2870
2871         WM_operator_properties_gesture_border_select(ot);
2872 }
2873
2874 /* ******************** circle select operator **************** */
2875
2876 static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2])
2877 {
2878         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
2879         float x, y;
2880         x = (uv[0] - offset[0]) * ellipse[0];
2881         y = (uv[1] - offset[1]) * ellipse[1];
2882         return ((x * x + y * y) < 1.0f);
2883 }
2884
2885 static int uv_circle_select_exec(bContext *C, wmOperator *op)
2886 {
2887         SpaceImage *sima = CTX_wm_space_image(C);
2888         Scene *scene = CTX_data_scene(C);
2889         ToolSettings *ts = scene->toolsettings;
2890         Object *obedit = CTX_data_edit_object(C);
2891         BMEditMesh *em = BKE_editmesh_from_object(obedit);
2892         ARegion *ar = CTX_wm_region(C);
2893         BMFace *efa;
2894         BMLoop *l;
2895         BMIter iter, liter;
2896         MLoopUV *luv;
2897         int x, y, radius, width, height;
2898         float zoomx, zoomy, offset[2], ellipse[2];
2899         const bool select = !RNA_boolean_get(op->ptr, "deselect");
2900         bool changed = false;
2901         const bool use_face_center = (ts->uv_flag & UV_SYNC_SELECTION) ?
2902                                      (ts->selectmode == SCE_SELECT_FACE) :
2903                                      (ts->uv_selectmode == UV_SELECT_FACE);
2904
2905         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2906
2907         /* get operator properties */
2908         x = RNA_int_get(op->ptr, "x");
2909         y = RNA_int_get(op->ptr, "y");
2910         radius = RNA_int_get(op->ptr, "radius");
2911
2912         /* compute ellipse size and location, not a circle since we deal
2913          * with non square image. ellipse is normalized, r = 1.0. */
2914         ED_space_image_get_size(sima, &width, &height);
2915         ED_space_image_get_zoom(sima, ar, &zoomx, &zoomy);
2916
2917         ellipse[0] = width * zoomx / radius;
2918         ellipse[1] = height * zoomy / radius;
2919
2920         UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
2921         
2922         /* do selection */
2923         if (use_face_center) {
2924                 changed = false;
2925                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2926                         BM_elem_flag_disable(efa, BM_ELEM_TAG);
2927                         /* assume not touched */
2928                         if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
2929                                 float cent[2];
2930                                 uv_poly_center(efa, cent, cd_loop_uv_offset);
2931                                 if (uv_inside_circle(cent, offset, ellipse)) {
2932                                         BM_elem_flag_enable(efa, BM_ELEM_TAG);
2933                                         changed = true;
2934                                 }
2935                         }
2936                 }
2937
2938                 /* (de)selects all tagged faces and deals with sticky modes */
2939                 if (changed) {
2940                         uv_select_flush_from_tag_face(sima, scene, obedit, select);
2941                 }
2942         }
2943         else {
2944                 BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
2945
2946                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2947                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2948                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2949                                 if (uv_inside_circle(luv->uv, offset, ellipse)) {
2950                                         changed = true;
2951                                         uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
2952                                         BM_elem_flag_enable(l->v, BM_ELEM_TAG);
2953                                 }
2954                         }
2955                 }
2956
2957                 if (sima->sticky == SI_STICKY_VERTEX) {
2958                         uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
2959                 }
2960         }
2961
2962         if (changed) {
2963                 uv_select_sync_flush(ts, em, select);
2964
2965                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
2966         }
2967
2968         return OPERATOR_FINISHED;
2969 }
2970
2971 static void UV_OT_circle_select(wmOperatorType *ot)
2972 {
2973         /* identifiers */
2974         ot->name = "Circle Select";
2975         ot->description = "Select UV vertices using circle selection";
2976         ot->idname = "UV_OT_circle_select";
2977         
2978         /* api callbacks */
2979         ot->invoke = WM_gesture_circle_invoke;
2980         ot->modal = WM_gesture_circle_modal;
2981         ot->exec = uv_circle_select_exec;
2982         ot->poll = ED_operator_uvedit_space_image; /* requires space image */;
2983         ot->cancel = WM_gesture_circle_cancel;
2984         
2985         /* flags */
2986         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2987
2988         /* properties */
2989         WM_operator_properties_gesture_circle_select(ot);
2990 }
2991
2992
2993 /* ******************** lasso select operator **************** */
2994
2995 static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves,
2996                                     const bool select, const bool extend)
2997 {
2998         SpaceImage *sima = CTX_wm_space_image(C);
2999         Image *ima = CTX_data_edit_image(C);
3000         ARegion *ar = CTX_wm_region(C);
3001         Object *obedit = CTX_data_edit_object(C);
3002         Scene *scene = CTX_data_scene(C);
3003         ToolSettings *ts = scene->toolsettings;
3004         BMEditMesh *em = BKE_editmesh_from_object(obedit);
3005         const bool use_face_center = (
3006                 (ts->uv_flag & UV_SYNC_SELECTION) ?
3007                 (ts->selectmode == SCE_SELECT_FACE) :
3008                 (ts->uv_selectmode == UV_SELECT_FACE));
3009
3010         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
3011
3012         BMIter iter, liter;
3013
3014         BMFace *efa;
3015         BMLoop *l;
3016         int screen_uv[2];
3017         bool changed = false;
3018         rcti rect;
3019
3020         BLI_lasso_boundbox(&rect, mcords, moves);
3021
3022         if (!extend && select) {
3023                 uv_select_all_perform(scene, ima, obedit, em, SEL_DESELECT);
3024         }
3025
3026         if (use_face_center) { /* Face Center Sel */
3027                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3028                         BM_elem_flag_disable(efa, BM_ELEM_TAG);
3029                         /* assume not touched */
3030                         if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
3031                                 float cent[2];
3032                                 uv_poly_center(efa, cent, cd_loop_uv_offset);
3033
3034                                 if (UI_view2d_view_to_region_clip(&ar->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) &&
3035                                     BLI_rcti_isect_pt_v(&rect, screen_uv) &&
3036                                     BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
3037                                 {
3038                                         BM_elem_flag_enable(efa, BM_ELEM_TAG);
3039                                         changed = true;
3040                                 }
3041                         }
3042                 }
3043
3044                 /* (de)selects all tagged faces and deals with sticky modes */
3045                 if (changed) {
3046                         uv_select_flush_from_tag_face(sima, scene, obedit, select);
3047                 }
3048         }
3049         else { /* Vert Sel */
3050                 BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false);
3051
3052                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
3053                         if (uvedit_face_visible_test(scene, obedit, ima, efa)) {
3054                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
3055                                         if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) {
3056                                                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
3057                                                 if (UI_view2d_view_to_region_clip(&ar->v2d,
3058                                                                                   luv->uv[0], luv->uv[1],
3059                                                                                   &screen_uv[0], &screen_uv[1]) &&
3060                                                     BLI_rcti_isect_pt_v(&rect, screen_uv) &&
3061                                                     BLI_lasso_is_point_inside(mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED))
3062                                                 {
3063                                                         uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset);
3064                                                         changed = true;
3065                                                         BM_elem_flag_enable(l->v, BM_ELEM_TAG);
3066                                                 }
3067                                         }
3068                                 }
3069                         }
3070                 }
3071
3072                 if (sima->sticky == SI_STICKY_VERTEX) {
3073                         uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset);
3074                 }
3075         }
3076
3077         if (changed) {
3078                 uv_select_sync_flush(scene->toolsettings, em, select);
3079
3080                 if (ts->uv_flag & UV_SYNC_SELECTION) {
3081                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data);
3082                 }
3083         }
3084
3085         return changed;
3086 }
3087
3088 static int uv_lasso_select_exec(bContext *C, wmOperator *op)
3089 {
3090         int mcords_tot;
3091         const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
3092
3093         if (mcords) {
3094                 bool select, extend;
3095                 bool changed;
3096
3097                 select = !RNA_boolean_get(op->ptr, "deselect");
3098                 extend = RNA_boolean_get(op->ptr, "extend");
3099                 changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, select, extend);
3100
3101                 MEM_freeN((void *)mcords);
3102
3103                 return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
3104         }
3105
3106         return OPERATOR_PASS_THROUGH;
3107 }