Blender  V2.93
uvedit_ops.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "DNA_image_types.h"
31 #include "DNA_material_types.h"
32 #include "DNA_mesh_types.h"
33 #include "DNA_meshdata_types.h"
34 #include "DNA_node_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_scene_types.h"
37 #include "DNA_space_types.h"
38 
39 #include "BLI_array.h"
40 #include "BLI_kdtree.h"
41 #include "BLI_math.h"
42 #include "BLI_utildefines.h"
43 
44 #include "BLT_translation.h"
45 
46 #include "BKE_context.h"
47 #include "BKE_customdata.h"
48 #include "BKE_editmesh.h"
49 #include "BKE_layer.h"
50 #include "BKE_main.h"
51 #include "BKE_material.h"
52 #include "BKE_mesh_mapping.h"
53 #include "BKE_node.h"
54 
55 #include "DEG_depsgraph.h"
56 
57 #include "ED_image.h"
58 #include "ED_mesh.h"
59 #include "ED_node.h"
60 #include "ED_screen.h"
61 #include "ED_uvedit.h"
62 
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65 
66 #include "WM_api.h"
67 #include "WM_message.h"
68 #include "WM_types.h"
69 
70 #include "UI_interface.h"
71 #include "UI_resources.h"
72 #include "UI_view2d.h"
73 
74 #include "uvedit_intern.h"
75 
76 /* -------------------------------------------------------------------- */
80 bool ED_uvedit_test(Object *obedit)
81 {
82  BMEditMesh *em;
83  int ret;
84 
85  if (!obedit) {
86  return 0;
87  }
88 
89  if (obedit->type != OB_MESH) {
90  return 0;
91  }
92 
93  em = BKE_editmesh_from_object(obedit);
94  ret = EDBM_uv_check(em);
95 
96  return ret;
97 }
98 
100 {
102 
103  if (ob && ob->type == OB_MESH) {
104  Mesh *me = ob->data;
105 
106  if (CustomData_get_layer(&me->ldata, CD_MLOOPUV) != NULL) {
107  return 1;
108  }
109  }
110 
111  return 0;
112 }
113 
116 /* -------------------------------------------------------------------- */
121 {
123 }
124 
126  int mat_nr,
127  Image **r_ima,
128  ImageUser **r_iuser,
129  bNode **r_node,
130  bNodeTree **r_ntree)
131 {
132  Material *ma = BKE_object_material_get(ob, mat_nr);
133  bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
135 
136  if (node && is_image_texture_node(node)) {
137  if (r_ima) {
138  *r_ima = (Image *)node->id;
139  }
140  if (r_iuser) {
141  if (node->type == SH_NODE_TEX_IMAGE) {
142  *r_iuser = &((NodeTexImage *)node->storage)->iuser;
143  }
144  else if (node->type == SH_NODE_TEX_ENVIRONMENT) {
145  *r_iuser = &((NodeTexEnvironment *)node->storage)->iuser;
146  }
147  else {
148  *r_iuser = NULL;
149  }
150  }
151  if (r_node) {
152  *r_node = node;
153  }
154  if (r_ntree) {
155  *r_ntree = ntree;
156  }
157  return true;
158  }
159 
160  if (r_ima) {
161  *r_ima = NULL;
162  }
163  if (r_iuser) {
164  *r_iuser = NULL;
165  }
166  if (r_node) {
167  *r_node = node;
168  }
169  if (r_ntree) {
170  *r_ntree = ntree;
171  }
172 
173  return false;
174 }
175 
176 void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
177 {
178  Material *ma = BKE_object_material_get(ob, mat_nr);
179  bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
180 
181  if (node && is_image_texture_node(node)) {
182  node->id = &ima->id;
184  }
185 }
186 
189 /* -------------------------------------------------------------------- */
194 {
195  if (sima && (sima->flag & SI_LIVE_UNWRAP)) {
199  }
200 }
201 
204 /* -------------------------------------------------------------------- */
208 void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
209 {
210  int i;
211  for (i = 0; i < len; i++) {
212  uv[i][0] = uv_orig[i][0] * aspx;
213  uv[i][1] = uv_orig[i][1] * aspy;
214  }
215 }
216 
218  const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2])
219 {
220  bool changed = false;
221  INIT_MINMAX2(r_min, r_max);
222 
223  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
224  Object *obedit = objects_edit[ob_index];
225 
226  BMEditMesh *em = BKE_editmesh_from_object(obedit);
227  BMFace *efa;
228  BMLoop *l;
229  BMIter iter, liter;
230  MLoopUV *luv;
231 
232  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
233 
234  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
235  if (!uvedit_face_visible_test(scene, efa)) {
236  continue;
237  }
238 
239  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
240  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
241  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
242  minmax_v2v2_v2(r_min, r_max, luv->uv);
243  changed = true;
244  }
245  }
246  }
247  }
248  return changed;
249 }
250 
251 bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2])
252 {
253  return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max);
254 }
255 
256 /* Be careful when using this, it bypasses all synchronization options */
258 {
259  BMFace *efa;
260  BMLoop *l;
261  BMIter iter, liter;
262  MLoopUV *luv;
263 
264  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
265 
266  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
267  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
268  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
269  luv->flag |= MLOOPUV_VERTSEL;
270  }
271  }
272 }
273 
274 static bool ED_uvedit_median_multi(const Scene *scene,
275  Object **objects_edit,
276  uint objects_len,
277  float co[2])
278 {
279  uint sel = 0;
280  zero_v2(co);
281 
282  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
283  Object *obedit = objects_edit[ob_index];
284 
285  BMEditMesh *em = BKE_editmesh_from_object(obedit);
286  BMFace *efa;
287  BMLoop *l;
288  BMIter iter, liter;
289  MLoopUV *luv;
290 
291  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
292 
293  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
294  if (!uvedit_face_visible_test(scene, efa)) {
295  continue;
296  }
297 
298  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
299  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
300  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
301  add_v2_v2(co, luv->uv);
302  sel++;
303  }
304  }
305  }
306  }
307 
308  mul_v2_fl(co, 1.0f / (float)sel);
309 
310  return (sel != 0);
311 }
312 
314  const Scene *scene, Object **objects_edit, uint objects_len, float cent[2], char mode)
315 {
316  bool changed = false;
317 
318  if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
319  float min[2], max[2];
320  if (ED_uvedit_minmax_multi(scene, objects_edit, objects_len, min, max)) {
321  mid_v2_v2v2(cent, min, max);
322  changed = true;
323  }
324  }
325  else {
326  if (ED_uvedit_median_multi(scene, objects_edit, objects_len, cent)) {
327  changed = true;
328  }
329  }
330 
331  return changed;
332 }
333 
335  Scene *scene,
336  ViewLayer *view_layer,
337  float r_center[2],
338  char mode,
339  bool *r_has_select)
340 {
341  bool changed = false;
342  switch (mode) {
343  case V3D_AROUND_CURSOR: {
344  copy_v2_v2(r_center, sima->cursor);
345  changed = true;
346  if (r_has_select != NULL) {
347  uint objects_len = 0;
349  view_layer, ((View3D *)NULL), &objects_len);
350  *r_has_select = uvedit_select_is_any_selected_multi(scene, objects, objects_len);
351  MEM_freeN(objects);
352  }
353  break;
354  }
355  default: {
356  uint objects_len = 0;
358  view_layer, ((View3D *)NULL), &objects_len);
359  changed = ED_uvedit_center_multi(scene, objects, objects_len, r_center, mode);
360  MEM_freeN(objects);
361  if (r_has_select != NULL) {
362  *r_has_select = changed;
363  }
364  break;
365  }
366  }
367  return changed;
368 }
369 
371  SpaceImage *sima, Scene *scene, ViewLayer *view_layer, float r_center[2], char mode)
372 {
373  return ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, mode, NULL);
374 }
375 
378 /* -------------------------------------------------------------------- */
382 typedef enum eUVWeldAlign {
391 
393 {
395  ViewLayer *view_layer = CTX_data_view_layer(C);
397  const ToolSettings *ts = scene->toolsettings;
398  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
399  float cent[2], min[2], max[2];
400 
401  INIT_MINMAX2(min, max);
402 
403  uint objects_len = 0;
405  view_layer, ((View3D *)NULL), &objects_len);
406 
407  if (tool == UV_ALIGN_AUTO) {
408  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
409  Object *obedit = objects[ob_index];
410  BMEditMesh *em = BKE_editmesh_from_object(obedit);
411 
412  if (synced_selection && (em->bm->totvertsel == 0)) {
413  continue;
414  }
415 
416  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
417 
418  BMIter iter, liter;
419  BMFace *efa;
420  BMLoop *l;
421 
422  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
423  if (!uvedit_face_visible_test(scene, efa)) {
424  continue;
425  }
426 
427  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
428  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
429  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
430  minmax_v2v2_v2(min, max, luv->uv);
431  }
432  }
433  }
434  }
435  tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X;
436  }
437 
438  ED_uvedit_center_multi(scene, objects, objects_len, cent, 0);
439 
440  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
441  Object *obedit = objects[ob_index];
442  BMEditMesh *em = BKE_editmesh_from_object(obedit);
443  bool changed = false;
444 
445  if (synced_selection && (em->bm->totvertsel == 0)) {
446  continue;
447  }
448 
449  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
450 
451  if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
452  BMIter iter, liter;
453  BMFace *efa;
454  BMLoop *l;
455 
456  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
457  if (!uvedit_face_visible_test(scene, efa)) {
458  continue;
459  }
460 
461  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
462  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
463  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
464  luv->uv[0] = cent[0];
465  changed = true;
466  }
467  }
468  }
469  }
470 
471  if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
472  BMIter iter, liter;
473  BMFace *efa;
474  BMLoop *l;
475 
476  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
477  if (!uvedit_face_visible_test(scene, efa)) {
478  continue;
479  }
480 
481  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
482  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
483  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
484  luv->uv[1] = cent[1];
485  changed = true;
486  }
487  }
488  }
489  }
490 
492  BMEdge *eed;
493  BMLoop *l;
494  BMVert *eve;
495  BMVert *eve_start;
496  BMIter iter, liter, eiter;
497 
498  /* clear tag */
500 
501  /* tag verts with a selected UV */
502  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
503  BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) {
504  if (!uvedit_face_visible_test(scene, l->f)) {
505  continue;
506  }
507 
508  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
510  break;
511  }
512  }
513  }
514 
515  /* flush vertex tags to edges */
516  BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
518  eed,
519  BM_ELEM_TAG,
521  }
522 
523  /* find a vertex with only one tagged edge */
524  eve_start = NULL;
525  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
526  int tot_eed_tag = 0;
527  BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
528  if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
529  tot_eed_tag++;
530  }
531  }
532 
533  if (tot_eed_tag == 1) {
534  eve_start = eve;
535  break;
536  }
537  }
538 
539  if (eve_start) {
540  BMVert **eve_line = NULL;
541  BMVert *eve_next = NULL;
542  BLI_array_declare(eve_line);
543  int i;
544 
545  eve = eve_start;
546 
547  /* walk over edges, building an array of verts in a line */
548  while (eve) {
549  BLI_array_append(eve_line, eve);
550  /* don't touch again */
552 
553  eve_next = NULL;
554 
555  /* find next eve */
556  BM_ITER_ELEM (eed, &eiter, eve, BM_EDGES_OF_VERT) {
557  if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
558  BMVert *eve_other = BM_edge_other_vert(eed, eve);
559  if (BM_elem_flag_test(eve_other, BM_ELEM_TAG)) {
560  /* this is a tagged vert we didn't walk over yet, step onto it */
561  eve_next = eve_other;
562  break;
563  }
564  }
565  }
566 
567  eve = eve_next;
568  }
569 
570  /* now we have all verts, make into a line */
571  if (BLI_array_len(eve_line) > 2) {
572 
573  /* we know the returns from these must be valid */
574  const float *uv_start = uvedit_first_selected_uv_from_vertex(
575  scene, eve_line[0], cd_loop_uv_offset);
576  const float *uv_end = uvedit_first_selected_uv_from_vertex(
577  scene, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset);
578  /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */
579  float a = 0.0f;
580  eUVWeldAlign tool_local = tool;
581 
582  if (tool_local == UV_STRAIGHTEN_X) {
583  if (uv_start[1] == uv_end[1]) {
584  tool_local = UV_STRAIGHTEN;
585  }
586  else {
587  a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
588  }
589  }
590  else if (tool_local == UV_STRAIGHTEN_Y) {
591  if (uv_start[0] == uv_end[0]) {
592  tool_local = UV_STRAIGHTEN;
593  }
594  else {
595  a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
596  }
597  }
598 
599  /* go over all verts except for endpoints */
600  for (i = 0; i < BLI_array_len(eve_line); i++) {
601  BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) {
602  if (!uvedit_face_visible_test(scene, l->f)) {
603  continue;
604  }
605 
606  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
607  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
608  /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
609  * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
610  * Maybe this should be a BLI func? Or is it already existing?
611  * Could use interp_v2_v2v2, but not sure it's worth it here...*/
612  if (tool_local == UV_STRAIGHTEN_X) {
613  luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
614  }
615  else if (tool_local == UV_STRAIGHTEN_Y) {
616  luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
617  }
618  else {
619  closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
620  }
621  changed = true;
622  }
623  }
624  }
625  }
626  else {
627  /* error - not a line, needs 3+ points */
628  }
629 
630  if (eve_line) {
631  MEM_freeN(eve_line);
632  }
633  }
634  else {
635  /* error - cant find an endpoint */
636  }
637  }
638 
639  if (changed) {
640  uvedit_live_unwrap_update(sima, scene, obedit);
641  DEG_id_tag_update(obedit->data, 0);
643  }
644  }
645 
646  MEM_freeN(objects);
647 }
648 
650 {
651  uv_weld_align(C, RNA_enum_get(op->ptr, "axis"));
652 
653  return OPERATOR_FINISHED;
654 }
655 
657 {
658  static const EnumPropertyItem axis_items[] = {
659  {UV_STRAIGHTEN,
660  "ALIGN_S",
661  0,
662  "Straighten",
663  "Align UVs along the line defined by the endpoints"},
665  "ALIGN_T",
666  0,
667  "Straighten X",
668  "Align UVs along the line defined by the endpoints along the X axis"},
670  "ALIGN_U",
671  0,
672  "Straighten Y",
673  "Align UVs along the line defined by the endpoints along the Y axis"},
674  {UV_ALIGN_AUTO,
675  "ALIGN_AUTO",
676  0,
677  "Align Auto",
678  "Automatically choose the axis on which there is most alignment already"},
679  {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
680  {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
681  {0, NULL, 0, NULL, NULL},
682  };
683 
684  /* identifiers */
685  ot->name = "Align";
686  ot->description = "Align selected UV vertices to an axis";
687  ot->idname = "UV_OT_align";
689 
690  /* api callbacks */
691  ot->exec = uv_align_exec;
693 
694  /* properties */
695  RNA_def_enum(
696  ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on");
697 }
698 
701 /* -------------------------------------------------------------------- */
706 {
708  ViewLayer *view_layer = CTX_data_view_layer(C);
710  const ToolSettings *ts = scene->toolsettings;
711 
712  const float threshold = RNA_float_get(op->ptr, "threshold");
713  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
714 
715  uint objects_len = 0;
717  view_layer, ((View3D *)NULL), &objects_len);
718 
719  bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed");
720 
721  /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr.
722  * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */
723  uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len,
724  "uv_remove_doubles_selected.ob_mloopuv_max_idx");
725 
726  /* Calculate max possible number of kdtree nodes. */
727  int uv_maxlen = 0;
728  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
729  Object *obedit = objects[ob_index];
730  BMEditMesh *em = BKE_editmesh_from_object(obedit);
731 
732  if (synced_selection && (em->bm->totvertsel == 0)) {
733  continue;
734  }
735 
736  uv_maxlen += em->bm->totloop;
737  }
738 
739  KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
740 
741  int *duplicates = NULL;
742  BLI_array_declare(duplicates);
743 
744  MLoopUV **mloopuv_arr = NULL;
745  BLI_array_declare(mloopuv_arr);
746 
747  int mloopuv_count = 0; /* Also used for *duplicates count. */
748 
749  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
750  BMIter iter, liter;
751  BMFace *efa;
752  BMLoop *l;
753  Object *obedit = objects[ob_index];
754  BMEditMesh *em = BKE_editmesh_from_object(obedit);
755 
756  if (synced_selection && (em->bm->totvertsel == 0)) {
757  continue;
758  }
759 
760  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
761 
762  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
763  if (!uvedit_face_visible_test(scene, efa)) {
764  continue;
765  }
766 
767  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
768  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
769  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
770  BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
771  BLI_array_append(duplicates, -1);
772  BLI_array_append(mloopuv_arr, luv);
773  mloopuv_count++;
774  }
775  }
776  }
777 
778  ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1;
779  }
780 
781  BLI_kdtree_2d_balance(tree);
782  int found_duplicates = BLI_kdtree_2d_calc_duplicates_fast(tree, threshold, false, duplicates);
783 
784  if (found_duplicates > 0) {
785  /* Calculate average uv for duplicates. */
786  int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count,
787  "uv_remove_doubles_selected.uv_duplicate_count");
788  for (int i = 0; i < mloopuv_count; i++) {
789  if (duplicates[i] == -1) { /* If doesn't reference another */
790  uv_duplicate_count[i]++; /* self */
791  continue;
792  }
793 
794  if (duplicates[i] != i) {
795  /* If not self then accumulate uv for averaging.
796  * Self uv is already present in accumulator */
797  add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv);
798  }
799  uv_duplicate_count[duplicates[i]]++;
800  }
801 
802  for (int i = 0; i < mloopuv_count; i++) {
803  if (uv_duplicate_count[i] < 2) {
804  continue;
805  }
806 
807  mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]);
808  }
809  MEM_freeN(uv_duplicate_count);
810 
811  /* Update duplicated uvs. */
812  uint ob_index = 0;
813  for (int i = 0; i < mloopuv_count; i++) {
814  /* Make sure we know which object owns the MLoopUV at this index.
815  * Remember that in some cases the object will have no loop uv,
816  * thus we need the while loop, and not simply an if check. */
817  while (ob_mloopuv_max_idx[ob_index] < i) {
818  ob_index++;
819  }
820 
821  if (duplicates[i] == -1) {
822  continue;
823  }
824 
825  copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv);
826  changed[ob_index] = true;
827  }
828 
829  for (ob_index = 0; ob_index < objects_len; ob_index++) {
830  if (changed[ob_index]) {
831  Object *obedit = objects[ob_index];
832  uvedit_live_unwrap_update(sima, scene, obedit);
833  DEG_id_tag_update(obedit->data, 0);
835  }
836  }
837  }
838 
839  BLI_kdtree_2d_free(tree);
840  BLI_array_free(mloopuv_arr);
841  BLI_array_free(duplicates);
842  MEM_freeN(changed);
843  MEM_freeN(objects);
844  MEM_freeN(ob_mloopuv_max_idx);
845 
846  return OPERATOR_FINISHED;
847 }
848 
850 {
852  ViewLayer *view_layer = CTX_data_view_layer(C);
854  const ToolSettings *ts = scene->toolsettings;
855 
856  const float threshold = RNA_float_get(op->ptr, "threshold");
857  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
858 
859  uint objects_len = 0;
861  view_layer, ((View3D *)NULL), &objects_len);
862 
863  /* Calculate max possible number of kdtree nodes. */
864  int uv_maxlen = 0;
865  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
866  Object *obedit = objects[ob_index];
867  BMEditMesh *em = BKE_editmesh_from_object(obedit);
868  uv_maxlen += em->bm->totloop;
869  }
870 
871  KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
872 
873  MLoopUV **mloopuv_arr = NULL;
874  BLI_array_declare(mloopuv_arr);
875 
876  int mloopuv_count = 0;
877 
878  /* Add visible non-selected uvs to tree */
879  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
880  BMIter iter, liter;
881  BMFace *efa;
882  BMLoop *l;
883  Object *obedit = objects[ob_index];
884  BMEditMesh *em = BKE_editmesh_from_object(obedit);
885 
886  if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) {
887  continue;
888  }
889 
890  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
891 
892  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
893  if (!uvedit_face_visible_test(scene, efa)) {
894  continue;
895  }
896 
897  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
898  if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
899  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
900  BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
901  BLI_array_append(mloopuv_arr, luv);
902  mloopuv_count++;
903  }
904  }
905  }
906  }
907 
908  BLI_kdtree_2d_balance(tree);
909 
910  /* For each selected uv, find duplicate non selected uv. */
911  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
912  BMIter iter, liter;
913  BMFace *efa;
914  BMLoop *l;
915  bool changed = false;
916  Object *obedit = objects[ob_index];
917  BMEditMesh *em = BKE_editmesh_from_object(obedit);
918 
919  if (synced_selection && (em->bm->totvertsel == 0)) {
920  continue;
921  }
922 
923  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
924 
925  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
926  if (!uvedit_face_visible_test(scene, efa)) {
927  continue;
928  }
929 
930  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
931  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
932  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
933  KDTreeNearest_2d nearest;
934  const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest);
935 
936  if (i != -1 && nearest.dist < threshold) {
937  copy_v2_v2(luv->uv, mloopuv_arr[i]->uv);
938  changed = true;
939  }
940  }
941  }
942  }
943 
944  if (changed) {
945  uvedit_live_unwrap_update(sima, scene, obedit);
946  DEG_id_tag_update(obedit->data, 0);
948  }
949  }
950 
951  BLI_kdtree_2d_free(tree);
952  BLI_array_free(mloopuv_arr);
953  MEM_freeN(objects);
954 
955  return OPERATOR_FINISHED;
956 }
957 
959 {
960  if (RNA_boolean_get(op->ptr, "use_unselected")) {
962  }
963  return uv_remove_doubles_to_selected(C, op);
964 }
965 
967 {
968  /* identifiers */
969  ot->name = "Merge UVs by Distance";
970  ot->description =
971  "Selected UV vertices that are within a radius of each other are welded together";
972  ot->idname = "UV_OT_remove_doubles";
974 
975  /* api callbacks */
978 
980  "threshold",
981  0.02f,
982  0.0f,
983  10.0f,
984  "Merge Distance",
985  "Maximum distance between welded vertices",
986  0.0f,
987  1.0f);
989  ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
990 }
991 
994 /* -------------------------------------------------------------------- */
999 {
1001 
1002  return OPERATOR_FINISHED;
1003 }
1004 
1006 {
1007  /* identifiers */
1008  ot->name = "Weld";
1009  ot->description = "Weld selected UV vertices together";
1010  ot->idname = "UV_OT_weld";
1012 
1013  /* api callbacks */
1014  ot->exec = uv_weld_exec;
1016 }
1017 
1020 /* -------------------------------------------------------------------- */
1024 static void uv_snap_to_pixel(float uvco[2], float w, float h)
1025 {
1026  uvco[0] = roundf(uvco[0] * w) / w;
1027  uvco[1] = roundf(uvco[1] * h) / h;
1028 }
1029 
1031 {
1032  int width = 0, height = 0;
1033 
1036 }
1037 
1039  Object **objects_edit,
1040  uint objects_len,
1041  SpaceImage *sima)
1042 {
1043  return ED_uvedit_center_multi(scene, objects_edit, objects_len, sima->cursor, sima->around);
1044 }
1045 
1047 {
1048  SpaceImage *sima = CTX_wm_space_image(C);
1049 
1050  bool changed = false;
1051 
1052  switch (RNA_enum_get(op->ptr, "target")) {
1053  case 0:
1055  changed = true;
1056  break;
1057  case 1: {
1059  ViewLayer *view_layer = CTX_data_view_layer(C);
1060 
1061  uint objects_len = 0;
1063  view_layer, ((View3D *)NULL), &objects_len);
1064  changed = uv_snap_cursor_to_selection(scene, objects, objects_len, sima);
1065  MEM_freeN(objects);
1066  break;
1067  }
1068  }
1069 
1070  if (!changed) {
1071  return OPERATOR_CANCELLED;
1072  }
1073 
1075 
1076  return OPERATOR_FINISHED;
1077 }
1078 
1080 {
1081  static const EnumPropertyItem target_items[] = {
1082  {0, "PIXELS", 0, "Pixels", ""},
1083  {1, "SELECTED", 0, "Selected", ""},
1084  {0, NULL, 0, NULL, NULL},
1085  };
1086 
1087  /* identifiers */
1088  ot->name = "Snap Cursor";
1089  ot->description = "Snap cursor to target type";
1090  ot->idname = "UV_OT_snap_cursor";
1092 
1093  /* api callbacks */
1095  ot->poll = ED_operator_uvedit_space_image; /* requires space image */
1096 
1097  /* properties */
1098  RNA_def_enum(
1099  ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
1100 }
1101 
1104 /* -------------------------------------------------------------------- */
1108 static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2])
1109 {
1110  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1111  BMFace *efa;
1112  BMLoop *l;
1113  BMIter iter, liter;
1114  MLoopUV *luv;
1115  bool changed = false;
1116 
1117  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1118 
1119  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1120  if (!uvedit_face_visible_test(scene, efa)) {
1121  continue;
1122  }
1123 
1124  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1125  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1126  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1127  copy_v2_v2(luv->uv, cursor);
1128  changed = true;
1129  }
1130  }
1131  }
1132 
1133  return changed;
1134 }
1135 
1136 static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2])
1137 {
1138  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1139  BMFace *efa;
1140  BMLoop *l;
1141  BMIter iter, liter;
1142  MLoopUV *luv;
1143  bool changed = false;
1144 
1145  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1146 
1147  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1148  if (!uvedit_face_visible_test(scene, efa)) {
1149  continue;
1150  }
1151 
1152  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1153  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1154  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1155  add_v2_v2(luv->uv, offset);
1156  changed = true;
1157  }
1158  }
1159  }
1160 
1161  return changed;
1162 }
1163 
1165 {
1166  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1167  BMesh *bm = em->bm;
1168  BMFace *f;
1169  BMLoop *l, *lsub;
1170  BMIter iter, liter, lsubiter;
1171  MLoopUV *luv;
1172  bool changed = false;
1173  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
1174 
1175  /* index every vert that has a selected UV using it, but only once so as to
1176  * get unique indices and to count how much to malloc */
1177  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1178  if (uvedit_face_visible_test(scene, f)) {
1180  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
1181  BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
1182  }
1183  }
1184  else {
1186  }
1187  }
1188 
1189  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1190  if (BM_elem_flag_test(f, BM_ELEM_TAG)) { /* face: visible */
1191  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
1192  if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* loop: selected*/
1193  float uv[2] = {0.0f, 0.0f};
1194  int uv_tot = 0;
1195 
1196  BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) {
1197  if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* face: visible */
1198  !BM_elem_flag_test(lsub, BM_ELEM_TAG)) /* loop: unselected */
1199  {
1200  luv = BM_ELEM_CD_GET_VOID_P(lsub, cd_loop_uv_offset);
1201  add_v2_v2(uv, luv->uv);
1202  uv_tot++;
1203  }
1204  }
1205 
1206  if (uv_tot) {
1207  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1208  mul_v2_v2fl(luv->uv, uv, 1.0f / (float)uv_tot);
1209  changed = true;
1210  }
1211  }
1212  }
1213  }
1214  }
1215 
1216  return changed;
1217 }
1218 
1219 static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
1220 {
1221  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1222  BMFace *efa;
1223  BMLoop *l;
1224  BMIter iter, liter;
1225  MLoopUV *luv;
1226  int width = 0, height = 0;
1227  float w, h;
1228  bool changed = false;
1229 
1230  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1231 
1233  w = (float)width;
1234  h = (float)height;
1235 
1236  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1237  if (!uvedit_face_visible_test(scene, efa)) {
1238  continue;
1239  }
1240 
1241  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1242  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1243  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1244  uv_snap_to_pixel(luv->uv, w, h);
1245  }
1246  }
1247 
1248  changed = true;
1249  }
1250 
1251  return changed;
1252 }
1253 
1255 {
1257  ViewLayer *view_layer = CTX_data_view_layer(C);
1258  SpaceImage *sima = CTX_wm_space_image(C);
1259  const ToolSettings *ts = scene->toolsettings;
1260  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1261  const int target = RNA_enum_get(op->ptr, "target");
1262  float offset[2] = {0};
1263 
1264  uint objects_len = 0;
1266  view_layer, ((View3D *)NULL), &objects_len);
1267 
1268  if (target == 2) {
1269  float center[2];
1270  if (!ED_uvedit_center_multi(scene, objects, objects_len, center, sima->around)) {
1271  MEM_freeN(objects);
1272  return OPERATOR_CANCELLED;
1273  }
1274  sub_v2_v2v2(offset, sima->cursor, center);
1275  }
1276 
1277  bool changed_multi = false;
1278  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1279  Object *obedit = objects[ob_index];
1280  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1281 
1282  if (synced_selection && (em->bm->totvertsel == 0)) {
1283  continue;
1284  }
1285 
1286  bool changed = false;
1287  switch (target) {
1288  case 0:
1289  changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
1290  break;
1291  case 1:
1292  changed = uv_snap_uvs_to_cursor(scene, obedit, sima->cursor);
1293  break;
1294  case 2:
1295  changed = uv_snap_uvs_offset(scene, obedit, offset);
1296  break;
1297  case 3:
1298  changed = uv_snap_uvs_to_adjacent_unselected(scene, obedit);
1299  break;
1300  }
1301 
1302  if (changed) {
1303  changed_multi = true;
1304  uvedit_live_unwrap_update(sima, scene, obedit);
1305  DEG_id_tag_update(obedit->data, 0);
1307  }
1308  }
1309  MEM_freeN(objects);
1310 
1311  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1312 }
1313 
1315 {
1316  static const EnumPropertyItem target_items[] = {
1317  {0, "PIXELS", 0, "Pixels", ""},
1318  {1, "CURSOR", 0, "Cursor", ""},
1319  {2, "CURSOR_OFFSET", 0, "Cursor (Offset)", ""},
1320  {3, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
1321  {0, NULL, 0, NULL, NULL},
1322  };
1323 
1324  /* identifiers */
1325  ot->name = "Snap Selection";
1326  ot->description = "Snap selected UV vertices to target type";
1327  ot->idname = "UV_OT_snap_selected";
1329 
1330  /* api callbacks */
1333 
1334  /* properties */
1335  RNA_def_enum(
1336  ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
1337 }
1338 
1341 /* -------------------------------------------------------------------- */
1346 {
1348  ViewLayer *view_layer = CTX_data_view_layer(C);
1349  BMFace *efa;
1350  BMLoop *l;
1351  BMIter iter, liter;
1352  MLoopUV *luv;
1353  const ToolSettings *ts = scene->toolsettings;
1354  const bool clear = RNA_boolean_get(op->ptr, "clear");
1355  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1356 
1357  uint objects_len = 0;
1359  view_layer, ((View3D *)NULL), &objects_len);
1360 
1361  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1362  Object *obedit = objects[ob_index];
1363  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1364 
1365  bool changed = false;
1366  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1367 
1368  if (synced_selection && (em->bm->totvertsel == 0)) {
1369  continue;
1370  }
1371 
1372  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1373  if (!uvedit_face_visible_test(scene, efa)) {
1374  continue;
1375  }
1376 
1377  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1378  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1379 
1380  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1381  changed = true;
1382  if (clear) {
1383  luv->flag &= ~MLOOPUV_PINNED;
1384  }
1385  else {
1386  luv->flag |= MLOOPUV_PINNED;
1387  }
1388  }
1389  }
1390  }
1391 
1392  if (changed) {
1395  }
1396  }
1397  MEM_freeN(objects);
1398 
1399  return OPERATOR_FINISHED;
1400 }
1401 
1403 {
1404  /* identifiers */
1405  ot->name = "Pin";
1406  ot->description =
1407  "Set/clear selected UV vertices as anchored between multiple unwrap operations";
1408  ot->idname = "UV_OT_pin";
1410 
1411  /* api callbacks */
1412  ot->exec = uv_pin_exec;
1414 
1415  /* properties */
1417  ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it");
1418 }
1419 
1422 /* -------------------------------------------------------------------- */
1426 /* check if we are selected or unselected based on 'bool_test' arg,
1427  * needed for select swap support */
1428 #define UV_SEL_TEST(luv, bool_test) \
1429  ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test)
1430 
1431 /* is every UV vert selected or unselected depending on bool_test */
1432 static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop_uv_offset)
1433 {
1434  BMLoop *l_iter;
1435  BMLoop *l_first;
1436 
1437  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1438  do {
1439  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
1440  if (!UV_SEL_TEST(luv, select_test)) {
1441  return false;
1442  }
1443  } while ((l_iter = l_iter->next) != l_first);
1444 
1445  return true;
1446 }
1447 
1449 {
1450  ViewLayer *view_layer = CTX_data_view_layer(C);
1452  const ToolSettings *ts = scene->toolsettings;
1453  const bool swap = RNA_boolean_get(op->ptr, "unselected");
1454  const bool use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
1455 
1456  uint objects_len = 0;
1458  view_layer, ((View3D *)NULL), &objects_len);
1459 
1460  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1461  Object *ob = objects[ob_index];
1463  BMFace *efa;
1464  BMLoop *l;
1465  BMIter iter, liter;
1466  MLoopUV *luv;
1467 
1468  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1469 
1470  if (ts->uv_flag & UV_SYNC_SELECTION) {
1471  if (EDBM_mesh_hide(em, swap)) {
1472  EDBM_update_generic(ob->data, true, false);
1473  }
1474  continue;
1475  }
1476 
1477  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1478  int hide = 0;
1479 
1480  if (!uvedit_face_visible_test(scene, efa)) {
1481  continue;
1482  }
1483 
1484  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1485  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1486 
1487  if (UV_SEL_TEST(luv, !swap)) {
1488  hide = 1;
1489  break;
1490  }
1491  }
1492 
1493  if (hide) {
1494  /* note, a special case for edges could be used,
1495  * for now edges act like verts and get flushed */
1496  if (use_face_center) {
1497  if (em->selectmode == SCE_SELECT_FACE) {
1498  /* check that every UV is selected */
1499  if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
1500  BM_face_select_set(em->bm, efa, false);
1501  }
1502  uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
1503  }
1504  else {
1505  if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
1506  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1507  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1508  if (UV_SEL_TEST(luv, !swap)) {
1509  BM_vert_select_set(em->bm, l->v, false);
1510  }
1511  }
1512  }
1513  if (!swap) {
1514  uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
1515  }
1516  }
1517  }
1518  else if (em->selectmode == SCE_SELECT_FACE) {
1519  /* check if a UV is de-selected */
1520  if (bm_face_is_all_uv_sel(efa, false, cd_loop_uv_offset) != !swap) {
1521  BM_face_select_set(em->bm, efa, false);
1522  uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
1523  }
1524  }
1525  else {
1526  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1527  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1528  if (UV_SEL_TEST(luv, !swap)) {
1529  BM_vert_select_set(em->bm, l->v, false);
1530  if (!swap) {
1531  luv->flag &= ~MLOOPUV_VERTSEL;
1532  }
1533  }
1534  }
1535  }
1536  }
1537  }
1538 
1539  /* flush vertex selection changes */
1540  if (em->selectmode != SCE_SELECT_FACE) {
1542  }
1543 
1545 
1548  }
1549 
1550  MEM_freeN(objects);
1551 
1552  return OPERATOR_FINISHED;
1553 }
1554 
1555 #undef UV_SEL_TEST
1556 
1558 {
1559  /* identifiers */
1560  ot->name = "Hide Selected";
1561  ot->description = "Hide (un)selected UV vertices";
1562  ot->idname = "UV_OT_hide";
1564 
1565  /* api callbacks */
1566  ot->exec = uv_hide_exec;
1568 
1569  /* props */
1570  RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1571 }
1572 
1575 /* -------------------------------------------------------------------- */
1580 {
1581  ViewLayer *view_layer = CTX_data_view_layer(C);
1582  SpaceImage *sima = CTX_wm_space_image(C);
1584  const ToolSettings *ts = scene->toolsettings;
1585 
1586  const bool use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
1587  const bool stickymode = sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
1588  const bool select = RNA_boolean_get(op->ptr, "select");
1589 
1590  uint objects_len = 0;
1592  view_layer, ((View3D *)NULL), &objects_len);
1593 
1594  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1595  Object *ob = objects[ob_index];
1597  BMFace *efa;
1598  BMLoop *l;
1599  BMIter iter, liter;
1600  MLoopUV *luv;
1601 
1602  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1603 
1604  /* note on tagging, selecting faces needs to be delayed so it doesn't select the verts and
1605  * confuse our checks on selected verts. */
1606 
1607  /* call the mesh function if we are in mesh sync sel */
1608  if (ts->uv_flag & UV_SYNC_SELECTION) {
1609  if (EDBM_mesh_reveal(em, select)) {
1610  EDBM_update_generic(ob->data, true, false);
1611  }
1612  continue;
1613  }
1614  if (use_face_center) {
1615  if (em->selectmode == SCE_SELECT_FACE) {
1616  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1619  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1620  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1622  }
1623  /* BM_face_select_set(em->bm, efa, true); */
1625  }
1626  }
1627  }
1628  else {
1629  /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
1630  if (!stickymode) {
1631  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1633  if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
1635  int totsel = 0;
1636  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1637  totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
1638  }
1639 
1640  if (!totsel) {
1641  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1642  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1644  }
1645  /* BM_face_select_set(em->bm, efa, true); */
1647  }
1648  }
1649  }
1650  }
1651  else {
1652  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1654  if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
1656  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1657  if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
1658  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1660  }
1661  }
1662  /* BM_face_select_set(em->bm, efa, true); */
1664  }
1665  }
1666  }
1667  }
1668  }
1669  else if (em->selectmode == SCE_SELECT_FACE) {
1670  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1673  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1674  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1676  }
1677  /* BM_face_select_set(em->bm, efa, true); */
1679  }
1680  }
1681  }
1682  else {
1683  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1686  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1687  if (BM_elem_flag_test(l->v, BM_ELEM_SELECT) == 0) {
1688  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1690  }
1691  }
1692  /* BM_face_select_set(em->bm, efa, true); */
1694  }
1695  }
1696  }
1697 
1698  /* re-select tagged faces */
1700 
1703  }
1704 
1705  MEM_freeN(objects);
1706 
1707  return OPERATOR_FINISHED;
1708 }
1709 
1711 {
1712  /* identifiers */
1713  ot->name = "Reveal Hidden";
1714  ot->description = "Reveal all hidden UV vertices";
1715  ot->idname = "UV_OT_reveal";
1717 
1718  /* api callbacks */
1719  ot->exec = uv_reveal_exec;
1721 
1722  RNA_def_boolean(ot->srna, "select", true, "Select", "");
1723 }
1724 
1727 /* -------------------------------------------------------------------- */
1732 {
1733  SpaceImage *sima = CTX_wm_space_image(C);
1734 
1735  if (!sima) {
1736  return OPERATOR_CANCELLED;
1737  }
1738 
1739  RNA_float_get_array(op->ptr, "location", sima->cursor);
1740 
1741  {
1742  struct wmMsgBus *mbus = CTX_wm_message_bus(C);
1743  bScreen *screen = CTX_wm_screen(C);
1744  WM_msg_publish_rna_prop(mbus, &screen->id, sima, SpaceImageEditor, cursor_location);
1745  }
1746 
1748 
1749  return OPERATOR_FINISHED;
1750 }
1751 
1752 static int uv_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1753 {
1754  ARegion *region = CTX_wm_region(C);
1755  float location[2];
1756 
1757  if (region->regiontype == RGN_TYPE_WINDOW) {
1758  if (event->mval[1] <= 16) {
1759  SpaceImage *sima = CTX_wm_space_image(C);
1760  if (sima && ED_space_image_show_cache(sima)) {
1761  return OPERATOR_PASS_THROUGH;
1762  }
1763  }
1764  }
1765 
1767  &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
1768  RNA_float_set_array(op->ptr, "location", location);
1769 
1770  return uv_set_2d_cursor_exec(C, op);
1771 }
1772 
1774 {
1775  /* identifiers */
1776  ot->name = "Set 2D Cursor";
1777  ot->description = "Set 2D cursor location";
1778  ot->idname = "UV_OT_cursor_set";
1779 
1780  /* api callbacks */
1784 
1785  /* properties */
1787  "location",
1788  2,
1789  NULL,
1790  -FLT_MAX,
1791  FLT_MAX,
1792  "Location",
1793  "Cursor location in normalized (0.0 to 1.0) coordinates",
1794  -10.0f,
1795  10.0f);
1796 }
1797 
1800 /* -------------------------------------------------------------------- */
1805 {
1807  ViewLayer *view_layer = CTX_data_view_layer(C);
1808  const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
1809  const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
1810  bool changed_multi = false;
1811 
1812  uint objects_len = 0;
1814  view_layer, ((View3D *)NULL), &objects_len);
1815 
1816  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1817  Object *ob = objects[ob_index];
1818  Mesh *me = (Mesh *)ob->data;
1819  BMEditMesh *em = me->edit_mesh;
1820  BMesh *bm = em->bm;
1821  BMIter iter;
1822 
1823  if (!EDBM_uv_check(em)) {
1824  continue;
1825  }
1826 
1827  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
1828  bool changed = false;
1829 
1830  BMFace *f;
1831  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1832  if (!uvedit_face_visible_test(scene, f)) {
1833  continue;
1834  }
1835 
1836  BMLoop *l_iter;
1837  BMLoop *l_first;
1838 
1839  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1840  do {
1841  if (l_iter == l_iter->radial_next) {
1842  continue;
1843  }
1844  if (!uvedit_edge_select_test(scene, l_iter, cd_loop_uv_offset)) {
1845  continue;
1846  }
1847 
1848  bool mark = false;
1849  BMLoop *l_other = l_iter->radial_next;
1850  do {
1851  if (!BM_loop_uv_share_edge_check(l_iter, l_other, cd_loop_uv_offset)) {
1852  mark = true;
1853  break;
1854  }
1855  } while ((l_other = l_other->radial_next) != l_iter);
1856 
1857  if (mark) {
1858  if (mark_seams) {
1860  }
1861  if (mark_sharp) {
1863  }
1864  changed = true;
1865  }
1866  } while ((l_iter = l_iter->next) != l_first);
1867  }
1868 
1869  if (changed) {
1870  changed_multi = true;
1871  DEG_id_tag_update(&me->id, 0);
1873  }
1874  }
1875  MEM_freeN(objects);
1876 
1877  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1878 }
1879 
1881 {
1882  /* identifiers */
1883  ot->name = "Seams from Islands";
1884  ot->description = "Set mesh seams according to island setup in the UV editor";
1885  ot->idname = "UV_OT_seams_from_islands";
1886 
1887  /* flags */
1889 
1890  /* api callbacks */
1893 
1894  RNA_def_boolean(ot->srna, "mark_seams", 1, "Mark Seams", "Mark boundary edges as seams");
1895  RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
1896 }
1897 
1900 /* -------------------------------------------------------------------- */
1905 {
1907  ViewLayer *view_layer = CTX_data_view_layer(C);
1908  const ToolSettings *ts = scene->toolsettings;
1909 
1910  BMFace *efa;
1911  BMLoop *loop;
1912  BMIter iter, liter;
1913 
1914  const bool flag_set = !RNA_boolean_get(op->ptr, "clear");
1915  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1916 
1917  uint objects_len = 0;
1919  view_layer, ((View3D *)NULL), &objects_len);
1920 
1921  bool changed = false;
1922 
1923  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1924  Object *ob = objects[ob_index];
1925  Mesh *me = (Mesh *)ob->data;
1926  BMEditMesh *em = me->edit_mesh;
1927  BMesh *bm = em->bm;
1928 
1929  if (synced_selection && (bm->totedgesel == 0)) {
1930  continue;
1931  }
1932 
1933  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
1934 
1935  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1936  if (uvedit_face_visible_test(scene, efa)) {
1937  BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
1938  if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
1939  BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
1940  changed = true;
1941  }
1942  }
1943  }
1944  }
1945 
1946  if (changed) {
1947  DEG_id_tag_update(&me->id, 0);
1949  }
1950  }
1951 
1952  if (changed) {
1953  ED_uvedit_live_unwrap(scene, objects, objects_len);
1954  }
1955 
1956  MEM_freeN(objects);
1957 
1958  return OPERATOR_FINISHED;
1959 }
1960 
1961 static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1962 {
1963  uiPopupMenu *pup;
1964  uiLayout *layout;
1965 
1966  if (RNA_struct_property_is_set(op->ptr, "clear")) {
1967  return uv_mark_seam_exec(C, op);
1968  }
1969 
1970  pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE);
1971  layout = UI_popup_menu_layout(pup);
1972 
1974  uiItemBooleanO(layout,
1976  ICON_NONE,
1977  op->type->idname,
1978  "clear",
1979  false);
1980  uiItemBooleanO(layout,
1982  ICON_NONE,
1983  op->type->idname,
1984  "clear",
1985  true);
1986 
1987  UI_popup_menu_end(C, pup);
1988 
1989  return OPERATOR_INTERFACE;
1990 }
1991 
1993 {
1994  /* identifiers */
1995  ot->name = "Mark Seam";
1996  ot->description = "Mark selected UV edges as seams";
1997  ot->idname = "UV_OT_mark_seam";
1998 
1999  /* flags */
2001 
2002  /* api callbacks */
2006 
2007  RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams");
2008 }
2009 
2012 /* -------------------------------------------------------------------- */
2017 {
2018  /* uvedit_select.c */
2033 
2036 
2038 
2043 
2049 
2060 
2063 
2065 }
2066 
2068 {
2069  wmOperatorType *ot;
2070  wmOperatorTypeMacro *otmacro;
2071 
2072  ot = WM_operatortype_append_macro("UV_OT_rip_move",
2073  "UV Rip Move",
2074  "Unstitch UV's and move the result",
2076  WM_operatortype_macro_define(ot, "UV_OT_rip");
2077  otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
2078  RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
2079  RNA_boolean_set(otmacro->ptr, "mirror", false);
2080 }
2081 
2083 {
2084  wmKeyMap *keymap;
2085 
2086  keymap = WM_keymap_ensure(keyconf, "UV Editor", 0, 0);
2087  keymap->poll = ED_operator_uvedit;
2088 }
2089 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1279
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:709
struct wmMsgBus * CTX_wm_message_bus(const bContext *C)
Definition: context.c:746
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:800
CustomData interface, see also DNA_customdata_types.h.
void * CustomData_get_layer(const struct CustomData *data, int type)
int CustomData_get_offset(const struct CustomData *data, int type)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:434
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:697
#define SH_NODE_TEX_ENVIRONMENT
Definition: BKE_node.h:1022
struct bNode * nodeGetActiveTexture(struct bNodeTree *ntree)
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:104
#define BLI_array_declare(arr)
Definition: BLI_array.h:62
#define BLI_array_len(arr)
Definition: BLI_array.h:74
#define BLI_array_free(arr)
Definition: BLI_array.h:116
A kd-tree for nearest neighbor search.
void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:353
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:1043
MINLINE void add_v2_v2(float r[2], const float a[2])
void mid_v2_v2v2(float r[2], const float a[2], const float b[2])
Definition: math_vector.c:277
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
MINLINE void mul_v2_v2fl(float r[2], const float a[2], float f)
unsigned int uint
Definition: BLI_sys_types.h:83
#define INIT_MINMAX2(min, max)
#define UNUSED_FUNCTION(x)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define ELEM(...)
#define CTX_IFACE_(context, msgid)
#define BLT_I18NCONTEXT_OPERATOR_DEFAULT
#define IFACE_(msgid)
void swap(T &a, T &b)
Definition: Common.h:33
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_SELECT
Definition: DNA_ID.h:638
@ CD_MLOOPUV
@ MLOOPUV_PINNED
@ MLOOPUV_VERTSEL
Object is a sort of wrapper for general info.
@ OB_MESH
#define UV_SELECT_FACE
#define SCE_SELECT_FACE
#define UV_SYNC_SELECTION
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
@ RGN_TYPE_WINDOW
@ SI_LIVE_UNWRAP
@ SI_STICKY_DISABLE
@ V3D_AROUND_CENTER_BOUNDS
@ V3D_AROUND_CURSOR
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
bool ED_space_image_show_cache(struct SpaceImage *sima)
Definition: image_draw.c:982
void ED_space_image_get_size(struct SpaceImage *sima, int *r_width, int *r_height)
Definition: image_edit.c:215
bool ED_space_image_cursor_poll(struct bContext *C)
Definition: image_edit.c:532
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode)
bool EDBM_mesh_hide(struct BMEditMesh *em, bool swap)
void EDBM_update_generic(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
bool EDBM_mesh_reveal(struct BMEditMesh *em, bool select)
bool EDBM_uv_check(struct BMEditMesh *em)
void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node)
Definition: node_draw.cc:164
bool ED_operator_uvedit_space_image(struct bContext *C)
Definition: screen_ops.c:518
bool ED_operator_uvedit(struct bContext *C)
Definition: screen_ops.c:511
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit)
void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, int objects_len)
bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset)
void ED_uvedit_live_unwrap_re_solve(void)
void uvedit_face_select_disable(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, const int cd_loop_uv_offset)
bool uvedit_edge_select_test(const struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset)
bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa)
void ED_uvedit_live_unwrap_end(short cancel)
NSNotificationCenter * center
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
Read Guarded memory(de)allocation.
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume SH_NODE_TEX_IMAGE
#define C
Definition: RandGen.cpp:39
void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext)
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
uiPopupMenu * UI_popup_menu_begin(struct bContext *C, const char *title, int icon) ATTR_NONNULL()
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:204
#define ND_SPACE_IMAGE
Definition: WM_types.h:417
#define ND_SELECT
Definition: WM_types.h:407
#define NC_SPACE
Definition: WM_types.h:293
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_select_history_validate(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_mesh_elem_hflag_enable_test(BMesh *bm, const char htype, const char hflag, const bool respecthide, const bool overwrite, const char hflag_test)
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
bool BM_loop_uv_share_edge_check(BMLoop *l_a, BMLoop *l_b, const int cd_loop_uv_offset)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
OperationNode * node
Scene scene
void * tree
bNodeTree * ntree
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static void clear(Message *msg)
Definition: msgfmt.c:294
static unsigned a[3]
Definition: RandGen.cpp:92
return ret
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:6272
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:6378
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:6685
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:6390
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, int len, const float *default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3851
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
#define min(a, b)
Definition: sort.c:51
short regiontype
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
short selectmode
Definition: BKE_editmesh.h:72
struct BMesh * bm
Definition: BKE_editmesh.h:52
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
int totvert
Definition: bmesh_class.h:297
int totvertsel
Definition: bmesh_class.h:298
int totloop
Definition: bmesh_class.h:297
int totedgesel
Definition: bmesh_class.h:298
CustomData ldata
Definition: bmesh_class.h:337
Definition: BKE_main.h:116
struct bNodeTree * nodetree
struct BMEditMesh * edit_mesh
struct CustomData pdata ldata
void * data
struct ToolSettings * toolsettings
float cursor[2]
int mval[2]
Definition: WM_types.h:583
bool(* poll)(struct bContext *)
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct wmOperatorType * type
struct PointerRNA * ptr
float max
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
void UV_OT_rip(struct wmOperatorType *ot)
Definition: uvedit_rip.c:950
void UV_OT_select_linked(struct wmOperatorType *ot)
void UV_OT_select_less(struct wmOperatorType *ot)
void UV_OT_select_loop(struct wmOperatorType *ot)
void UV_OT_select(struct wmOperatorType *ot)
void UV_OT_select_pinned(struct wmOperatorType *ot)
bool uvedit_select_is_any_selected_multi(struct Scene *scene, struct Object **objects, const uint objects_len)
void UV_OT_select_overlap(struct wmOperatorType *ot)
void UV_OT_select_box(struct wmOperatorType *ot)
void UV_OT_unwrap(struct wmOperatorType *ot)
void UV_OT_sphere_project(struct wmOperatorType *ot)
void UV_OT_select_more(struct wmOperatorType *ot)
void UV_OT_smart_project(struct wmOperatorType *ot)
void UV_OT_shortest_path_pick(struct wmOperatorType *ot)
Definition: uvedit_path.c:774
void UV_OT_shortest_path_select(struct wmOperatorType *ot)
Definition: uvedit_path.c:881
void UV_OT_cube_project(struct wmOperatorType *ot)
const float * uvedit_first_selected_uv_from_vertex(struct Scene *scene, struct BMVert *eve, const int cd_loop_uv_offset)
void UV_OT_cylinder_project(struct wmOperatorType *ot)
void UV_OT_select_split(struct wmOperatorType *ot)
void UV_OT_select_all(struct wmOperatorType *ot)
void UV_OT_stitch(struct wmOperatorType *ot)
void UV_OT_select_lasso(struct wmOperatorType *ot)
void UV_OT_reset(struct wmOperatorType *ot)
void UV_OT_average_islands_scale(struct wmOperatorType *ot)
void UV_OT_select_linked_pick(struct wmOperatorType *ot)
void UV_OT_select_circle(struct wmOperatorType *ot)
void UV_OT_project_from_view(struct wmOperatorType *ot)
void UV_OT_pack_islands(struct wmOperatorType *ot)
void UV_OT_minimize_stretch(struct wmOperatorType *ot)
void UV_OT_select_edge_ring(struct wmOperatorType *ot)
void ED_keymap_uvedit(wmKeyConfig *keyconf)
Definition: uvedit_ops.c:2082
void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
Definition: uvedit_ops.c:208
static void UV_OT_snap_cursor(wmOperatorType *ot)
Definition: uvedit_ops.c:1079
static void UV_OT_cursor_set(wmOperatorType *ot)
Definition: uvedit_ops.c:1773
void ED_operatormacros_uvedit(void)
Definition: uvedit_ops.c:2067
static int uv_snap_selection_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1254
bool ED_uvedit_center_from_pivot(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, float r_center[2], char mode)
Definition: uvedit_ops.c:370
static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: uvedit_ops.c:1961
static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:705
static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:958
bool ED_uvedit_center_multi(const Scene *scene, Object **objects_edit, uint objects_len, float cent[2], char mode)
Definition: uvedit_ops.c:313
static void UV_OT_align(wmOperatorType *ot)
Definition: uvedit_ops.c:656
static int uv_hide_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1448
static void UV_OT_mark_seam(wmOperatorType *ot)
Definition: uvedit_ops.c:1992
static void UV_OT_weld(wmOperatorType *ot)
Definition: uvedit_ops.c:1005
static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
Definition: uvedit_ops.c:1219
static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2])
Definition: uvedit_ops.c:1108
bool ED_uvedit_test(Object *obedit)
Definition: uvedit_ops.c:80
static void uv_weld_align(bContext *C, eUVWeldAlign tool)
Definition: uvedit_ops.c:392
static bool ED_uvedit_median_multi(const Scene *scene, Object **objects_edit, uint objects_len, float co[2])
Definition: uvedit_ops.c:274
void ED_uvedit_select_all(BMesh *bm)
Definition: uvedit_ops.c:257
static void UV_OT_snap_selected(wmOperatorType *ot)
Definition: uvedit_ops.c:1314
static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op))
Definition: uvedit_ops.c:998
static void uv_snap_to_pixel(float uvco[2], float w, float h)
Definition: uvedit_ops.c:1024
static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Object *obedit)
Definition: uvedit_ops.c:1164
bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, float r_center[2], char mode, bool *r_has_select)
Definition: uvedit_ops.c:334
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1046
static void UV_OT_reveal(wmOperatorType *ot)
Definition: uvedit_ops.c:1710
static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2])
Definition: uvedit_ops.c:1136
eUVWeldAlign
Definition: uvedit_ops.c:382
@ UV_ALIGN_Y
Definition: uvedit_ops.c:388
@ UV_STRAIGHTEN
Definition: uvedit_ops.c:383
@ UV_WELD
Definition: uvedit_ops.c:389
@ UV_STRAIGHTEN_Y
Definition: uvedit_ops.c:385
@ UV_ALIGN_AUTO
Definition: uvedit_ops.c:386
@ UV_ALIGN_X
Definition: uvedit_ops.c:387
@ UV_STRAIGHTEN_X
Definition: uvedit_ops.c:384
#define UV_SEL_TEST(luv, bool_test)
Definition: uvedit_ops.c:1428
void ED_operatortypes_uvedit(void)
Definition: uvedit_ops.c:2016
static int uv_align_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:649
static void UV_OT_hide(wmOperatorType *ot)
Definition: uvedit_ops.c:1557
static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1804
bool ED_object_get_active_image(Object *ob, int mat_nr, Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree)
Definition: uvedit_ops.c:125
static bool uv_snap_cursor_to_selection(Scene *scene, Object **objects_edit, uint objects_len, SpaceImage *sima)
Definition: uvedit_ops.c:1038
static void uv_snap_cursor_to_pixels(SpaceImage *sima)
Definition: uvedit_ops.c:1030
static int uv_pin_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1345
void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
Definition: uvedit_ops.c:193
static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop_uv_offset)
Definition: uvedit_ops.c:1432
static void UV_OT_seams_from_islands(wmOperatorType *ot)
Definition: uvedit_ops.c:1880
void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
Definition: uvedit_ops.c:176
static int UNUSED_FUNCTION() ED_operator_uvmap_mesh(bContext *C)
Definition: uvedit_ops.c:99
static void UV_OT_pin(wmOperatorType *ot)
Definition: uvedit_ops.c:1402
bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2])
Definition: uvedit_ops.c:251
static int uv_reveal_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1579
static int uv_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: uvedit_ops.c:1752
static int uv_mark_seam_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1904
static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:849
static void UV_OT_remove_doubles(wmOperatorType *ot)
Definition: uvedit_ops.c:966
static bool is_image_texture_node(bNode *node)
Definition: uvedit_ops.c:120
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1731
bool ED_uvedit_minmax_multi(const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2])
Definition: uvedit_ops.c:217
uint len
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition: wm_keymap.c:852
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_)
wmOperatorType * WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag)
wmOperatorTypeMacro * WM_operatortype_macro_define(wmOperatorType *ot, const char *idname)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))