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