Blender  V3.3
uvedit_ops.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include <math.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "DNA_image_types.h"
15 #include "DNA_material_types.h"
16 #include "DNA_mesh_types.h"
17 #include "DNA_meshdata_types.h"
18 #include "DNA_node_types.h"
19 #include "DNA_object_types.h"
20 #include "DNA_scene_types.h"
21 #include "DNA_space_types.h"
22 
23 #include "BLI_array.h"
24 #include "BLI_kdtree.h"
25 #include "BLI_math.h"
26 #include "BLI_utildefines.h"
27 
28 #include "BLT_translation.h"
29 
30 #include "BKE_context.h"
31 #include "BKE_customdata.h"
32 #include "BKE_editmesh.h"
33 #include "BKE_layer.h"
34 #include "BKE_main.h"
35 #include "BKE_material.h"
36 #include "BKE_mesh_mapping.h"
37 #include "BKE_node.h"
38 
39 #include "DEG_depsgraph.h"
40 
41 #include "ED_image.h"
42 #include "ED_mesh.h"
43 #include "ED_node.h"
44 #include "ED_screen.h"
45 #include "ED_uvedit.h"
46 
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49 
50 #include "WM_api.h"
51 #include "WM_message.h"
52 #include "WM_types.h"
53 
54 #include "UI_interface.h"
55 #include "UI_resources.h"
56 #include "UI_view2d.h"
57 
58 #include "uvedit_intern.h"
59 
60 /* -------------------------------------------------------------------- */
64 bool ED_uvedit_test(Object *obedit)
65 {
66  BMEditMesh *em;
67  int ret;
68 
69  if (!obedit) {
70  return 0;
71  }
72 
73  if (obedit->type != OB_MESH) {
74  return 0;
75  }
76 
77  em = BKE_editmesh_from_object(obedit);
78  ret = EDBM_uv_check(em);
79 
80  return ret;
81 }
82 
84 {
86 
87  if (ob && ob->type == OB_MESH) {
88  Mesh *me = ob->data;
89 
90  if (CustomData_get_layer(&me->ldata, CD_MLOOPUV) != NULL) {
91  return 1;
92  }
93  }
94 
95  return 0;
96 }
97 
100 /* -------------------------------------------------------------------- */
105 {
107 }
108 
110  int mat_nr,
111  Image **r_ima,
112  ImageUser **r_iuser,
113  bNode **r_node,
114  bNodeTree **r_ntree)
115 {
116  Material *ma = BKE_object_material_get(ob, mat_nr);
117  bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
119 
120  if (node && is_image_texture_node(node)) {
121  if (r_ima) {
122  *r_ima = (Image *)node->id;
123  }
124  if (r_iuser) {
125  if (node->type == SH_NODE_TEX_IMAGE) {
126  *r_iuser = &((NodeTexImage *)node->storage)->iuser;
127  }
128  else if (node->type == SH_NODE_TEX_ENVIRONMENT) {
129  *r_iuser = &((NodeTexEnvironment *)node->storage)->iuser;
130  }
131  else {
132  *r_iuser = NULL;
133  }
134  }
135  if (r_node) {
136  *r_node = node;
137  }
138  if (r_ntree) {
139  *r_ntree = ntree;
140  }
141  return true;
142  }
143 
144  if (r_ima) {
145  *r_ima = NULL;
146  }
147  if (r_iuser) {
148  *r_iuser = NULL;
149  }
150  if (r_node) {
151  *r_node = node;
152  }
153  if (r_ntree) {
154  *r_ntree = ntree;
155  }
156 
157  return false;
158 }
159 
160 void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
161 {
162  Material *ma = BKE_object_material_get(ob, mat_nr);
163  bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
164 
165  if (node && is_image_texture_node(node)) {
166  node->id = &ima->id;
168  }
169 }
170 
173 /* -------------------------------------------------------------------- */
178 {
179  if (sima && (sima->flag & SI_LIVE_UNWRAP)) {
183  }
184 }
185 
188 /* -------------------------------------------------------------------- */
192 void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
193 {
194  int i;
195  for (i = 0; i < len; i++) {
196  uv[i][0] = uv_orig[i][0] * aspx;
197  uv[i][1] = uv_orig[i][1] * aspy;
198  }
199 }
200 
202  const Scene *scene, Object **objects_edit, uint objects_len, float r_min[2], float r_max[2])
203 {
204  bool changed = false;
205  INIT_MINMAX2(r_min, r_max);
206 
207  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
208  Object *obedit = objects_edit[ob_index];
209 
210  BMEditMesh *em = BKE_editmesh_from_object(obedit);
211  BMFace *efa;
212  BMLoop *l;
213  BMIter iter, liter;
214  MLoopUV *luv;
215 
216  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
217 
218  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
219  if (!uvedit_face_visible_test(scene, efa)) {
220  continue;
221  }
222 
223  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
224  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
225  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
226  minmax_v2v2_v2(r_min, r_max, luv->uv);
227  changed = true;
228  }
229  }
230  }
231  }
232  return changed;
233 }
234 
235 bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2])
236 {
237  return ED_uvedit_minmax_multi(scene, &obedit, 1, r_min, r_max);
238 }
239 
241 {
242  BMFace *efa;
243  BMLoop *l;
244  BMIter iter, liter;
245  MLoopUV *luv;
246 
247  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
248 
249  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
250  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
251  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
253  }
254  }
255 }
256 
257 static bool ED_uvedit_median_multi(const Scene *scene,
258  Object **objects_edit,
259  uint objects_len,
260  float co[2])
261 {
262  uint sel = 0;
263  zero_v2(co);
264 
265  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
266  Object *obedit = objects_edit[ob_index];
267 
268  BMEditMesh *em = BKE_editmesh_from_object(obedit);
269  BMFace *efa;
270  BMLoop *l;
271  BMIter iter, liter;
272  MLoopUV *luv;
273 
274  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
275 
276  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
277  if (!uvedit_face_visible_test(scene, efa)) {
278  continue;
279  }
280 
281  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
282  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
283  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
284  add_v2_v2(co, luv->uv);
285  sel++;
286  }
287  }
288  }
289  }
290 
291  mul_v2_fl(co, 1.0f / (float)sel);
292 
293  return (sel != 0);
294 }
295 
297  const Scene *scene, Object **objects_edit, uint objects_len, float cent[2], char mode)
298 {
299  bool changed = false;
300 
301  if (mode == V3D_AROUND_CENTER_BOUNDS) { /* bounding box */
302  float min[2], max[2];
303  if (ED_uvedit_minmax_multi(scene, objects_edit, objects_len, min, max)) {
304  mid_v2_v2v2(cent, min, max);
305  changed = true;
306  }
307  }
308  else {
309  if (ED_uvedit_median_multi(scene, objects_edit, objects_len, cent)) {
310  changed = true;
311  }
312  }
313 
314  return changed;
315 }
316 
318  Scene *scene,
319  ViewLayer *view_layer,
320  float r_center[2],
321  char mode,
322  bool *r_has_select)
323 {
324  bool changed = false;
325  switch (mode) {
326  case V3D_AROUND_CURSOR: {
327  copy_v2_v2(r_center, sima->cursor);
328  changed = true;
329  if (r_has_select != NULL) {
330  uint objects_len = 0;
332  view_layer, ((View3D *)NULL), &objects_len);
333  *r_has_select = uvedit_select_is_any_selected_multi(scene, objects, objects_len);
334  MEM_freeN(objects);
335  }
336  break;
337  }
338  default: {
339  uint objects_len = 0;
341  view_layer, ((View3D *)NULL), &objects_len);
342  changed = ED_uvedit_center_multi(scene, objects, objects_len, r_center, mode);
343  MEM_freeN(objects);
344  if (r_has_select != NULL) {
345  *r_has_select = changed;
346  }
347  break;
348  }
349  }
350  return changed;
351 }
352 
354  SpaceImage *sima, Scene *scene, ViewLayer *view_layer, float r_center[2], char mode)
355 {
356  return ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, mode, NULL);
357 }
358 
361 /* -------------------------------------------------------------------- */
365 typedef enum eUVWeldAlign {
374 
376  BMesh *bm,
377  const eUVWeldAlign tool,
378  const float cent[2])
379 {
380  bool changed = false;
381  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
382 
383  BMIter iter;
384  BMFace *efa;
385  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
386  if (!uvedit_face_visible_test(scene, efa)) {
387  continue;
388  }
389 
390  BMIter liter;
391  BMLoop *l;
392  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
393  if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
394  continue;
395  }
396  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
397  if (ELEM(tool, UV_ALIGN_X, UV_WELD)) {
398  if (luv->uv[0] != cent[0]) {
399  luv->uv[0] = cent[0];
400  changed = true;
401  }
402  }
403  if (ELEM(tool, UV_ALIGN_Y, UV_WELD)) {
404  if (luv->uv[1] != cent[1]) {
405  luv->uv[1] = cent[1];
406  changed = true;
407  }
408  }
409  }
410  }
411  return changed;
412 }
413 
415 typedef enum eUVEndPointPrecedence {
417  UVEP_SELECTED = (1 << 0),
418  UVEP_PINNED = (1 << 1), /* i.e. Pinned verts are preferred to selected. */
420 
422 {
424  if (luv->flag & MLOOPUV_PINNED) {
425  precedence |= UVEP_PINNED;
426  }
427  return precedence;
428 }
429 
434 static bool uvedit_line_update_endpoint(const MLoopUV *luv,
435  float uv_a[2],
436  eUVEndPointPrecedence *prec_a,
437  float uv_b[2],
438  eUVEndPointPrecedence *prec_b)
439 {
441 
442  float len_sq_a = len_squared_v2v2(uv_a, luv->uv);
443  float len_sq_b = len_squared_v2v2(uv_b, luv->uv);
444 
445  /* Caching the value of `len_sq_ab` is unlikely to be faster than recalculating.
446  * Profile before optimizing. */
447  float len_sq_ab = len_squared_v2v2(uv_a, uv_b);
448 
449  if ((*prec_a < flags && 0.0f < len_sq_b) || (*prec_a == flags && len_sq_ab < len_sq_b)) {
450  *prec_a = flags;
451  copy_v2_v2(uv_a, luv->uv);
452  return true;
453  }
454 
455  if ((*prec_b < flags && 0.0f < len_sq_a) || (*prec_b == flags && len_sq_ab < len_sq_a)) {
456  *prec_b = flags;
457  copy_v2_v2(uv_b, luv->uv);
458  return true;
459  }
460 
461  return false;
462 }
463 
469  const int len,
470  const int cd_loop_uv_offset,
471  const eUVWeldAlign tool)
472 {
473  float uv_start[2];
474  float uv_end[2];
475  eUVEndPointPrecedence prec_start = UVEP_INVALID;
477 
478  /* Find start and end of line. */
479  for (int i = 0; i < 10; i++) { /* Heuristic to prevent infinite loop. */
480  bool update = false;
481  for (int j = 0; j < len; j++) {
482  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(element[j].l, cd_loop_uv_offset);
483  update |= uvedit_line_update_endpoint(luv, uv_start, &prec_start, uv_end, &prec_end);
484  }
485  if (!update) {
486  break;
487  }
488  }
489 
490  if (prec_start == UVEP_INVALID || prec_end == UVEP_INVALID) {
491  return false; /* Unable to find two endpoints. */
492  }
493 
494  float a = 0.0f; /* Similar to "slope". */
495  eUVWeldAlign tool_local = tool;
496 
497  if (tool_local == UV_STRAIGHTEN_X) {
498  if (uv_start[1] == uv_end[1]) {
499  /* Caution, different behavior outside line segment. */
500  tool_local = UV_STRAIGHTEN;
501  }
502  else {
503  a = (uv_end[0] - uv_start[0]) / (uv_end[1] - uv_start[1]);
504  }
505  }
506  else if (tool_local == UV_STRAIGHTEN_Y) {
507  if (uv_start[0] == uv_end[0]) {
508  /* Caution, different behavior outside line segment. */
509  tool_local = UV_STRAIGHTEN;
510  }
511  else {
512  a = (uv_end[1] - uv_start[1]) / (uv_end[0] - uv_start[0]);
513  }
514  }
515 
516  bool changed = false;
517  for (int j = 0; j < len; j++) {
518  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(element[j].l, cd_loop_uv_offset);
519  /* Projection of point (x, y) over line (x1, y1, x2, y2) along X axis:
520  * new_y = (y2 - y1) / (x2 - x1) * (x - x1) + y1
521  * Maybe this should be a BLI func? Or is it already existing?
522  * Could use interp_v2_v2v2, but not sure it's worth it here. */
523  if (tool_local == UV_STRAIGHTEN_X) {
524  luv->uv[0] = a * (luv->uv[1] - uv_start[1]) + uv_start[0];
525  }
526  else if (tool_local == UV_STRAIGHTEN_Y) {
527  luv->uv[1] = a * (luv->uv[0] - uv_start[0]) + uv_start[1];
528  }
529  else {
530  closest_to_line_segment_v2(luv->uv, luv->uv, uv_start, uv_end);
531  }
532  changed = true; /* TODO: Did the UV actually move? */
533  }
534  return changed;
535 }
536 
541 {
542  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
543  if (cd_loop_uv_offset == -1) {
544  return false;
545  }
546 
547  UvElementMap *element_map = BM_uv_element_map_create(bm, scene, true, false, true);
548  if (element_map == NULL) {
549  return false;
550  }
551 
552  bool changed = false;
553 
554  /* Loop backwards to simplify logic. */
555  int j1 = element_map->totalUVs;
556  for (int i = element_map->totalIslands - 1; i >= 0; --i) {
557  int j0 = element_map->islandIndices[i];
559  element_map->buf + j0, j1 - j0, cd_loop_uv_offset, tool);
560  j1 = j0;
561  }
562 
563  BM_uv_element_map_free(element_map);
564  return changed;
565 }
566 
568 {
570  ViewLayer *view_layer = CTX_data_view_layer(C);
572  const ToolSettings *ts = scene->toolsettings;
573  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
574  float cent[2], min[2], max[2];
575 
576  INIT_MINMAX2(min, max);
577 
578  uint objects_len = 0;
580  view_layer, ((View3D *)NULL), &objects_len);
581 
582  if (tool == UV_ALIGN_AUTO) {
583  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
584  Object *obedit = objects[ob_index];
585  BMEditMesh *em = BKE_editmesh_from_object(obedit);
586 
587  if (synced_selection && (em->bm->totvertsel == 0)) {
588  continue;
589  }
590 
591  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
592 
593  BMIter iter, liter;
594  BMFace *efa;
595  BMLoop *l;
596 
597  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
598  if (!uvedit_face_visible_test(scene, efa)) {
599  continue;
600  }
601 
602  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
603  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
604  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
605  minmax_v2v2_v2(min, max, luv->uv);
606  }
607  }
608  }
609  }
610  tool = (max[0] - min[0] >= max[1] - min[1]) ? UV_ALIGN_Y : UV_ALIGN_X;
611  }
612 
613  ED_uvedit_center_multi(scene, objects, objects_len, cent, 0);
614 
615  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
616  Object *obedit = objects[ob_index];
617  BMEditMesh *em = BKE_editmesh_from_object(obedit);
618  bool changed = false;
619 
620  if (synced_selection && (em->bm->totvertsel == 0)) {
621  continue;
622  }
623 
625  changed |= uvedit_uv_align_weld(scene, em->bm, tool, cent);
626  }
627 
629  changed |= uvedit_uv_straighten(scene, em->bm, tool);
630  }
631 
632  if (changed) {
633  uvedit_live_unwrap_update(sima, scene, obedit);
634  DEG_id_tag_update(obedit->data, 0);
636  }
637  }
638 
639  MEM_freeN(objects);
640 }
641 
643 {
644  uv_weld_align(C, RNA_enum_get(op->ptr, "axis"));
645 
646  return OPERATOR_FINISHED;
647 }
648 
650 {
651  static const EnumPropertyItem axis_items[] = {
652  {UV_STRAIGHTEN,
653  "ALIGN_S",
654  0,
655  "Straighten",
656  "Align UVs along the line defined by the endpoints"},
658  "ALIGN_T",
659  0,
660  "Straighten X",
661  "Align UVs along the line defined by the endpoints along the X axis"},
663  "ALIGN_U",
664  0,
665  "Straighten Y",
666  "Align UVs along the line defined by the endpoints along the Y axis"},
667  {UV_ALIGN_AUTO,
668  "ALIGN_AUTO",
669  0,
670  "Align Auto",
671  "Automatically choose the axis on which there is most alignment already"},
672  {UV_ALIGN_X, "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
673  {UV_ALIGN_Y, "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
674  {0, NULL, 0, NULL, NULL},
675  };
676 
677  /* identifiers */
678  ot->name = "Align";
679  ot->description = "Align selected UV vertices to an axis";
680  ot->idname = "UV_OT_align";
682 
683  /* api callbacks */
684  ot->exec = uv_align_exec;
686 
687  /* properties */
688  RNA_def_enum(
689  ot->srna, "axis", axis_items, UV_ALIGN_AUTO, "Axis", "Axis to align UV locations on");
690 }
691 
694 /* -------------------------------------------------------------------- */
699 {
701  ViewLayer *view_layer = CTX_data_view_layer(C);
703  const ToolSettings *ts = scene->toolsettings;
704 
705  const float threshold = RNA_float_get(op->ptr, "threshold");
706  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
707 
708  uint objects_len = 0;
710  view_layer, ((View3D *)NULL), &objects_len);
711 
712  bool *changed = MEM_callocN(sizeof(bool) * objects_len, "uv_remove_doubles_selected.changed");
713 
714  /* Maximum index of an objects[i]'s MLoopUVs in MLoopUV_arr.
715  * It helps find which MLoopUV in *MLoopUV_arr belongs to which object. */
716  uint *ob_mloopuv_max_idx = MEM_callocN(sizeof(uint) * objects_len,
717  "uv_remove_doubles_selected.ob_mloopuv_max_idx");
718 
719  /* Calculate max possible number of kdtree nodes. */
720  int uv_maxlen = 0;
721  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
722  Object *obedit = objects[ob_index];
723  BMEditMesh *em = BKE_editmesh_from_object(obedit);
724 
725  if (synced_selection && (em->bm->totvertsel == 0)) {
726  continue;
727  }
728 
729  uv_maxlen += em->bm->totloop;
730  }
731 
732  KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
733 
734  int *duplicates = NULL;
735  BLI_array_declare(duplicates);
736 
737  MLoopUV **mloopuv_arr = NULL;
738  BLI_array_declare(mloopuv_arr);
739 
740  int mloopuv_count = 0; /* Also used for *duplicates count. */
741 
742  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
743  BMIter iter, liter;
744  BMFace *efa;
745  BMLoop *l;
746  Object *obedit = objects[ob_index];
747  BMEditMesh *em = BKE_editmesh_from_object(obedit);
748 
749  if (synced_selection && (em->bm->totvertsel == 0)) {
750  continue;
751  }
752 
753  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
754 
755  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
756  if (!uvedit_face_visible_test(scene, efa)) {
757  continue;
758  }
759 
760  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
761  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
762  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
763  BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
764  BLI_array_append(duplicates, -1);
765  BLI_array_append(mloopuv_arr, luv);
766  mloopuv_count++;
767  }
768  }
769  }
770 
771  ob_mloopuv_max_idx[ob_index] = mloopuv_count - 1;
772  }
773 
774  BLI_kdtree_2d_balance(tree);
775  int found_duplicates = BLI_kdtree_2d_calc_duplicates_fast(tree, threshold, false, duplicates);
776 
777  if (found_duplicates > 0) {
778  /* Calculate average uv for duplicates. */
779  int *uv_duplicate_count = MEM_callocN(sizeof(int) * mloopuv_count,
780  "uv_remove_doubles_selected.uv_duplicate_count");
781  for (int i = 0; i < mloopuv_count; i++) {
782  if (duplicates[i] == -1) { /* If doesn't reference another */
783  uv_duplicate_count[i]++; /* self */
784  continue;
785  }
786 
787  if (duplicates[i] != i) {
788  /* If not self then accumulate uv for averaging.
789  * Self uv is already present in accumulator */
790  add_v2_v2(mloopuv_arr[duplicates[i]]->uv, mloopuv_arr[i]->uv);
791  }
792  uv_duplicate_count[duplicates[i]]++;
793  }
794 
795  for (int i = 0; i < mloopuv_count; i++) {
796  if (uv_duplicate_count[i] < 2) {
797  continue;
798  }
799 
800  mul_v2_fl(mloopuv_arr[i]->uv, 1.0f / (float)uv_duplicate_count[i]);
801  }
802  MEM_freeN(uv_duplicate_count);
803 
804  /* Update duplicated uvs. */
805  uint ob_index = 0;
806  for (int i = 0; i < mloopuv_count; i++) {
807  /* Make sure we know which object owns the MLoopUV at this index.
808  * Remember that in some cases the object will have no loop uv,
809  * thus we need the while loop, and not simply an if check. */
810  while (ob_mloopuv_max_idx[ob_index] < i) {
811  ob_index++;
812  }
813 
814  if (duplicates[i] == -1) {
815  continue;
816  }
817 
818  copy_v2_v2(mloopuv_arr[i]->uv, mloopuv_arr[duplicates[i]]->uv);
819  changed[ob_index] = true;
820  }
821 
822  for (ob_index = 0; ob_index < objects_len; ob_index++) {
823  if (changed[ob_index]) {
824  Object *obedit = objects[ob_index];
825  uvedit_live_unwrap_update(sima, scene, obedit);
826  DEG_id_tag_update(obedit->data, 0);
828  }
829  }
830  }
831 
832  BLI_kdtree_2d_free(tree);
833  BLI_array_free(mloopuv_arr);
834  BLI_array_free(duplicates);
835  MEM_freeN(changed);
836  MEM_freeN(objects);
837  MEM_freeN(ob_mloopuv_max_idx);
838 
839  return OPERATOR_FINISHED;
840 }
841 
843 {
845  ViewLayer *view_layer = CTX_data_view_layer(C);
847  const ToolSettings *ts = scene->toolsettings;
848 
849  const float threshold = RNA_float_get(op->ptr, "threshold");
850  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
851 
852  uint objects_len = 0;
854  view_layer, ((View3D *)NULL), &objects_len);
855 
856  /* Calculate max possible number of kdtree nodes. */
857  int uv_maxlen = 0;
858  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
859  Object *obedit = objects[ob_index];
860  BMEditMesh *em = BKE_editmesh_from_object(obedit);
861  uv_maxlen += em->bm->totloop;
862  }
863 
864  KDTree_2d *tree = BLI_kdtree_2d_new(uv_maxlen);
865 
866  MLoopUV **mloopuv_arr = NULL;
867  BLI_array_declare(mloopuv_arr);
868 
869  int mloopuv_count = 0;
870 
871  /* Add visible non-selected uvs to tree */
872  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
873  BMIter iter, liter;
874  BMFace *efa;
875  BMLoop *l;
876  Object *obedit = objects[ob_index];
877  BMEditMesh *em = BKE_editmesh_from_object(obedit);
878 
879  if (synced_selection && (em->bm->totvertsel == em->bm->totvert)) {
880  continue;
881  }
882 
883  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
884 
885  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
886  if (!uvedit_face_visible_test(scene, efa)) {
887  continue;
888  }
889 
890  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
891  if (!uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
892  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
893  BLI_kdtree_2d_insert(tree, mloopuv_count, luv->uv);
894  BLI_array_append(mloopuv_arr, luv);
895  mloopuv_count++;
896  }
897  }
898  }
899  }
900 
901  BLI_kdtree_2d_balance(tree);
902 
903  /* For each selected uv, find duplicate non selected uv. */
904  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
905  BMIter iter, liter;
906  BMFace *efa;
907  BMLoop *l;
908  bool changed = false;
909  Object *obedit = objects[ob_index];
910  BMEditMesh *em = BKE_editmesh_from_object(obedit);
911 
912  if (synced_selection && (em->bm->totvertsel == 0)) {
913  continue;
914  }
915 
916  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
917 
918  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
919  if (!uvedit_face_visible_test(scene, efa)) {
920  continue;
921  }
922 
923  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
924  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
925  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
926  KDTreeNearest_2d nearest;
927  const int i = BLI_kdtree_2d_find_nearest(tree, luv->uv, &nearest);
928 
929  if (i != -1 && nearest.dist < threshold) {
930  copy_v2_v2(luv->uv, mloopuv_arr[i]->uv);
931  changed = true;
932  }
933  }
934  }
935  }
936 
937  if (changed) {
938  uvedit_live_unwrap_update(sima, scene, obedit);
939  DEG_id_tag_update(obedit->data, 0);
941  }
942  }
943 
944  BLI_kdtree_2d_free(tree);
945  BLI_array_free(mloopuv_arr);
946  MEM_freeN(objects);
947 
948  return OPERATOR_FINISHED;
949 }
950 
952 {
953  if (RNA_boolean_get(op->ptr, "use_unselected")) {
955  }
956  return uv_remove_doubles_to_selected(C, op);
957 }
958 
960 {
961  /* identifiers */
962  ot->name = "Merge UVs by Distance";
963  ot->description =
964  "Selected UV vertices that are within a radius of each other are welded together";
965  ot->idname = "UV_OT_remove_doubles";
967 
968  /* api callbacks */
971 
973  "threshold",
974  0.02f,
975  0.0f,
976  10.0f,
977  "Merge Distance",
978  "Maximum distance between welded vertices",
979  0.0f,
980  1.0f);
982  ot->srna, "use_unselected", 0, "Unselected", "Merge selected to other unselected vertices");
983 }
984 
987 /* -------------------------------------------------------------------- */
992 {
994 
995  return OPERATOR_FINISHED;
996 }
997 
999 {
1000  /* identifiers */
1001  ot->name = "Weld";
1002  ot->description = "Weld selected UV vertices together";
1003  ot->idname = "UV_OT_weld";
1005 
1006  /* api callbacks */
1007  ot->exec = uv_weld_exec;
1009 }
1010 
1013 /* -------------------------------------------------------------------- */
1017 static void uv_snap_to_pixel(float uvco[2], float w, float h)
1018 {
1019  uvco[0] = roundf(uvco[0] * w) / w;
1020  uvco[1] = roundf(uvco[1] * h) / h;
1021 }
1022 
1024 {
1025  int width = 0, height = 0;
1026 
1029 }
1030 
1032  Object **objects_edit,
1033  uint objects_len,
1034  SpaceImage *sima)
1035 {
1036  return ED_uvedit_center_multi(scene, objects_edit, objects_len, sima->cursor, sima->around);
1037 }
1038 
1039 static void uv_snap_cursor_to_origin(float uvco[2])
1040 {
1041  uvco[0] = 0;
1042  uvco[1] = 0;
1043 }
1044 
1046 {
1047  SpaceImage *sima = CTX_wm_space_image(C);
1048 
1049  bool changed = false;
1050 
1051  switch (RNA_enum_get(op->ptr, "target")) {
1052  case 0:
1054  changed = true;
1055  break;
1056  case 1: {
1058  ViewLayer *view_layer = CTX_data_view_layer(C);
1059 
1060  uint objects_len = 0;
1062  view_layer, ((View3D *)NULL), &objects_len);
1063  changed = uv_snap_cursor_to_selection(scene, objects, objects_len, sima);
1064  MEM_freeN(objects);
1065  break;
1066  }
1067  case 2:
1069  changed = true;
1070  break;
1071  }
1072 
1073  if (!changed) {
1074  return OPERATOR_CANCELLED;
1075  }
1076 
1078 
1079  return OPERATOR_FINISHED;
1080 }
1081 
1083 {
1084  static const EnumPropertyItem target_items[] = {
1085  {0, "PIXELS", 0, "Pixels", ""},
1086  {1, "SELECTED", 0, "Selected", ""},
1087  {2, "ORIGIN", 0, "Origin", ""},
1088  {0, NULL, 0, NULL, NULL},
1089  };
1090 
1091  /* identifiers */
1092  ot->name = "Snap Cursor";
1093  ot->description = "Snap cursor to target type";
1094  ot->idname = "UV_OT_snap_cursor";
1096 
1097  /* api callbacks */
1099  ot->poll = ED_operator_uvedit_space_image; /* requires space image */
1100 
1101  /* properties */
1102  RNA_def_enum(
1103  ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
1104 }
1105 
1108 /* -------------------------------------------------------------------- */
1112 static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2])
1113 {
1114  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1115  BMFace *efa;
1116  BMLoop *l;
1117  BMIter iter, liter;
1118  MLoopUV *luv;
1119  bool changed = false;
1120 
1121  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1122 
1123  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1124  if (!uvedit_face_visible_test(scene, efa)) {
1125  continue;
1126  }
1127 
1128  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1129  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1130  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1131  copy_v2_v2(luv->uv, cursor);
1132  changed = true;
1133  }
1134  }
1135  }
1136 
1137  return changed;
1138 }
1139 
1140 static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2])
1141 {
1142  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1143  BMFace *efa;
1144  BMLoop *l;
1145  BMIter iter, liter;
1146  MLoopUV *luv;
1147  bool changed = false;
1148 
1149  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1150 
1151  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1152  if (!uvedit_face_visible_test(scene, efa)) {
1153  continue;
1154  }
1155 
1156  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1157  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1158  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1159  add_v2_v2(luv->uv, offset);
1160  changed = true;
1161  }
1162  }
1163  }
1164 
1165  return changed;
1166 }
1167 
1169 {
1170  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1171  BMesh *bm = em->bm;
1172  BMFace *f;
1173  BMLoop *l, *lsub;
1174  BMIter iter, liter, lsubiter;
1175  MLoopUV *luv;
1176  bool changed = false;
1177  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
1178 
1179  /* index every vert that has a selected UV using it, but only once so as to
1180  * get unique indices and to count how much to malloc */
1181  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1182  if (uvedit_face_visible_test(scene, f)) {
1184  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
1185  BM_elem_flag_set(l, BM_ELEM_TAG, uvedit_uv_select_test(scene, l, cd_loop_uv_offset));
1186  }
1187  }
1188  else {
1190  }
1191  }
1192 
1193  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1194  if (BM_elem_flag_test(f, BM_ELEM_TAG)) { /* Face: visible. */
1195  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
1196  if (BM_elem_flag_test(l, BM_ELEM_TAG)) { /* Loop: selected. */
1197  float uv[2] = {0.0f, 0.0f};
1198  int uv_tot = 0;
1199 
1200  BM_ITER_ELEM (lsub, &lsubiter, l->v, BM_LOOPS_OF_VERT) {
1201  if (BM_elem_flag_test(lsub->f, BM_ELEM_TAG) && /* Face: visible. */
1202  !BM_elem_flag_test(lsub, BM_ELEM_TAG)) /* Loop: unselected. */
1203  {
1204  luv = BM_ELEM_CD_GET_VOID_P(lsub, cd_loop_uv_offset);
1205  add_v2_v2(uv, luv->uv);
1206  uv_tot++;
1207  }
1208  }
1209 
1210  if (uv_tot) {
1211  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1212  mul_v2_v2fl(luv->uv, uv, 1.0f / (float)uv_tot);
1213  changed = true;
1214  }
1215  }
1216  }
1217  }
1218  }
1219 
1220  return changed;
1221 }
1222 
1223 static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
1224 {
1225  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1226  BMFace *efa;
1227  BMLoop *l;
1228  BMIter iter, liter;
1229  MLoopUV *luv;
1230  int width = 0, height = 0;
1231  float w, h;
1232  bool changed = false;
1233 
1234  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1235 
1237  w = (float)width;
1238  h = (float)height;
1239 
1240  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1241  if (!uvedit_face_visible_test(scene, efa)) {
1242  continue;
1243  }
1244 
1245  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1246  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1247  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1248  uv_snap_to_pixel(luv->uv, w, h);
1249  }
1250  }
1251 
1252  changed = true;
1253  }
1254 
1255  return changed;
1256 }
1257 
1259 {
1261  ViewLayer *view_layer = CTX_data_view_layer(C);
1262  SpaceImage *sima = CTX_wm_space_image(C);
1263  const ToolSettings *ts = scene->toolsettings;
1264  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1265  const int target = RNA_enum_get(op->ptr, "target");
1266  float offset[2] = {0};
1267 
1268  uint objects_len = 0;
1270  view_layer, ((View3D *)NULL), &objects_len);
1271 
1272  if (target == 2) {
1273  float center[2];
1274  if (!ED_uvedit_center_multi(scene, objects, objects_len, center, sima->around)) {
1275  MEM_freeN(objects);
1276  return OPERATOR_CANCELLED;
1277  }
1278  sub_v2_v2v2(offset, sima->cursor, center);
1279  }
1280 
1281  bool changed_multi = false;
1282  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1283  Object *obedit = objects[ob_index];
1284  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1285 
1286  if (synced_selection && (em->bm->totvertsel == 0)) {
1287  continue;
1288  }
1289 
1290  bool changed = false;
1291  switch (target) {
1292  case 0:
1293  changed = uv_snap_uvs_to_pixels(sima, scene, obedit);
1294  break;
1295  case 1:
1296  changed = uv_snap_uvs_to_cursor(scene, obedit, sima->cursor);
1297  break;
1298  case 2:
1299  changed = uv_snap_uvs_offset(scene, obedit, offset);
1300  break;
1301  case 3:
1302  changed = uv_snap_uvs_to_adjacent_unselected(scene, obedit);
1303  break;
1304  }
1305 
1306  if (changed) {
1307  changed_multi = true;
1308  uvedit_live_unwrap_update(sima, scene, obedit);
1309  DEG_id_tag_update(obedit->data, 0);
1311  }
1312  }
1313  MEM_freeN(objects);
1314 
1315  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1316 }
1317 
1319 {
1320  static const EnumPropertyItem target_items[] = {
1321  {0, "PIXELS", 0, "Pixels", ""},
1322  {1, "CURSOR", 0, "Cursor", ""},
1323  {2, "CURSOR_OFFSET", 0, "Cursor (Offset)", ""},
1324  {3, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
1325  {0, NULL, 0, NULL, NULL},
1326  };
1327 
1328  /* identifiers */
1329  ot->name = "Snap Selection";
1330  ot->description = "Snap selected UV vertices to target type";
1331  ot->idname = "UV_OT_snap_selected";
1333 
1334  /* api callbacks */
1337 
1338  /* properties */
1339  RNA_def_enum(
1340  ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
1341 }
1342 
1345 /* -------------------------------------------------------------------- */
1350 {
1352  ViewLayer *view_layer = CTX_data_view_layer(C);
1353  BMFace *efa;
1354  BMLoop *l;
1355  BMIter iter, liter;
1356  MLoopUV *luv;
1357  const ToolSettings *ts = scene->toolsettings;
1358  const bool clear = RNA_boolean_get(op->ptr, "clear");
1359  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1360 
1361  uint objects_len = 0;
1363  view_layer, ((View3D *)NULL), &objects_len);
1364 
1365  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1366  Object *obedit = objects[ob_index];
1367  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1368 
1369  bool changed = false;
1370  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1371 
1372  if (synced_selection && (em->bm->totvertsel == 0)) {
1373  continue;
1374  }
1375 
1376  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1377  if (!uvedit_face_visible_test(scene, efa)) {
1378  continue;
1379  }
1380 
1381  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1382  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1383 
1384  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
1385  changed = true;
1386  if (clear) {
1387  luv->flag &= ~MLOOPUV_PINNED;
1388  }
1389  else {
1390  luv->flag |= MLOOPUV_PINNED;
1391  }
1392  }
1393  }
1394  }
1395 
1396  if (changed) {
1399  }
1400  }
1401  MEM_freeN(objects);
1402 
1403  return OPERATOR_FINISHED;
1404 }
1405 
1407 {
1408  /* identifiers */
1409  ot->name = "Pin";
1410  ot->description =
1411  "Set/clear selected UV vertices as anchored between multiple unwrap operations";
1412  ot->idname = "UV_OT_pin";
1414 
1415  /* api callbacks */
1416  ot->exec = uv_pin_exec;
1418 
1419  /* properties */
1421  ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it");
1422 }
1423 
1426 /* -------------------------------------------------------------------- */
1430 /* Check if vertex/edge is selected or unselected based on #bool_test arg. Needed for select swap
1431  * support */
1432 #define UV_VERT_SEL_TEST(luv, bool_test) \
1433  ((((luv)->flag & MLOOPUV_VERTSEL) == MLOOPUV_VERTSEL) == bool_test)
1434 
1435 #define UV_EDGE_SEL_TEST(luv, bool_test) \
1436  ((((luv)->flag & MLOOPUV_EDGESEL) == MLOOPUV_EDGESEL) == bool_test)
1437 
1438 /* Is the specified UV face, selected or unselected depending on bool_test. */
1439 static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop_uv_offset)
1440 {
1441  BMLoop *l_iter;
1442  BMLoop *l_first;
1443 
1444  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1445  do {
1446  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset);
1447  if (!UV_EDGE_SEL_TEST(luv, select_test)) {
1448  return false;
1449  }
1450  } while ((l_iter = l_iter->next) != l_first);
1451 
1452  return true;
1453 }
1454 
1456 {
1457  ViewLayer *view_layer = CTX_data_view_layer(C);
1459  const ToolSettings *ts = scene->toolsettings;
1460  const bool swap = RNA_boolean_get(op->ptr, "unselected");
1461  const bool use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
1462 
1463  uint objects_len = 0;
1465  view_layer, ((View3D *)NULL), &objects_len);
1466 
1467  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1468  Object *ob = objects[ob_index];
1470  BMFace *efa;
1471  BMLoop *l;
1472  BMIter iter, liter;
1473  MLoopUV *luv;
1474 
1475  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1476 
1477  if (ts->uv_flag & UV_SYNC_SELECTION) {
1478  if (EDBM_mesh_hide(em, swap)) {
1479  EDBM_update(ob->data,
1480  &(const struct EDBMUpdate_Params){
1481  .calc_looptri = true,
1482  .calc_normals = false,
1483  .is_destructive = false,
1484  });
1485  }
1486  continue;
1487  }
1488 
1489  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1490  int hide = 0;
1491 
1492  if (!uvedit_face_visible_test(scene, efa)) {
1493  continue;
1494  }
1495 
1496  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1497  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1498 
1499  if (UV_VERT_SEL_TEST(luv, !swap) || UV_EDGE_SEL_TEST(luv, !swap)) {
1500  hide = 1;
1501  break;
1502  }
1503  }
1504 
1505  if (hide) {
1506  if (use_face_center) {
1507  if (em->selectmode == SCE_SELECT_FACE) {
1508  /* Deselect BMesh face if UV face is (de)selected depending on #swap. */
1509  if (bm_face_is_all_uv_sel(efa, !swap, cd_loop_uv_offset)) {
1510  BM_face_select_set(em->bm, efa, false);
1511  }
1512  uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
1513  }
1514  else {
1515  if (bm_face_is_all_uv_sel(efa, true, cd_loop_uv_offset) == !swap) {
1516  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1517  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1518  /* For both cases rely on edge sel tests, since all vert sel tests are invalid in
1519  * case of sticky selections. */
1520  if (UV_EDGE_SEL_TEST(luv, !swap) && (em->selectmode == SCE_SELECT_EDGE)) {
1521  BM_edge_select_set(em->bm, l->e, false);
1522  }
1523  else if (UV_EDGE_SEL_TEST(luv, !swap) && (em->selectmode == SCE_SELECT_VERTEX)) {
1524  BM_vert_select_set(em->bm, l->v, false);
1525  }
1526  }
1527  }
1528  if (!swap) {
1529  uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
1530  }
1531  }
1532  }
1533  else if (em->selectmode == SCE_SELECT_FACE) {
1534  /* Deselect BMesh face depending on the type of UV selectmode and the type of UV element
1535  * being considered. */
1536  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1537  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1538  if (UV_EDGE_SEL_TEST(luv, !swap) && (ts->uv_selectmode == UV_SELECT_EDGE)) {
1539  BM_face_select_set(em->bm, efa, false);
1540  break;
1541  }
1542  if (UV_VERT_SEL_TEST(luv, !swap) && (ts->uv_selectmode == UV_SELECT_VERTEX)) {
1543  BM_face_select_set(em->bm, efa, false);
1544  break;
1545  }
1546  if (ts->uv_selectmode == UV_SELECT_ISLAND) {
1547  BM_face_select_set(em->bm, efa, false);
1548  break;
1549  }
1550  }
1551  uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
1552  }
1553  else {
1554  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1555  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1556  if (UV_EDGE_SEL_TEST(luv, !swap) && (ts->uv_selectmode == UV_SELECT_EDGE)) {
1557  if (em->selectmode == SCE_SELECT_EDGE) {
1558  BM_edge_select_set(em->bm, l->e, false);
1559  }
1560  else {
1561  BM_vert_select_set(em->bm, l->v, false);
1562  BM_vert_select_set(em->bm, l->next->v, false);
1563  }
1564  }
1565  else if (UV_VERT_SEL_TEST(luv, !swap) && (ts->uv_selectmode != UV_SELECT_EDGE)) {
1566  if (em->selectmode == SCE_SELECT_EDGE) {
1567  BM_edge_select_set(em->bm, l->e, false);
1568  }
1569  else {
1570  BM_vert_select_set(em->bm, l->v, false);
1571  }
1572  }
1573  }
1574  if (!swap) {
1575  uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset);
1576  }
1577  }
1578  }
1579  }
1580 
1581  /* Flush editmesh selections to ensure valid selection states. */
1582  if (em->selectmode != SCE_SELECT_FACE) {
1583  /* NOTE: Make sure correct flags are used. Previously this was done by passing
1584  * (SCE_SELECT_VERTEX | SCE_SELECT_EDGE), which doesn't work now that we support proper UV
1585  * edge selection. */
1586 
1588  }
1589 
1591 
1594  }
1595 
1596  MEM_freeN(objects);
1597 
1598  return OPERATOR_FINISHED;
1599 }
1600 
1601 #undef UV_VERT_SEL_TEST
1602 #undef UV_EDGE_SEL_TEST
1603 
1605 {
1606  /* identifiers */
1607  ot->name = "Hide Selected";
1608  ot->description = "Hide (un)selected UV vertices";
1609  ot->idname = "UV_OT_hide";
1611 
1612  /* api callbacks */
1613  ot->exec = uv_hide_exec;
1615 
1616  /* props */
1617  RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1618 }
1619 
1622 /* -------------------------------------------------------------------- */
1627 {
1628  ViewLayer *view_layer = CTX_data_view_layer(C);
1630  const ToolSettings *ts = scene->toolsettings;
1631 
1632  const bool use_face_center = (ts->uv_selectmode == UV_SELECT_FACE);
1633  const bool select = RNA_boolean_get(op->ptr, "select");
1634 
1635  uint objects_len = 0;
1637  view_layer, ((View3D *)NULL), &objects_len);
1638 
1639  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1640  Object *ob = objects[ob_index];
1642  BMFace *efa;
1643  BMLoop *l;
1644  BMIter iter, liter;
1645  MLoopUV *luv;
1646 
1647  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1648 
1649  /* NOTE: Selecting faces is delayed so that it doesn't select verts/edges and confuse certain
1650  * UV selection checks.
1651  * This creates a temporary state which breaks certain UV selection functions that do face
1652  * visibility checks internally. Current implementation handles each case separately. */
1653 
1654  /* call the mesh function if we are in mesh sync sel */
1655  if (ts->uv_flag & UV_SYNC_SELECTION) {
1656  if (EDBM_mesh_reveal(em, select)) {
1657  EDBM_update(ob->data,
1658  &(const struct EDBMUpdate_Params){
1659  .calc_looptri = true,
1660  .calc_normals = false,
1661  .is_destructive = false,
1662  });
1663  }
1664  continue;
1665  }
1666 
1667  /* NOTE(@sidd017): Supporting selections in all cases is quite difficult considering there are
1668  * at least 12 cases to look into (3 mesh select-modes + 4 uv select-modes + sticky modes).
1669  * For now we select all UV faces as sticky disabled to ensure proper UV selection states (vert
1670  * + edge flags) */
1671  if (use_face_center) {
1672  if (em->selectmode == SCE_SELECT_FACE) {
1673  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1676  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1677  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1679  }
1680  /* BM_face_select_set(em->bm, efa, true); */
1682  }
1683  }
1684  }
1685  else {
1686  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1689  int totsel = 0;
1690  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1691  if (em->selectmode == SCE_SELECT_VERTEX) {
1692  totsel += BM_elem_flag_test(l->v, BM_ELEM_SELECT);
1693  }
1694  else if (em->selectmode == SCE_SELECT_EDGE) {
1695  totsel += BM_elem_flag_test(l->e, BM_ELEM_SELECT);
1696  }
1697  }
1698 
1699  if (!totsel) {
1700  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1701  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1703  }
1704  }
1705  /* BM_face_select_set(em->bm, efa, true); */
1707  }
1708  }
1709  }
1710  }
1711  else if (em->selectmode == SCE_SELECT_FACE) {
1712  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1715  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1716  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1718  }
1719  /* BM_face_select_set(em->bm, efa, true); */
1721  }
1722  }
1723  }
1724  else {
1725  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1728  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1729  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1731  }
1732  /* BM_face_select_set(em->bm, efa, true); */
1734  }
1735  }
1736  }
1737 
1738  /* re-select tagged faces */
1740 
1743  }
1744 
1745  MEM_freeN(objects);
1746 
1747  return OPERATOR_FINISHED;
1748 }
1749 
1751 {
1752  /* identifiers */
1753  ot->name = "Reveal Hidden";
1754  ot->description = "Reveal all hidden UV vertices";
1755  ot->idname = "UV_OT_reveal";
1757 
1758  /* api callbacks */
1759  ot->exec = uv_reveal_exec;
1761 
1762  RNA_def_boolean(ot->srna, "select", true, "Select", "");
1763 }
1764 
1767 /* -------------------------------------------------------------------- */
1772 {
1773  SpaceImage *sima = CTX_wm_space_image(C);
1774 
1775  if (!sima) {
1776  return OPERATOR_CANCELLED;
1777  }
1778 
1779  RNA_float_get_array(op->ptr, "location", sima->cursor);
1780 
1781  {
1782  struct wmMsgBus *mbus = CTX_wm_message_bus(C);
1783  bScreen *screen = CTX_wm_screen(C);
1784  WM_msg_publish_rna_prop(mbus, &screen->id, sima, SpaceImageEditor, cursor_location);
1785  }
1786 
1788 
1789  /* Use pass-through to allow click-drag to transform the cursor. */
1791 }
1792 
1793 static int uv_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1794 {
1795  ARegion *region = CTX_wm_region(C);
1796  float location[2];
1797 
1798  if (region->regiontype == RGN_TYPE_WINDOW) {
1799  SpaceImage *sima = CTX_wm_space_image(C);
1800  if (sima && ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) {
1801  return OPERATOR_PASS_THROUGH;
1802  }
1803  }
1804 
1806  &region->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
1807  RNA_float_set_array(op->ptr, "location", location);
1808 
1809  return uv_set_2d_cursor_exec(C, op);
1810 }
1811 
1813 {
1814  /* identifiers */
1815  ot->name = "Set 2D Cursor";
1816  ot->description = "Set 2D cursor location";
1817  ot->idname = "UV_OT_cursor_set";
1818 
1819  /* api callbacks */
1823 
1824  /* properties */
1826  "location",
1827  2,
1828  NULL,
1829  -FLT_MAX,
1830  FLT_MAX,
1831  "Location",
1832  "Cursor location in normalized (0.0 to 1.0) coordinates",
1833  -10.0f,
1834  10.0f);
1835 }
1836 
1839 /* -------------------------------------------------------------------- */
1844 {
1846  ViewLayer *view_layer = CTX_data_view_layer(C);
1847  const bool mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
1848  const bool mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
1849  bool changed_multi = false;
1850 
1851  uint objects_len = 0;
1853  view_layer, ((View3D *)NULL), &objects_len);
1854 
1855  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1856  Object *ob = objects[ob_index];
1857  Mesh *me = (Mesh *)ob->data;
1858  BMEditMesh *em = me->edit_mesh;
1859  BMesh *bm = em->bm;
1860  BMIter iter;
1861 
1862  if (!EDBM_uv_check(em)) {
1863  continue;
1864  }
1865 
1866  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
1867  bool changed = false;
1868 
1869  BMFace *f;
1870  BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
1871  if (!uvedit_face_visible_test(scene, f)) {
1872  continue;
1873  }
1874 
1875  BMLoop *l_iter;
1876  BMLoop *l_first;
1877 
1878  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1879  do {
1880  if (l_iter == l_iter->radial_next) {
1881  continue;
1882  }
1883  if (!uvedit_edge_select_test(scene, l_iter, cd_loop_uv_offset)) {
1884  continue;
1885  }
1886 
1887  bool mark = false;
1888  BMLoop *l_other = l_iter->radial_next;
1889  do {
1890  if (!BM_loop_uv_share_edge_check(l_iter, l_other, cd_loop_uv_offset)) {
1891  mark = true;
1892  break;
1893  }
1894  } while ((l_other = l_other->radial_next) != l_iter);
1895 
1896  if (mark) {
1897  if (mark_seams) {
1899  }
1900  if (mark_sharp) {
1902  }
1903  changed = true;
1904  }
1905  } while ((l_iter = l_iter->next) != l_first);
1906  }
1907 
1908  if (changed) {
1909  changed_multi = true;
1910  DEG_id_tag_update(&me->id, 0);
1912  }
1913  }
1914  MEM_freeN(objects);
1915 
1916  return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
1917 }
1918 
1920 {
1921  /* identifiers */
1922  ot->name = "Seams from Islands";
1923  ot->description = "Set mesh seams according to island setup in the UV editor";
1924  ot->idname = "UV_OT_seams_from_islands";
1925 
1926  /* flags */
1928 
1929  /* api callbacks */
1932 
1933  RNA_def_boolean(ot->srna, "mark_seams", 1, "Mark Seams", "Mark boundary edges as seams");
1934  RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
1935 }
1936 
1939 /* -------------------------------------------------------------------- */
1944 {
1946  ViewLayer *view_layer = CTX_data_view_layer(C);
1947  const ToolSettings *ts = scene->toolsettings;
1948 
1949  BMFace *efa;
1950  BMLoop *loop;
1951  BMIter iter, liter;
1952 
1953  const bool flag_set = !RNA_boolean_get(op->ptr, "clear");
1954  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1955 
1956  uint objects_len = 0;
1958  view_layer, ((View3D *)NULL), &objects_len);
1959 
1960  bool changed = false;
1961 
1962  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1963  Object *ob = objects[ob_index];
1964  Mesh *me = (Mesh *)ob->data;
1965  BMEditMesh *em = me->edit_mesh;
1966  BMesh *bm = em->bm;
1967 
1968  if (synced_selection && (bm->totedgesel == 0)) {
1969  continue;
1970  }
1971 
1972  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
1973 
1974  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
1975  if (uvedit_face_visible_test(scene, efa)) {
1976  BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
1977  if (uvedit_edge_select_test(scene, loop, cd_loop_uv_offset)) {
1978  BM_elem_flag_set(loop->e, BM_ELEM_SEAM, flag_set);
1979  changed = true;
1980  }
1981  }
1982  }
1983  }
1984 
1985  if (changed) {
1986  DEG_id_tag_update(&me->id, 0);
1988  }
1989  }
1990 
1991  if (changed) {
1992  ED_uvedit_live_unwrap(scene, objects, objects_len);
1993  }
1994 
1995  MEM_freeN(objects);
1996 
1997  return OPERATOR_FINISHED;
1998 }
1999 
2000 static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2001 {
2002  uiPopupMenu *pup;
2003  uiLayout *layout;
2004 
2005  if (RNA_struct_property_is_set(op->ptr, "clear")) {
2006  return uv_mark_seam_exec(C, op);
2007  }
2008 
2009  pup = UI_popup_menu_begin(C, IFACE_("Edges"), ICON_NONE);
2010  layout = UI_popup_menu_layout(pup);
2011 
2013  uiItemBooleanO(layout,
2015  ICON_NONE,
2016  op->type->idname,
2017  "clear",
2018  false);
2019  uiItemBooleanO(layout,
2021  ICON_NONE,
2022  op->type->idname,
2023  "clear",
2024  true);
2025 
2026  UI_popup_menu_end(C, pup);
2027 
2028  return OPERATOR_INTERFACE;
2029 }
2030 
2032 {
2033  /* identifiers */
2034  ot->name = "Mark Seam";
2035  ot->description = "Mark selected UV edges as seams";
2036  ot->idname = "UV_OT_mark_seam";
2037 
2038  /* flags */
2040 
2041  /* api callbacks */
2045 
2046  RNA_def_boolean(ot->srna, "clear", false, "Clear Seams", "Clear instead of marking seams");
2047 }
2048 
2051 /* -------------------------------------------------------------------- */
2056 {
2057  /* uvedit_select.c */
2074 
2077 
2079 
2084 
2090 
2101 
2104 
2106 }
2107 
2109 {
2110  wmOperatorType *ot;
2111  wmOperatorTypeMacro *otmacro;
2112 
2113  ot = WM_operatortype_append_macro("UV_OT_rip_move",
2114  "UV Rip Move",
2115  "Unstitch UV's and move the result",
2117  WM_operatortype_macro_define(ot, "UV_OT_rip");
2118  otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
2119  RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false);
2120  RNA_boolean_set(otmacro->ptr, "mirror", false);
2121 }
2122 
2124 {
2125  wmKeyMap *keymap;
2126 
2127  keymap = WM_keymap_ensure(keyconf, "UV Editor", 0, 0);
2128  keymap->poll = ED_operator_uvedit;
2129 }
2130 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct bScreen * CTX_wm_screen(const bContext *C)
Definition: context.c:733
struct wmMsgBus * CTX_wm_message_bus(const bContext *C)
Definition: context.c:770
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct SpaceImage * CTX_wm_space_image(const bContext *C)
Definition: context.c:824
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:58
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:550
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:687
#define SH_NODE_TEX_ENVIRONMENT
Definition: BKE_node.h:1128
struct bNode * nodeGetActiveTexture(struct bNodeTree *ntree)
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:98
#define BLI_array_declare(arr)
Definition: BLI_array.h:50
#define BLI_array_free(arr)
Definition: BLI_array.h:113
A KD-tree for nearest neighbor search.
float 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:357
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
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:890
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:244
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:67
#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:19
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ CD_MLOOPUV
@ MLOOPUV_PINNED
@ MLOOPUV_VERTSEL
@ MLOOPUV_EDGESEL
Object is a sort of wrapper for general info.
@ OB_MESH
#define UV_SELECT_EDGE
#define UV_SELECT_FACE
#define SCE_SELECT_FACE
#define UV_SYNC_SELECTION
#define SCE_SELECT_VERTEX
#define UV_SELECT_ISLAND
#define UV_SELECT_VERTEX
#define SCE_SELECT_EDGE
@ RGN_TYPE_WINDOW
@ SI_LIVE_UNWRAP
@ V3D_AROUND_CENTER_BOUNDS
@ V3D_AROUND_CURSOR
@ OPERATOR_CANCELLED
@ OPERATOR_INTERFACE
@ OPERATOR_FINISHED
@ OPERATOR_PASS_THROUGH
bool ED_space_image_show_cache_and_mval_over(const struct SpaceImage *sima, struct ARegion *region, const int mval[2])
void ED_space_image_get_size(struct SpaceImage *sima, int *r_width, int *r_height)
Definition: image_edit.c:201
bool ED_space_image_cursor_poll(struct bContext *C)
Definition: image_edit.c:526
struct UvElementMap * BM_uv_element_map_create(struct BMesh *bm, const struct Scene *scene, bool uv_selected, bool use_winding, bool do_islands)
void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params)
bool EDBM_mesh_hide(struct BMEditMesh *em, bool swap)
bool EDBM_mesh_reveal(struct BMEditMesh *em, bool select)
bool EDBM_uv_check(struct BMEditMesh *em)
void BM_uv_element_map_free(struct UvElementMap *element_map)
void ED_node_tree_propagate_change(const struct bContext *C, struct Main *bmain, struct bNodeTree *ntree)
bool ED_operator_uvedit_space_image(struct bContext *C)
Definition: screen_ops.c:564
bool ED_operator_uvedit(struct bContext *C)
Definition: screen_ops.c:557
void ED_uvedit_live_unwrap_begin(struct Scene *scene, struct Object *obedit)
bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset)
void ED_uvedit_live_unwrap(const struct Scene *scene, struct Object **objects, int objects_len)
void ED_uvedit_live_unwrap_re_solve(void)
void uvedit_face_select_disable(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, int cd_loop_uv_offset)
bool uvedit_edge_select_test(const struct Scene *scene, struct BMLoop *l, 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 height
_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
Read Guarded memory(de)allocation.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block SH_NODE_TEX_IMAGE
#define C
Definition: RandGen.cpp:25
void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *opname, const char *propname, int value)
struct uiLayout * UI_popup_menu_layout(uiPopupMenu *pup)
void UI_popup_menu_end(struct bContext *C, struct uiPopupMenu *pup)
void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext)
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()
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
#define ND_SPACE_IMAGE
Definition: WM_types.h:465
#define ND_SELECT
Definition: WM_types.h:455
@ WM_OP_EXEC_DEFAULT
Definition: WM_types.h:208
#define NC_SPACE
Definition: WM_types.h:342
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_FACE
Definition: bmesh_class.h:386
@ 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_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_select_mode_flush(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_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_select_history_validate(BMesh *bm)
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)
ATTR_WARN_UNUSED_RESULT const void * element
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
int len
Definition: draw_manager.c:108
void * tree
bNodeTree * ntree
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
static void clear(Message *msg)
Definition: msgfmt.c:278
static unsigned a[3]
Definition: RandGen.cpp:78
static void update(bNodeTree *ntree)
return ret
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
Definition: rna_access.c:4980
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:5301
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
Definition: rna_access.c:4992
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
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:3836
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
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:3862
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:3783
#define min(a, b)
Definition: sort.c:35
short regiontype
short selectmode
Definition: BKE_editmesh.h:52
struct BMesh * bm
Definition: BKE_editmesh.h:40
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
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:121
struct bNodeTree * nodetree
struct BMEditMesh * edit_mesh
CustomData ldata
void * data
struct ToolSettings * toolsettings
float cursor[2]
struct UvElement * buf
int mval[2]
Definition: WM_types.h:684
bool(* poll)(struct bContext *)
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct wmOperatorType * type
struct PointerRNA * ptr
float max
void UV_OT_rip(struct wmOperatorType *ot)
Definition: uvedit_rip.c:945
void UV_OT_select_linked(struct wmOperatorType *ot)
void UV_OT_select_similar(struct wmOperatorType *ot)
bool uvedit_select_is_any_selected_multi(const struct Scene *scene, struct Object **objects, uint objects_len)
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)
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_select_mode(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:753
void UV_OT_shortest_path_select(struct wmOperatorType *ot)
Definition: uvedit_path.c:852
void UV_OT_cube_project(struct wmOperatorType *ot)
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:2123
void uv_poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
Definition: uvedit_ops.c:192
static void UV_OT_snap_cursor(wmOperatorType *ot)
Definition: uvedit_ops.c:1082
static eUVEndPointPrecedence uvedit_line_update_get_precedence(const MLoopUV *luv)
Definition: uvedit_ops.c:421
static void UV_OT_cursor_set(wmOperatorType *ot)
Definition: uvedit_ops.c:1812
void ED_operatormacros_uvedit(void)
Definition: uvedit_ops.c:2108
eUVEndPointPrecedence
Definition: uvedit_ops.c:415
@ UVEP_PINNED
Definition: uvedit_ops.c:418
@ UVEP_SELECTED
Definition: uvedit_ops.c:417
@ UVEP_INVALID
Definition: uvedit_ops.c:416
static int uv_snap_selection_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1258
bool ED_uvedit_center_from_pivot(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, float r_center[2], char mode)
Definition: uvedit_ops.c:353
static int uv_mark_seam_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: uvedit_ops.c:2000
static int uv_remove_doubles_to_selected(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:698
static int uv_remove_doubles_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:951
bool ED_uvedit_center_multi(const Scene *scene, Object **objects_edit, uint objects_len, float cent[2], char mode)
Definition: uvedit_ops.c:296
static void UV_OT_align(wmOperatorType *ot)
Definition: uvedit_ops.c:649
static bool uvedit_uv_straighten(Scene *scene, BMesh *bm, eUVWeldAlign tool)
Definition: uvedit_ops.c:540
static int uv_hide_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1455
static void uv_snap_cursor_to_origin(float uvco[2])
Definition: uvedit_ops.c:1039
static void UV_OT_mark_seam(wmOperatorType *ot)
Definition: uvedit_ops.c:2031
static void UV_OT_weld(wmOperatorType *ot)
Definition: uvedit_ops.c:998
static bool uv_snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
Definition: uvedit_ops.c:1223
static bool uv_snap_uvs_to_cursor(Scene *scene, Object *obedit, const float cursor[2])
Definition: uvedit_ops.c:1112
bool ED_uvedit_test(Object *obedit)
Definition: uvedit_ops.c:64
static void uv_weld_align(bContext *C, eUVWeldAlign tool)
Definition: uvedit_ops.c:567
static bool ED_uvedit_median_multi(const Scene *scene, Object **objects_edit, uint objects_len, float co[2])
Definition: uvedit_ops.c:257
static bool uvedit_uv_align_weld(Scene *scene, BMesh *bm, const eUVWeldAlign tool, const float cent[2])
Definition: uvedit_ops.c:375
void ED_uvedit_select_all(BMesh *bm)
Definition: uvedit_ops.c:240
static bool uvedit_line_update_endpoint(const MLoopUV *luv, float uv_a[2], eUVEndPointPrecedence *prec_a, float uv_b[2], eUVEndPointPrecedence *prec_b)
Definition: uvedit_ops.c:434
static void UV_OT_snap_selected(wmOperatorType *ot)
Definition: uvedit_ops.c:1318
static int uv_weld_exec(bContext *C, wmOperator *UNUSED(op))
Definition: uvedit_ops.c:991
static void uv_snap_to_pixel(float uvco[2], float w, float h)
Definition: uvedit_ops.c:1017
static bool uv_snap_uvs_to_adjacent_unselected(Scene *scene, Object *obedit)
Definition: uvedit_ops.c:1168
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:317
static int uv_snap_cursor_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1045
static void UV_OT_reveal(wmOperatorType *ot)
Definition: uvedit_ops.c:1750
static bool uv_snap_uvs_offset(Scene *scene, Object *obedit, const float offset[2])
Definition: uvedit_ops.c:1140
eUVWeldAlign
Definition: uvedit_ops.c:365
@ UV_ALIGN_Y
Definition: uvedit_ops.c:371
@ UV_STRAIGHTEN
Definition: uvedit_ops.c:366
@ UV_WELD
Definition: uvedit_ops.c:372
@ UV_STRAIGHTEN_Y
Definition: uvedit_ops.c:368
@ UV_ALIGN_AUTO
Definition: uvedit_ops.c:369
@ UV_ALIGN_X
Definition: uvedit_ops.c:370
@ UV_STRAIGHTEN_X
Definition: uvedit_ops.c:367
#define UV_EDGE_SEL_TEST(luv, bool_test)
Definition: uvedit_ops.c:1435
void ED_operatortypes_uvedit(void)
Definition: uvedit_ops.c:2055
static bool uvedit_uv_straighten_elements(const UvElement *element, const int len, const int cd_loop_uv_offset, const eUVWeldAlign tool)
Definition: uvedit_ops.c:468
static int uv_align_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:642
static void UV_OT_hide(wmOperatorType *ot)
Definition: uvedit_ops.c:1604
static int uv_seams_from_islands_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1843
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:109
static bool uv_snap_cursor_to_selection(Scene *scene, Object **objects_edit, uint objects_len, SpaceImage *sima)
Definition: uvedit_ops.c:1031
static void uv_snap_cursor_to_pixels(SpaceImage *sima)
Definition: uvedit_ops.c:1023
static int uv_pin_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1349
void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
Definition: uvedit_ops.c:177
static bool bm_face_is_all_uv_sel(BMFace *f, bool select_test, const int cd_loop_uv_offset)
Definition: uvedit_ops.c:1439
static void UV_OT_seams_from_islands(wmOperatorType *ot)
Definition: uvedit_ops.c:1919
void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
Definition: uvedit_ops.c:160
#define UV_VERT_SEL_TEST(luv, bool_test)
Definition: uvedit_ops.c:1432
static int UNUSED_FUNCTION() ED_operator_uvmap_mesh(bContext *C)
Definition: uvedit_ops.c:83
static void UV_OT_pin(wmOperatorType *ot)
Definition: uvedit_ops.c:1406
bool ED_uvedit_minmax(const Scene *scene, Object *obedit, float r_min[2], float r_max[2])
Definition: uvedit_ops.c:235
static int uv_reveal_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1626
static int uv_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: uvedit_ops.c:1793
static int uv_mark_seam_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1943
static int uv_remove_doubles_to_unselected(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:842
static void UV_OT_remove_doubles(wmOperatorType *ot)
Definition: uvedit_ops.c:959
static bool is_image_texture_node(bNode *node)
Definition: uvedit_ops.c:104
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
Definition: uvedit_ops.c:1771
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:201
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3479
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 *))