Blender  V3.3
uvedit_unwrap_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_camera_types.h"
15 #include "DNA_mesh_types.h"
16 #include "DNA_meshdata_types.h"
17 #include "DNA_modifier_types.h"
18 #include "DNA_object_types.h"
19 #include "DNA_scene_types.h"
20 
21 #include "BLI_alloca.h"
22 #include "BLI_array.h"
23 #include "BLI_linklist.h"
24 #include "BLI_listbase.h"
25 #include "BLI_math.h"
26 #include "BLI_memarena.h"
27 #include "BLI_string.h"
28 #include "BLI_utildefines.h"
29 #include "BLI_uvproject.h"
30 
31 #include "BLT_translation.h"
32 
33 #include "BKE_cdderivedmesh.h"
34 #include "BKE_context.h"
35 #include "BKE_customdata.h"
36 #include "BKE_editmesh.h"
37 #include "BKE_image.h"
38 #include "BKE_layer.h"
39 #include "BKE_lib_id.h"
40 #include "BKE_main.h"
41 #include "BKE_material.h"
42 #include "BKE_mesh.h"
43 #include "BKE_report.h"
44 #include "BKE_scene.h"
45 #include "BKE_subsurf.h"
46 
47 #include "DEG_depsgraph.h"
48 
49 #include "GEO_uv_parametrizer.h"
50 
51 #include "PIL_time.h"
52 
53 #include "UI_interface.h"
54 #include "UI_view2d.h"
55 
56 #include "ED_image.h"
57 #include "ED_mesh.h"
58 #include "ED_screen.h"
59 #include "ED_uvedit.h"
60 #include "ED_view3d.h"
61 
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64 
65 #include "WM_api.h"
66 #include "WM_types.h"
67 
68 #include "uvedit_intern.h"
69 
70 /* -------------------------------------------------------------------- */
74 static void modifier_unwrap_state(Object *obedit, const Scene *scene, bool *r_use_subsurf)
75 {
76  ModifierData *md;
77  bool subsurf = (scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF) != 0;
78 
79  md = obedit->modifiers.first;
80 
81  /* subsurf will take the modifier settings only if modifier is first or right after mirror */
82  if (subsurf) {
83  if (md && md->type == eModifierType_Subsurf) {
84  subsurf = true;
85  }
86  else {
87  subsurf = false;
88  }
89  }
90 
91  *r_use_subsurf = subsurf;
92 }
93 
94 static bool ED_uvedit_ensure_uvs(Object *obedit)
95 {
96  if (ED_uvedit_test(obedit)) {
97  return 1;
98  }
99 
100  BMEditMesh *em = BKE_editmesh_from_object(obedit);
101  BMFace *efa;
102  BMIter iter;
103  int cd_loop_uv_offset;
104 
105  if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
106  ED_mesh_uv_add(obedit->data, NULL, true, true, NULL);
107  }
108 
109  /* Happens when there are no faces. */
110  if (!ED_uvedit_test(obedit)) {
111  return 0;
112  }
113 
114  cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
115 
116  /* select new UV's (ignore UV_SYNC_SELECTION in this case) */
117  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
118  BMIter liter;
119  BMLoop *l;
120 
121  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
122  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
124  }
125  }
126 
127  return 1;
128 }
129 
132 /* -------------------------------------------------------------------- */
137  bool use_active,
138  struct UVMapUDIM_Params *udim_params)
139 {
140  memset(udim_params, 0, sizeof(*udim_params));
141 
142  udim_params->grid_shape[0] = 1;
143  udim_params->grid_shape[1] = 1;
144  udim_params->target_udim = 0;
145  udim_params->use_target_udim = false;
146 
147  if (sima == NULL) {
148  return false;
149  }
150 
151  udim_params->image = sima->image;
152  udim_params->grid_shape[0] = sima->tile_grid_shape[0];
153  udim_params->grid_shape[1] = sima->tile_grid_shape[1];
154 
155  if (use_active) {
156  int active_udim = 1001;
157  /* NOTE: Presently, when UDIM grid and tiled image are present together, only active tile for
158  * the tiled image is considered. */
159  const Image *image = sima->image;
160  if (image && image->source == IMA_SRC_TILED) {
161  ImageTile *active_tile = BLI_findlink(&image->tiles, image->active_tile_index);
162  if (active_tile) {
163  active_udim = active_tile->tile_number;
164  }
165  }
166  else {
167  /* TODO: Support storing an active UDIM when there are no tiles present.
168  * Until then, use 2D cursor to find the active tile index for the UDIM grid. */
169  if (uv_coords_isect_udim(sima->image, sima->tile_grid_shape, sima->cursor)) {
170  int tile_number = 1001;
171  tile_number += floorf(sima->cursor[1]) * 10;
172  tile_number += floorf(sima->cursor[0]);
173  active_udim = tile_number;
174  }
175  }
176 
177  udim_params->target_udim = active_udim;
178  udim_params->use_target_udim = true;
179  }
180 
181  return true;
182 }
183 
186 /* -------------------------------------------------------------------- */
190 typedef struct UnwrapOptions {
210 
211 typedef struct UnwrapResultInfo {
215 
217 {
218  BMFace *efa;
219  BMLoop *l;
220  BMIter iter, liter;
221  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
222 
223  if (cd_loop_uv_offset == -1) {
224  return (em->bm->totfacesel != 0);
225  }
226 
227  /* verify if we have any selected uv's before unwrapping,
228  * so we can cancel the operator early */
229  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
231  if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
232  continue;
233  }
234  }
235  else if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
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  break;
242  }
243  }
244 
245  if (options->only_selected_uvs && !l) {
246  continue;
247  }
248 
249  return true;
250  }
251 
252  return false;
253 }
254 
256  Object **objects,
257  const uint objects_len,
258  const UnwrapOptions *options)
259 {
260  bool have_select = false;
261  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
262  Object *obedit = objects[ob_index];
263  BMEditMesh *em = BKE_editmesh_from_object(obedit);
264  if (uvedit_have_selection(scene, em, options)) {
265  have_select = true;
266  break;
267  }
268  }
269  return have_select;
270 }
271 
273  const int material_index,
274  float *r_aspx,
275  float *r_aspy)
276 {
277  if (UNLIKELY(material_index < 0 || material_index >= ob->totcol)) {
278  *r_aspx = 1.0f;
279  *r_aspy = 1.0f;
280  return;
281  }
282  Image *ima;
283  ED_object_get_active_image(ob, material_index + 1, &ima, NULL, NULL, NULL);
284  ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
285 }
286 
287 void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
288 {
290  BLI_assert(em != NULL);
291  bool sloppy = true;
292  bool selected = false;
293  BMFace *efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
294  if (!efa) {
295  *r_aspx = 1.0f;
296  *r_aspy = 1.0f;
297  return;
298  }
299 
300  ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy);
301 }
302 
304  BMFace *efa,
305  const UnwrapOptions *options,
306  const int cd_loop_uv_offset)
307 {
308  if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
309  return false;
310  }
311 
312  if (options->only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
313  return false;
314  }
315 
316  if (options->only_selected_uvs) {
317  BMLoop *l;
318  BMIter iter;
319  BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
320  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
321  return true;
322  }
323  }
324  return false;
325  }
326 
327  return true;
328 }
329 
330 /* Prepare unique indices for each unique pinned UV, even if it shares a BMVert.
331  */
333  const Scene *scene,
334  BMFace *efa,
335  const UnwrapOptions *options,
336  const int cd_loop_uv_offset)
337 {
338  BMIter liter;
339  BMLoop *l;
340  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
341  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
342  bool pin = luv->flag & MLOOPUV_PINNED;
343  if (options->pin_unselected && !pin) {
344  pin = !uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
345  }
346  if (pin) {
347  int bmvertindex = BM_elem_index_get(l->v);
348  GEO_uv_prepare_pin_index(handle, bmvertindex, luv->uv);
349  }
350  }
351 }
352 
354  const Scene *scene,
355  BMFace *efa,
356  ParamKey face_index,
357  const UnwrapOptions *options,
358  const int cd_loop_uv_offset)
359 {
360  ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
361  bool *pin = BLI_array_alloca(pin, efa->len);
362  bool *select = BLI_array_alloca(select, efa->len);
363  const float **co = BLI_array_alloca(co, efa->len);
364  float **uv = BLI_array_alloca(uv, efa->len);
365  int i;
366 
367  BMIter liter;
368  BMLoop *l;
369 
370  /* let parametrizer split the ngon, it can make better decisions
371  * about which split is best for unwrapping than poly-fill. */
372  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
373  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
374 
375  vkeys[i] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv);
376  co[i] = l->v->co;
377  uv[i] = luv->uv;
378  pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
379  select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
380  if (options->pin_unselected && !select[i]) {
381  pin[i] = true;
382  }
383  }
384 
385  GEO_uv_parametrizer_face_add(handle, face_index, i, vkeys, co, uv, pin, select);
386 }
387 
388 /* Set seams on UV Parametrizer based on options. */
390  BMesh *bm,
391  const UnwrapOptions *options)
392 {
393  if (options->topology_from_uvs && !options->topology_from_uvs_use_seams) {
394  return; /* Seams are not required with these options. */
395  }
396 
397  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
398  if (cd_loop_uv_offset == -1) {
399  return; /* UVs aren't present on BMesh. Nothing to do. */
400  }
401 
402  BMEdge *edge;
403  BMIter iter;
404  BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
405  if (!BM_elem_flag_test(edge, BM_ELEM_SEAM)) {
406  continue; /* No seam on this edge, nothing to do. */
407  }
408 
409  /* Pinned vertices might have more than one ParamKey per BMVert.
410  * Check all the BM_LOOPS_OF_EDGE to find all the ParamKeys.
411  */
412  BMLoop *l;
413  BMIter liter;
414  BM_ITER_ELEM (l, &liter, edge, BM_LOOPS_OF_EDGE) {
415  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
416  MLoopUV *luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset);
417  ParamKey vkeys[2];
418  vkeys[0] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv);
419  vkeys[1] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->next->v), luv_next->uv);
420 
421  /* Set the seam. */
422  GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
423  }
424  }
425 }
426 
427 /*
428  * Version of #construct_param_handle_multi with a separate BMesh parameter.
429  */
431  Object *ob,
432  BMesh *bm,
433  const UnwrapOptions *options,
434  UnwrapResultInfo *result_info)
435 {
436  BMFace *efa;
437  BMIter iter;
438  int i;
439 
441 
442  if (options->correct_aspect) {
443  float aspx, aspy;
444 
445  ED_uvedit_get_aspect(ob, &aspx, &aspy);
446 
447  if (aspx != aspy) {
448  GEO_uv_parametrizer_aspect_ratio(handle, aspx, aspy);
449  }
450  }
451 
452  /* we need the vert indices */
454 
455  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
456  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
457  if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
458  uvedit_prepare_pinned_indices(handle, scene, efa, options, cd_loop_uv_offset);
459  }
460  }
461 
462  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
463  if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
464  construct_param_handle_face_add(handle, scene, efa, i, options, cd_loop_uv_offset);
465  }
466  }
467 
469 
471  options->fill_holes,
472  options->topology_from_uvs,
473  result_info ? &result_info->count_failed : NULL);
474 
475  return handle;
476 }
477 
482  Object **objects,
483  const uint objects_len,
484  const UnwrapOptions *options)
485 {
486  BMFace *efa;
487  BMIter iter;
488  int i;
489 
491 
492  if (options->correct_aspect) {
493  Object *ob = objects[0];
494  float aspx, aspy;
495 
496  ED_uvedit_get_aspect(ob, &aspx, &aspy);
497  if (aspx != aspy) {
498  GEO_uv_parametrizer_aspect_ratio(handle, aspx, aspy);
499  }
500  }
501 
502  /* we need the vert indices */
503  EDBM_mesh_elem_index_ensure_multi(objects, objects_len, BM_VERT);
504 
505  int offset = 0;
506 
507  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
508  Object *obedit = objects[ob_index];
509  BMEditMesh *em = BKE_editmesh_from_object(obedit);
510  BMesh *bm = em->bm;
511 
512  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
513 
514  if (cd_loop_uv_offset == -1) {
515  continue;
516  }
517 
518  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
519  if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
520  uvedit_prepare_pinned_indices(handle, scene, efa, options, cd_loop_uv_offset);
521  }
522  }
523 
524  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
525  if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
527  handle, scene, efa, i + offset, options, cd_loop_uv_offset);
528  }
529  }
530 
532 
533  offset += bm->totface;
534  }
535 
536  GEO_uv_parametrizer_construct_end(handle, options->fill_holes, options->topology_from_uvs, NULL);
537 
538  return handle;
539 }
540 
542  const int cd_loop_uv_offset,
543  BMFace *efa,
544  int index,
545  float **r_uv,
546  bool *r_pin,
547  bool *r_select)
548 {
549  BMLoop *l;
550  BMIter liter;
551  MLoopUV *luv;
552 
553  *r_uv = NULL;
554  *r_pin = 0;
555  *r_select = 1;
556 
557  if (index == ORIGINDEX_NONE) {
558  return;
559  }
560 
561  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
562  if (BM_elem_index_get(l->v) == index) {
563  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
564  *r_uv = luv->uv;
565  *r_pin = (luv->flag & MLOOPUV_PINNED) ? 1 : 0;
566  *r_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
567  break;
568  }
569  }
570 }
571 
578  Object *ob,
579  BMEditMesh *em,
580  const UnwrapOptions *options,
581  UnwrapResultInfo *result_info)
582 {
583  /* index pointers */
584  MPoly *mpoly;
585  MLoop *mloop;
586  MEdge *edge;
587  int i;
588 
589  /* pointers to modifier data for unwrap control */
590  ModifierData *md;
591  SubsurfModifierData *smd_real;
592  /* Modifier initialization data, will control what type of subdivision will happen. */
593  SubsurfModifierData smd = {{NULL}};
594  /* Used to hold subsurfed Mesh */
595  DerivedMesh *derivedMesh, *initialDerived;
596  /* holds original indices for subsurfed mesh */
597  const int *origVertIndices, *origEdgeIndices, *origPolyIndices;
598  /* Holds vertices of subsurfed mesh */
599  MVert *subsurfedVerts;
600  MEdge *subsurfedEdges;
601  MPoly *subsurfedPolys;
602  MLoop *subsurfedLoops;
603  /* Number of vertices and faces for subsurfed mesh. */
604  int numOfEdges, numOfFaces;
605 
606  /* holds a map to editfaces for every subsurfed MFace.
607  * These will be used to get hidden/ selected flags etc. */
608  BMFace **faceMap;
609  /* similar to the above, we need a way to map edges to their original ones */
610  BMEdge **edgeMap;
611 
612  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
613 
615 
616  if (options->correct_aspect) {
617  float aspx, aspy;
618 
619  ED_uvedit_get_aspect(ob, &aspx, &aspy);
620 
621  if (aspx != aspy) {
622  GEO_uv_parametrizer_aspect_ratio(handle, aspx, aspy);
623  }
624  }
625 
626  /* number of subdivisions to perform */
627  md = ob->modifiers.first;
628  smd_real = (SubsurfModifierData *)md;
629 
630  smd.levels = smd_real->levels;
631  smd.subdivType = smd_real->subdivType;
632 
633  {
634  Mesh *me_from_em = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data);
635  initialDerived = CDDM_from_mesh(me_from_em);
636  derivedMesh = subsurf_make_derived_from_derived(
637  initialDerived, &smd, scene, NULL, SUBSURF_IN_EDIT_MODE);
638 
639  initialDerived->release(initialDerived);
640  BKE_id_free(NULL, me_from_em);
641  }
642 
643  /* get the derived data */
644  subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
645  subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
646  subsurfedPolys = derivedMesh->getPolyArray(derivedMesh);
647  subsurfedLoops = derivedMesh->getLoopArray(derivedMesh);
648 
649  origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
650  origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
651  origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX);
652 
653  numOfEdges = derivedMesh->getNumEdges(derivedMesh);
654  numOfFaces = derivedMesh->getNumPolys(derivedMesh);
655 
656  faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map");
657 
660 
661  /* map subsurfed faces to original editFaces */
662  for (i = 0; i < numOfFaces; i++) {
663  faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]);
664  }
665 
666  edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map");
667 
668  /* map subsurfed edges to original editEdges */
669  for (i = 0; i < numOfEdges; i++) {
670  /* not all edges correspond to an old edge */
671  edgeMap[i] = (origEdgeIndices[i] != ORIGINDEX_NONE) ?
672  BM_edge_at_index(em->bm, origEdgeIndices[i]) :
673  NULL;
674  }
675 
676  /* Prepare and feed faces to the solver */
677  for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) {
678  ParamKey key, vkeys[4];
679  bool pin[4], select[4];
680  const float *co[4];
681  float *uv[4];
682  BMFace *origFace = faceMap[i];
683 
685  if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN)) {
686  continue;
687  }
688  }
689  else {
690  if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) ||
691  (options->only_selected_faces && !BM_elem_flag_test(origFace, BM_ELEM_SELECT))) {
692  continue;
693  }
694  }
695 
696  mloop = &subsurfedLoops[mpoly->loopstart];
697 
698  /* We will not check for v4 here. Sub-surface faces always have 4 vertices. */
699  BLI_assert(mpoly->totloop == 4);
700  key = (ParamKey)i;
701  vkeys[0] = (ParamKey)mloop[0].v;
702  vkeys[1] = (ParamKey)mloop[1].v;
703  vkeys[2] = (ParamKey)mloop[2].v;
704  vkeys[3] = (ParamKey)mloop[3].v;
705 
706  co[0] = subsurfedVerts[mloop[0].v].co;
707  co[1] = subsurfedVerts[mloop[1].v].co;
708  co[2] = subsurfedVerts[mloop[2].v].co;
709  co[3] = subsurfedVerts[mloop[3].v].co;
710 
711  /* This is where all the magic is done.
712  * If the vertex exists in the, we pass the original uv pointer to the solver, thus
713  * flushing the solution to the edit mesh. */
715  cd_loop_uv_offset,
716  origFace,
717  origVertIndices[mloop[0].v],
718  &uv[0],
719  &pin[0],
720  &select[0]);
722  cd_loop_uv_offset,
723  origFace,
724  origVertIndices[mloop[1].v],
725  &uv[1],
726  &pin[1],
727  &select[1]);
729  cd_loop_uv_offset,
730  origFace,
731  origVertIndices[mloop[2].v],
732  &uv[2],
733  &pin[2],
734  &select[2]);
736  cd_loop_uv_offset,
737  origFace,
738  origVertIndices[mloop[3].v],
739  &uv[3],
740  &pin[3],
741  &select[3]);
742 
743  GEO_uv_parametrizer_face_add(handle, key, 4, vkeys, co, uv, pin, select);
744  }
745 
746  /* these are calculated from original mesh too */
747  for (edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) {
748  if ((edgeMap[i] != NULL) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) {
749  ParamKey vkeys[2];
750  vkeys[0] = (ParamKey)edge->v1;
751  vkeys[1] = (ParamKey)edge->v2;
752  GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
753  }
754  }
755 
757  options->fill_holes,
758  options->topology_from_uvs,
759  result_info ? &result_info->count_failed : NULL);
760 
761  /* cleanup */
763  MEM_freeN(edgeMap);
764  derivedMesh->release(derivedMesh);
765 
766  return handle;
767 }
768 
771 /* -------------------------------------------------------------------- */
775 typedef struct MinStretch {
776  const Scene *scene;
780  float blend;
781  double lasttime;
782  int i, iterations;
785 
787 {
788  const Scene *scene = CTX_data_scene(C);
789  ViewLayer *view_layer = CTX_data_view_layer(C);
790 
791  const UnwrapOptions options = {
792  .topology_from_uvs = true,
793  .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
794  .only_selected_faces = true,
795  .only_selected_uvs = true,
796  .correct_aspect = true,
797  };
798 
799  uint objects_len = 0;
801  view_layer, CTX_wm_view3d(C), &objects_len);
802 
803  if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
804  MEM_freeN(objects);
805  return false;
806  }
807 
808  MinStretch *ms = MEM_callocN(sizeof(MinStretch), "MinStretch");
809  ms->scene = scene;
810  ms->objects_edit = objects;
811  ms->objects_len = objects_len;
812  ms->blend = RNA_float_get(op->ptr, "blend");
813  ms->iterations = RNA_int_get(op->ptr, "iterations");
814  ms->i = 0;
815  ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options);
817 
819  if (ms->blend != 0.0f) {
821  }
822 
823  op->customdata = ms;
824 
825  return true;
826 }
827 
828 static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interactive)
829 {
830  MinStretch *ms = op->customdata;
832  const Scene *scene = CTX_data_scene(C);
834  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
835 
838 
839  ms->i++;
840  RNA_int_set(op->ptr, "iterations", ms->i);
841 
842  if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
843  char str[UI_MAX_DRAW_STR];
844 
846 
847  if (area) {
848  BLI_snprintf(str, sizeof(str), TIP_("Minimize Stretch. Blend %.2f"), ms->blend);
850  ED_workspace_status_text(C, TIP_("Press + and -, or scroll wheel to set blending"));
851  }
852 
854 
855  for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
856  Object *obedit = ms->objects_edit[ob_index];
857  BMEditMesh *em = BKE_editmesh_from_object(obedit);
858 
859  if (synced_selection && (em->bm->totfacesel == 0)) {
860  continue;
861  }
862 
865  }
866  }
867 }
868 
869 static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
870 {
871  MinStretch *ms = op->customdata;
873  const Scene *scene = CTX_data_scene(C);
875  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
876 
879 
880  if (ms->timer) {
882  }
883 
884  if (cancel) {
886  }
887  else {
889  }
890 
893 
894  for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
895  Object *obedit = ms->objects_edit[ob_index];
896  BMEditMesh *em = BKE_editmesh_from_object(obedit);
897 
898  if (synced_selection && (em->bm->totfacesel == 0)) {
899  continue;
900  }
901 
904  }
905 
906  MEM_freeN(ms->objects_edit);
907  MEM_freeN(ms);
908  op->customdata = NULL;
909 }
910 
912 {
913  int i, iterations;
914 
915  if (!minimize_stretch_init(C, op)) {
916  return OPERATOR_CANCELLED;
917  }
918 
919  iterations = RNA_int_get(op->ptr, "iterations");
920  for (i = 0; i < iterations; i++) {
921  minimize_stretch_iteration(C, op, false);
922  }
923  minimize_stretch_exit(C, op, false);
924 
925  return OPERATOR_FINISHED;
926 }
927 
928 static int minimize_stretch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
929 {
930  MinStretch *ms;
931 
932  if (!minimize_stretch_init(C, op)) {
933  return OPERATOR_CANCELLED;
934  }
935 
936  minimize_stretch_iteration(C, op, true);
937 
938  ms = op->customdata;
941 
942  return OPERATOR_RUNNING_MODAL;
943 }
944 
945 static int minimize_stretch_modal(bContext *C, wmOperator *op, const wmEvent *event)
946 {
947  MinStretch *ms = op->customdata;
948 
949  switch (event->type) {
950  case EVT_ESCKEY:
951  case RIGHTMOUSE:
952  minimize_stretch_exit(C, op, true);
953  return OPERATOR_CANCELLED;
954  case EVT_RETKEY:
955  case EVT_PADENTER:
956  case LEFTMOUSE:
957  minimize_stretch_exit(C, op, false);
958  return OPERATOR_FINISHED;
959  case EVT_PADPLUSKEY:
960  case WHEELUPMOUSE:
961  if (event->val == KM_PRESS) {
962  if (ms->blend < 0.95f) {
963  ms->blend += 0.1f;
964  ms->lasttime = 0.0f;
965  RNA_float_set(op->ptr, "blend", ms->blend);
966  minimize_stretch_iteration(C, op, true);
967  }
968  }
969  break;
970  case EVT_PADMINUS:
971  case WHEELDOWNMOUSE:
972  if (event->val == KM_PRESS) {
973  if (ms->blend > 0.05f) {
974  ms->blend -= 0.1f;
975  ms->lasttime = 0.0f;
976  RNA_float_set(op->ptr, "blend", ms->blend);
977  minimize_stretch_iteration(C, op, true);
978  }
979  }
980  break;
981  case TIMER:
982  if (ms->timer == event->customdata) {
983  double start = PIL_check_seconds_timer();
984 
985  do {
986  minimize_stretch_iteration(C, op, true);
987  } while (PIL_check_seconds_timer() - start < 0.01);
988  }
989  break;
990  }
991 
992  if (ms->iterations && ms->i >= ms->iterations) {
993  minimize_stretch_exit(C, op, false);
994  return OPERATOR_FINISHED;
995  }
996 
997  return OPERATOR_RUNNING_MODAL;
998 }
999 
1001 {
1002  minimize_stretch_exit(C, op, true);
1003 }
1004 
1006 {
1007  /* identifiers */
1008  ot->name = "Minimize Stretch";
1009  ot->idname = "UV_OT_minimize_stretch";
1011  ot->description = "Reduce UV stretching by relaxing angles";
1012 
1013  /* api callbacks */
1019 
1020  /* properties */
1022  "fill_holes",
1023  1,
1024  "Fill Holes",
1025  "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and "
1026  "preserve symmetry");
1028  "blend",
1029  0.0f,
1030  0.0f,
1031  1.0f,
1032  "Blend",
1033  "Blend factor between stretch minimized and original",
1034  0.0f,
1035  1.0f);
1036  RNA_def_int(ot->srna,
1037  "iterations",
1038  0,
1039  0,
1040  INT_MAX,
1041  "Iterations",
1042  "Number of iterations to run, 0 is unlimited when run interactively",
1043  0,
1044  100);
1045 }
1046 
1049 /* -------------------------------------------------------------------- */
1053 static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
1054 {
1055  const UnwrapOptions options = {
1056  .topology_from_uvs = true,
1057  .only_selected_faces = false,
1058  .only_selected_uvs = true,
1059  .fill_holes = false,
1060  .correct_aspect = false,
1061  };
1062 
1063  bool rotate = true;
1064  bool ignore_pinned = false;
1065 
1067  GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
1068  GEO_uv_parametrizer_flush(handle);
1070 }
1071 
1079  Object **objects,
1080  const uint objects_len,
1081  const UnwrapOptions *options,
1082  bool rotate,
1083  bool ignore_pinned)
1084 {
1085  ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options);
1086  GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
1087  GEO_uv_parametrizer_flush(handle);
1089 
1090  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1091  Object *obedit = objects[ob_index];
1094  }
1095 }
1096 
1097 /* Packing targets. */
1098 enum {
1101 };
1102 
1104 {
1105  ViewLayer *view_layer = CTX_data_view_layer(C);
1106  const Scene *scene = CTX_data_scene(C);
1107  const SpaceImage *sima = CTX_wm_space_image(C);
1108 
1109  const UnwrapOptions options = {
1110  .topology_from_uvs = true,
1111  .only_selected_faces = true,
1112  .only_selected_uvs = true,
1113  .fill_holes = false,
1114  .correct_aspect = true,
1115  };
1116 
1117  uint objects_len = 0;
1119  view_layer, CTX_wm_view3d(C), &objects_len);
1120 
1121  /* Early exit in case no UVs are selected. */
1122  if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
1123  MEM_freeN(objects);
1124  return OPERATOR_CANCELLED;
1125  }
1126 
1127  /* RNA props */
1128  const bool rotate = RNA_boolean_get(op->ptr, "rotate");
1129  const int udim_source = RNA_enum_get(op->ptr, "udim_source");
1130  if (RNA_struct_property_is_set(op->ptr, "margin")) {
1131  scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
1132  }
1133  else {
1134  RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
1135  }
1136 
1137  struct UVMapUDIM_Params udim_params;
1138  const bool use_active = (udim_source == PACK_UDIM_SRC_ACTIVE);
1139  const bool use_udim_params = ED_uvedit_udim_params_from_image_space(
1140  sima, use_active, &udim_params);
1141 
1143  objects,
1144  objects_len,
1145  use_udim_params ? &udim_params : NULL,
1146  &(struct UVPackIsland_Params){
1147  .rotate = rotate,
1148  .rotate_align_axis = -1,
1149  .only_selected_uvs = true,
1150  .only_selected_faces = true,
1151  .correct_aspect = true,
1152  });
1153 
1154  MEM_freeN(objects);
1155  return OPERATOR_FINISHED;
1156 }
1157 
1159 {
1160  static const EnumPropertyItem pack_target[] = {
1161  {PACK_UDIM_SRC_CLOSEST, "CLOSEST_UDIM", 0, "Closest UDIM", "Pack islands to closest UDIM"},
1163  "ACTIVE_UDIM",
1164  0,
1165  "Active UDIM",
1166  "Pack islands to active UDIM image tile or UDIM grid tile where 2D cursor is located"},
1167  {0, NULL, 0, NULL, NULL},
1168  };
1169  /* identifiers */
1170  ot->name = "Pack Islands";
1171  ot->idname = "UV_OT_pack_islands";
1172  ot->description =
1173  "Transform all islands so that they fill up the UV/UDIM space as much as possible";
1174 
1176 
1177  /* api callbacks */
1180 
1181  /* properties */
1182  RNA_def_enum(ot->srna, "udim_source", pack_target, PACK_UDIM_SRC_CLOSEST, "Pack to", "");
1183  RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
1185  ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
1186 }
1187 
1190 /* -------------------------------------------------------------------- */
1195 {
1196  const Scene *scene = CTX_data_scene(C);
1197  ViewLayer *view_layer = CTX_data_view_layer(C);
1199  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1200 
1201  const UnwrapOptions options = {
1202  .topology_from_uvs = true,
1203  .only_selected_faces = true,
1204  .only_selected_uvs = true,
1205  .fill_holes = false,
1206  .correct_aspect = true,
1207  };
1208 
1209  uint objects_len = 0;
1211  view_layer, CTX_wm_view3d(C), &objects_len);
1212 
1213  if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
1214  MEM_freeN(objects);
1215  return OPERATOR_CANCELLED;
1216  }
1217 
1218  /* RNA props */
1219  const bool scale_uv = RNA_boolean_get(op->ptr, "scale_uv");
1220  const bool shear = RNA_boolean_get(op->ptr, "shear");
1221 
1222  ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options);
1223  GEO_uv_parametrizer_average(handle, false, scale_uv, shear);
1224  GEO_uv_parametrizer_flush(handle);
1226 
1227  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1228  Object *obedit = objects[ob_index];
1229  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1230 
1231  if (synced_selection && (em->bm->totvertsel == 0)) {
1232  continue;
1233  }
1234 
1237  }
1238  MEM_freeN(objects);
1239  return OPERATOR_FINISHED;
1240 }
1241 
1243 {
1244  /* identifiers */
1245  ot->name = "Average Islands Scale";
1246  ot->idname = "UV_OT_average_islands_scale";
1247  ot->description = "Average the size of separate UV islands, based on their area in 3D space";
1248 
1250 
1251  /* api callbacks */
1254 
1255  /* properties */
1256  RNA_def_boolean(ot->srna, "scale_uv", false, "Non-Uniform", "Scale U and V independently");
1257  RNA_def_boolean(ot->srna, "shear", false, "Shear", "Reduce shear within islands");
1258 }
1259 
1262 /* -------------------------------------------------------------------- */
1266 static struct {
1270 
1272 {
1273  ParamHandle *handle = NULL;
1274  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1275  const bool abf = (scene->toolsettings->unwrapper == 0);
1276  bool use_subsurf;
1277 
1278  modifier_unwrap_state(obedit, scene, &use_subsurf);
1279 
1280  if (!ED_uvedit_test(obedit)) {
1281  return;
1282  }
1283 
1284  const UnwrapOptions options = {
1285  .topology_from_uvs = false,
1286  .only_selected_faces = false,
1287  .only_selected_uvs = false,
1288  .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
1289  .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
1290  };
1291 
1292  if (use_subsurf) {
1293  handle = construct_param_handle_subsurfed(scene, obedit, em, &options, NULL);
1294  }
1295  else {
1296  handle = construct_param_handle(scene, obedit, em->bm, &options, NULL);
1297  }
1298 
1299  GEO_uv_parametrizer_lscm_begin(handle, true, abf);
1300 
1301  /* Create or increase size of g_live_unwrap.handles array */
1302  if (g_live_unwrap.handles == NULL) {
1303  g_live_unwrap.len_alloc = 32;
1304  g_live_unwrap.handles = MEM_mallocN(sizeof(ParamHandle *) * g_live_unwrap.len_alloc,
1305  "uvedit_live_unwrap_liveHandles");
1306  g_live_unwrap.len = 0;
1307  }
1308  if (g_live_unwrap.len >= g_live_unwrap.len_alloc) {
1309  g_live_unwrap.len_alloc *= 2;
1310  g_live_unwrap.handles = MEM_reallocN(g_live_unwrap.handles,
1311  sizeof(ParamHandle *) * g_live_unwrap.len_alloc);
1312  }
1313  g_live_unwrap.handles[g_live_unwrap.len] = handle;
1314  g_live_unwrap.len++;
1315 }
1316 
1318 {
1319  if (g_live_unwrap.handles) {
1320  for (int i = 0; i < g_live_unwrap.len; i++) {
1323  }
1324  }
1325 }
1326 
1327 void ED_uvedit_live_unwrap_end(short cancel)
1328 {
1329  if (g_live_unwrap.handles) {
1330  for (int i = 0; i < g_live_unwrap.len; i++) {
1332  if (cancel) {
1334  }
1336  }
1337  MEM_freeN(g_live_unwrap.handles);
1338  g_live_unwrap.handles = NULL;
1339  g_live_unwrap.len = 0;
1340  g_live_unwrap.len_alloc = 0;
1341  }
1342 }
1343 
1346 /* -------------------------------------------------------------------- */
1350 #define VIEW_ON_EQUATOR 0
1351 #define VIEW_ON_POLES 1
1352 #define ALIGN_TO_OBJECT 2
1353 
1354 #define POLAR_ZX 0
1355 #define POLAR_ZY 1
1356 
1357 static void uv_map_transform_calc_bounds(BMEditMesh *em, float r_min[3], float r_max[3])
1358 {
1359  BMFace *efa;
1360  BMIter iter;
1361  INIT_MINMAX(r_min, r_max);
1362  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1363  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1364  BM_face_calc_bounds_expand(efa, r_min, r_max);
1365  }
1366  }
1367 }
1368 
1369 static void uv_map_transform_calc_center_median(BMEditMesh *em, float r_center[3])
1370 {
1371  BMFace *efa;
1372  BMIter iter;
1373  uint center_accum_num = 0;
1374  zero_v3(r_center);
1375  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1376  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1377  float center[3];
1379  add_v3_v3(r_center, center);
1380  center_accum_num += 1;
1381  }
1382  }
1383  mul_v3_fl(r_center, 1.0f / (float)center_accum_num);
1384 }
1385 
1387  View3D *v3d,
1388  Object *ob,
1389  BMEditMesh *em,
1390  float r_center[3],
1391  float r_bounds[2][3])
1392 {
1393  /* only operates on the edit object - this is all that's needed now */
1394  const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS;
1395 
1396  float bounds[2][3];
1397  INIT_MINMAX(bounds[0], bounds[1]);
1398  bool is_minmax_set = false;
1399 
1400  switch (around) {
1401  case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */
1402  {
1404  is_minmax_set = true;
1405  mid_v3_v3v3(r_center, bounds[0], bounds[1]);
1406  break;
1407  }
1408  case V3D_AROUND_CENTER_MEDIAN: {
1410  break;
1411  }
1412  case V3D_AROUND_CURSOR: /* cursor center */
1413  {
1414  invert_m4_m4(ob->imat, ob->obmat);
1415  mul_v3_m4v3(r_center, ob->imat, scene->cursor.location);
1416  break;
1417  }
1418  case V3D_AROUND_ACTIVE: {
1419  BMEditSelection ese;
1420  if (BM_select_history_active_get(em->bm, &ese)) {
1421  BM_editselection_center(&ese, r_center);
1422  break;
1423  }
1425  }
1426  case V3D_AROUND_LOCAL_ORIGINS: /* object center */
1427  default:
1428  zero_v3(r_center);
1429  break;
1430  }
1431 
1432  /* if this is passed, always set! */
1433  if (r_bounds) {
1434  if (!is_minmax_set) {
1436  }
1437  copy_v3_v3(r_bounds[0], bounds[0]);
1438  copy_v3_v3(r_bounds[1], bounds[1]);
1439  }
1440 }
1441 
1442 static void uv_map_rotation_matrix_ex(float result[4][4],
1443  RegionView3D *rv3d,
1444  Object *ob,
1445  float upangledeg,
1446  float sideangledeg,
1447  float radius,
1448  const float offset[4])
1449 {
1450  float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
1451  float sideangle = 0.0f, upangle = 0.0f;
1452 
1453  /* get rotation of the current view matrix */
1454  if (rv3d) {
1455  copy_m4_m4(viewmatrix, rv3d->viewmat);
1456  }
1457  else {
1458  unit_m4(viewmatrix);
1459  }
1460 
1461  /* but shifting */
1462  zero_v3(viewmatrix[3]);
1463 
1464  /* get rotation of the current object matrix */
1465  copy_m4_m4(rotobj, ob->obmat);
1466  zero_v3(rotobj[3]);
1467 
1468  /* but shifting */
1469  add_v4_v4(rotobj[3], offset);
1470  rotobj[3][3] = 0.0f;
1471 
1472  zero_m4(rotup);
1473  zero_m4(rotside);
1474 
1475  /* Compensate front/side.. against opengl x,y,z world definition.
1476  * This is "a sledgehammer to crack a nut" (overkill), a few plus minus 1 will do here.
1477  * I wanted to keep the reason here, so we're rotating. */
1478  sideangle = (float)M_PI * (sideangledeg + 180.0f) / 180.0f;
1479  rotside[0][0] = cosf(sideangle);
1480  rotside[0][1] = -sinf(sideangle);
1481  rotside[1][0] = sinf(sideangle);
1482  rotside[1][1] = cosf(sideangle);
1483  rotside[2][2] = 1.0f;
1484 
1485  upangle = (float)M_PI * upangledeg / 180.0f;
1486  rotup[1][1] = cosf(upangle) / radius;
1487  rotup[1][2] = -sinf(upangle) / radius;
1488  rotup[2][1] = sinf(upangle) / radius;
1489  rotup[2][2] = cosf(upangle) / radius;
1490  rotup[0][0] = 1.0f / radius;
1491 
1492  /* Calculate transforms. */
1493  mul_m4_series(result, rotup, rotside, viewmatrix, rotobj);
1494 }
1495 
1496 static void uv_map_rotation_matrix(float result[4][4],
1497  RegionView3D *rv3d,
1498  Object *ob,
1499  float upangledeg,
1500  float sideangledeg,
1501  float radius)
1502 {
1503  const float offset[4] = {0};
1504  uv_map_rotation_matrix_ex(result, rv3d, ob, upangledeg, sideangledeg, radius, offset);
1505 }
1506 
1507 static void uv_map_transform(bContext *C, wmOperator *op, float rotmat[4][4])
1508 {
1509  /* context checks are messy here, making it work in both 3d view and uv editor */
1510  Object *obedit = CTX_data_edit_object(C);
1512  /* common operator properties */
1513  int align = RNA_enum_get(op->ptr, "align");
1514  int direction = RNA_enum_get(op->ptr, "direction");
1515  float radius = RNA_struct_find_property(op->ptr, "radius") ? RNA_float_get(op->ptr, "radius") :
1516  1.0f;
1517  float upangledeg, sideangledeg;
1518 
1519  if (direction == VIEW_ON_EQUATOR) {
1520  upangledeg = 90.0f;
1521  sideangledeg = 0.0f;
1522  }
1523  else {
1524  upangledeg = 0.0f;
1525  if (align == POLAR_ZY) {
1526  sideangledeg = 0.0f;
1527  }
1528  else {
1529  sideangledeg = 90.0f;
1530  }
1531  }
1532 
1533  /* be compatible to the "old" sphere/cylinder mode */
1534  if (direction == ALIGN_TO_OBJECT) {
1535  unit_m4(rotmat);
1536  }
1537  else {
1538  uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius);
1539  }
1540 }
1541 
1542 static void uv_transform_properties(wmOperatorType *ot, int radius)
1543 {
1544  static const EnumPropertyItem direction_items[] = {
1545  {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"},
1546  {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"},
1547  {ALIGN_TO_OBJECT,
1548  "ALIGN_TO_OBJECT",
1549  0,
1550  "Align to Object",
1551  "Align according to object transform"},
1552  {0, NULL, 0, NULL, NULL},
1553  };
1554  static const EnumPropertyItem align_items[] = {
1555  {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"},
1556  {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"},
1557  {0, NULL, 0, NULL, NULL},
1558  };
1559 
1560  RNA_def_enum(ot->srna,
1561  "direction",
1562  direction_items,
1564  "Direction",
1565  "Direction of the sphere or cylinder");
1566  RNA_def_enum(ot->srna,
1567  "align",
1568  align_items,
1570  "Align",
1571  "How to determine rotation around the pole");
1572  if (radius) {
1574  "radius",
1575  1.0f,
1576  0.0f,
1577  FLT_MAX,
1578  "Radius",
1579  "Radius of the sphere or cylinder",
1580  0.0001f,
1581  100.0f);
1582  }
1583 }
1584 
1586  const int cd_loop_uv_offset,
1587  const float aspect_y)
1588 {
1589  BLI_assert(aspect_y != 1.0f); /* Nothing to do, should be handled by caller. */
1590  BLI_assert(aspect_y > 0.0f); /* Negative aspect ratios are not supported. */
1591 
1592  BMLoop *l;
1593  BMIter iter;
1594  BM_ITER_ELEM (l, &iter, efa, BM_LOOPS_OF_FACE) {
1595  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1596  if (aspect_y > 1.0f) {
1597  /* Reduce round-off error, i.e. `u = (u - 0.5) / aspect_y + 0.5`. */
1598  luv->uv[0] = luv->uv[0] / aspect_y + (0.5f - 0.5f / aspect_y);
1599  }
1600  else {
1601  /* Reduce round-off error, i.e. `v = (v - 0.5) * aspect_y + 0.5`. */
1602  luv->uv[1] = luv->uv[1] * aspect_y + (0.5f - 0.5f * aspect_y);
1603  }
1604  }
1605 }
1606 
1607 static void correct_uv_aspect(Object *ob, BMEditMesh *em)
1608 {
1609  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1610  float aspx, aspy;
1611  ED_uvedit_get_aspect(ob, &aspx, &aspy);
1612  const float aspect_y = aspx / aspy;
1613  if (aspect_y == 1.0f) {
1614  /* Scaling by 1.0 has no effect. */
1615  return;
1616  }
1617  BMFace *efa;
1618  BMIter iter;
1619  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1620  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1621  shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
1622  }
1623  }
1624 }
1625 
1627 {
1628  const int materials_num = ob->totcol;
1629  if (materials_num == 0) {
1630  /* Without any materials, there is no aspect_y information and nothing to do. */
1631  return;
1632  }
1633 
1634  float *material_aspect_y = BLI_array_alloca(material_aspect_y, materials_num);
1635  /* Lazily initialize aspect ratio for materials. */
1636  copy_vn_fl(material_aspect_y, materials_num, -1.0f);
1637 
1638  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1639 
1640  BMFace *efa;
1641  BMIter iter;
1642  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1643  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1644  continue;
1645  }
1646 
1647  const int material_index = efa->mat_nr;
1648  if (UNLIKELY(material_index < 0 || material_index >= materials_num)) {
1649  /* The index might be for a material slot which is not currently setup. */
1650  continue;
1651  }
1652 
1653  float aspect_y = material_aspect_y[material_index];
1654  if (aspect_y == -1.0f) {
1655  /* Lazily initialize aspect ratio for materials. */
1656  float aspx, aspy;
1657  ED_uvedit_get_aspect_from_material(ob, material_index, &aspx, &aspy);
1658  aspect_y = aspx / aspy;
1659  material_aspect_y[material_index] = aspect_y;
1660  }
1661 
1662  if (aspect_y == 1.0f) {
1663  /* Scaling by 1.0 has no effect. */
1664  continue;
1665  }
1666  shrink_loop_uv_by_aspect_ratio(efa, cd_loop_uv_offset, aspect_y);
1667  }
1668 }
1669 
1670 #undef VIEW_ON_EQUATOR
1671 #undef VIEW_ON_POLES
1672 #undef ALIGN_TO_OBJECT
1673 
1674 #undef POLAR_ZX
1675 #undef POLAR_ZY
1676 
1679 /* -------------------------------------------------------------------- */
1683 static void uv_map_clip_correct_properties_ex(wmOperatorType *ot, bool clip_to_bounds)
1684 {
1686  "correct_aspect",
1687  1,
1688  "Correct Aspect",
1689  "Map UVs taking image aspect ratio into account");
1690  /* Optional, since not all unwrapping types need to be clipped. */
1691  if (clip_to_bounds) {
1693  "clip_to_bounds",
1694  0,
1695  "Clip to Bounds",
1696  "Clip UV coordinates to bounds after unwrapping");
1697  }
1699  "scale_to_bounds",
1700  0,
1701  "Scale to Bounds",
1702  "Scale UV coordinates to bounds after unwrapping");
1703 }
1704 
1706 {
1708 }
1709 
1717 static void uv_map_clip_correct_multi(Object **objects,
1718  uint objects_len,
1719  wmOperator *op,
1720  bool per_face_aspect)
1721 {
1722  BMFace *efa;
1723  BMLoop *l;
1724  BMIter iter, liter;
1725  MLoopUV *luv;
1726  float dx, dy, min[2], max[2];
1727  const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
1728  const bool clip_to_bounds = (RNA_struct_find_property(op->ptr, "clip_to_bounds") &&
1729  RNA_boolean_get(op->ptr, "clip_to_bounds"));
1730  const bool scale_to_bounds = RNA_boolean_get(op->ptr, "scale_to_bounds");
1731 
1732  INIT_MINMAX2(min, max);
1733 
1734  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1735  Object *ob = objects[ob_index];
1736 
1738  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1739 
1740  /* Correct for image aspect ratio. */
1741  if (correct_aspect) {
1742  if (per_face_aspect) {
1744  }
1745  else {
1746  correct_uv_aspect(ob, em);
1747  }
1748  }
1749 
1750  if (scale_to_bounds) {
1751  /* find uv limits */
1752  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1753  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1754  continue;
1755  }
1756 
1757  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1758  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1759  minmax_v2v2_v2(min, max, luv->uv);
1760  }
1761  }
1762  }
1763  else if (clip_to_bounds) {
1764  /* clipping and wrapping */
1765  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1766  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1767  continue;
1768  }
1769 
1770  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1771  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1772  clamp_v2(luv->uv, 0.0f, 1.0f);
1773  }
1774  }
1775  }
1776  }
1777 
1778  if (scale_to_bounds) {
1779  /* rescale UV to be in 1/1 */
1780  dx = (max[0] - min[0]);
1781  dy = (max[1] - min[1]);
1782 
1783  if (dx > 0.0f) {
1784  dx = 1.0f / dx;
1785  }
1786  if (dy > 0.0f) {
1787  dy = 1.0f / dy;
1788  }
1789 
1790  if (dx == 1.0f && dy == 1.0f) {
1791  /* Scaling by 1.0 has no effect. */
1792  return;
1793  }
1794 
1795  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1796  Object *ob = objects[ob_index];
1797 
1799  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1800 
1801  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1802  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1803  continue;
1804  }
1805 
1806  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1807  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1808 
1809  luv->uv[0] = (luv->uv[0] - min[0]) * dx;
1810  luv->uv[1] = (luv->uv[1] - min[1]) * dy;
1811  }
1812  }
1813  }
1814  }
1815 }
1816 
1818 {
1819  uv_map_clip_correct_multi(&ob, 1, op, true);
1820 }
1821 
1824 /* -------------------------------------------------------------------- */
1828 /* Assumes UV Map exists, doesn't run update funcs. */
1829 static void uvedit_unwrap(const Scene *scene,
1830  Object *obedit,
1831  const UnwrapOptions *options,
1832  UnwrapResultInfo *result_info)
1833 {
1834  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1835  if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
1836  return;
1837  }
1838 
1839  bool use_subsurf;
1840  modifier_unwrap_state(obedit, scene, &use_subsurf);
1841 
1842  ParamHandle *handle;
1843  if (use_subsurf) {
1844  handle = construct_param_handle_subsurfed(scene, obedit, em, options, result_info);
1845  }
1846  else {
1847  handle = construct_param_handle(scene, obedit, em->bm, options, result_info);
1848  }
1849 
1852  result_info ? &result_info->count_changed : NULL,
1853  result_info ? &result_info->count_failed : NULL);
1855 
1856  GEO_uv_parametrizer_average(handle, true, false, false);
1857 
1858  GEO_uv_parametrizer_flush(handle);
1859 
1861 }
1862 
1863 static void uvedit_unwrap_multi(const Scene *scene,
1864  Object **objects,
1865  const int objects_len,
1866  const UnwrapOptions *options,
1867  UnwrapResultInfo *result_info)
1868 {
1869  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1870  Object *obedit = objects[ob_index];
1871  uvedit_unwrap(scene, obedit, options, result_info);
1874  }
1875 }
1876 
1877 void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len)
1878 {
1880  const UnwrapOptions options = {
1881  .topology_from_uvs = false,
1882  .only_selected_faces = false,
1883  .only_selected_uvs = false,
1884  .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
1885  .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
1886  };
1887 
1888  bool rotate = true;
1889  bool ignore_pinned = true;
1890 
1891  uvedit_unwrap_multi(scene, objects, objects_len, &options, NULL);
1892  uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
1893  }
1894 }
1895 
1896 enum {
1899 };
1900 
1902 {
1903  ViewLayer *view_layer = CTX_data_view_layer(C);
1904  const Scene *scene = CTX_data_scene(C);
1905  int method = RNA_enum_get(op->ptr, "method");
1906  const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
1907  int reported_errors = 0;
1908  /* We will report an error unless at least one object
1909  * has the subsurf modifier in the right place. */
1910  bool subsurf_error = use_subsurf;
1911 
1912  uint objects_len = 0;
1914  view_layer, CTX_wm_view3d(C), &objects_len);
1915 
1917  .topology_from_uvs = false,
1918  .only_selected_faces = true,
1919  .only_selected_uvs = false,
1920  .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
1921  .correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
1922  };
1923 
1924  bool rotate = true;
1925  bool ignore_pinned = true;
1926  if (CTX_wm_space_image(C)) {
1927  /* Inside the UV Editor, only unwrap selected UVs. */
1928  options.only_selected_uvs = true;
1929  options.pin_unselected = true;
1930  }
1931 
1932  if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
1933  MEM_freeN(objects);
1934  return OPERATOR_CANCELLED;
1935  }
1936 
1937  /* add uvs if they don't exist yet */
1938  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1939  Object *obedit = objects[ob_index];
1940  float obsize[3];
1941  bool use_subsurf_final;
1942 
1943  if (!ED_uvedit_ensure_uvs(obedit)) {
1944  continue;
1945  }
1946 
1947  if (subsurf_error) {
1948  /* Double up the check here but better keep uvedit_unwrap interface simple and not
1949  * pass operator for warning append. */
1950  modifier_unwrap_state(obedit, scene, &use_subsurf_final);
1951  if (use_subsurf_final) {
1952  subsurf_error = false;
1953  }
1954  }
1955 
1956  if (reported_errors & (UNWRAP_ERROR_NONUNIFORM | UNWRAP_ERROR_NEGATIVE)) {
1957  continue;
1958  }
1959 
1960  mat4_to_size(obsize, obedit->obmat);
1961  if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) {
1962  if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) {
1963  BKE_report(op->reports,
1964  RPT_INFO,
1965  "Object has non-uniform scale, unwrap will operate on a non-scaled version of "
1966  "the mesh");
1967  reported_errors |= UNWRAP_ERROR_NONUNIFORM;
1968  }
1969  }
1970  else if (is_negative_m4(obedit->obmat)) {
1971  if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) {
1972  BKE_report(
1973  op->reports,
1974  RPT_INFO,
1975  "Object has negative scale, unwrap will operate on a non-flipped version of the mesh");
1976  reported_errors |= UNWRAP_ERROR_NEGATIVE;
1977  }
1978  }
1979  }
1980 
1981  if (subsurf_error) {
1982  BKE_report(op->reports,
1983  RPT_INFO,
1984  "Subdivision Surface modifier needs to be first to work with unwrap");
1985  }
1986 
1987  /* remember last method for live unwrap */
1988  if (RNA_struct_property_is_set(op->ptr, "method")) {
1989  scene->toolsettings->unwrapper = method;
1990  }
1991  else {
1992  RNA_enum_set(op->ptr, "method", scene->toolsettings->unwrapper);
1993  }
1994 
1995  /* remember packing margin */
1996  if (RNA_struct_property_is_set(op->ptr, "margin")) {
1997  scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
1998  }
1999  else {
2000  RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
2001  }
2002 
2003  if (options.fill_holes) {
2005  }
2006  else {
2008  }
2009 
2010  if (options.correct_aspect) {
2012  }
2013  else {
2015  }
2016 
2017  if (use_subsurf) {
2019  }
2020  else {
2022  }
2023 
2024  /* execute unwrap */
2025  UnwrapResultInfo result_info = {
2026  .count_changed = 0,
2027  .count_failed = 0,
2028  };
2029  uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info);
2030  uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
2031 
2032  MEM_freeN(objects);
2033 
2034  if (result_info.count_failed == 0 && result_info.count_changed == 0) {
2035  BKE_report(op->reports,
2036  RPT_WARNING,
2037  "Unwrap could not solve any island(s), edge seams may need to be added");
2038  }
2039  else if (result_info.count_failed) {
2040  BKE_reportf(op->reports,
2041  RPT_WARNING,
2042  "Unwrap failed to solve %d of %d island(s), edge seams may need to be added",
2043  result_info.count_failed,
2044  result_info.count_changed + result_info.count_failed);
2045  }
2046 
2047  return OPERATOR_FINISHED;
2048 }
2049 
2051 {
2052  static const EnumPropertyItem method_items[] = {
2053  {0, "ANGLE_BASED", 0, "Angle Based", ""},
2054  {1, "CONFORMAL", 0, "Conformal", ""},
2055  {0, NULL, 0, NULL, NULL},
2056  };
2057 
2058  /* identifiers */
2059  ot->name = "Unwrap";
2060  ot->description = "Unwrap the mesh of the object being edited";
2061  ot->idname = "UV_OT_unwrap";
2063 
2064  /* api callbacks */
2065  ot->exec = unwrap_exec;
2067 
2068  /* properties */
2069  RNA_def_enum(ot->srna,
2070  "method",
2071  method_items,
2072  0,
2073  "Method",
2074  "Unwrapping method (Angle Based usually gives better results than Conformal, while "
2075  "being somewhat slower)");
2077  "fill_holes",
2078  1,
2079  "Fill Holes",
2080  "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and "
2081  "preserve symmetry");
2083  "correct_aspect",
2084  1,
2085  "Correct Aspect",
2086  "Map UVs taking image aspect ratio into account");
2088  ot->srna,
2089  "use_subsurf_data",
2090  0,
2091  "Use Subdivision Surface",
2092  "Map UVs taking vertex position after Subdivision Surface modifier has been applied");
2094  ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
2095 }
2096 
2099 /* -------------------------------------------------------------------- */
2103 /* Ignore all areas below this, as the UV's get zeroed. */
2104 static const float smart_uv_project_area_ignore = 1e-12f;
2105 
2106 typedef struct ThickFace {
2107  float area;
2110 
2111 static int smart_uv_project_thickface_area_cmp_fn(const void *tf_a_p, const void *tf_b_p)
2112 {
2113 
2114  const ThickFace *tf_a = (ThickFace *)tf_a_p;
2115  const ThickFace *tf_b = (ThickFace *)tf_b_p;
2116 
2117  /* Ignore the area of small faces.
2118  * Also, order checks so `!isfinite(...)` values are counted as zero area. */
2119  if (!((tf_a->area > smart_uv_project_area_ignore) ||
2120  (tf_b->area > smart_uv_project_area_ignore))) {
2121  return 0;
2122  }
2123 
2124  if (tf_a->area < tf_b->area) {
2125  return 1;
2126  }
2127  if (tf_a->area > tf_b->area) {
2128  return -1;
2129  }
2130  return 0;
2131 }
2132 
2134  const uint thick_faces_len,
2135  BMesh *bm,
2136  const float project_angle_limit_half_cos,
2137  const float project_angle_limit_cos,
2138  const float area_weight,
2139  float (**r_project_normal_array)[3])
2140 {
2141  if (UNLIKELY(thick_faces_len == 0)) {
2142  *r_project_normal_array = NULL;
2143  return 0;
2144  }
2145 
2146  const float *project_normal = thick_faces[0].efa->no;
2147 
2148  const ThickFace **project_thick_faces = NULL;
2149  BLI_array_declare(project_thick_faces);
2150 
2151  float(*project_normal_array)[3] = NULL;
2152  BLI_array_declare(project_normal_array);
2153 
2155 
2156  while (true) {
2157  for (int f_index = thick_faces_len - 1; f_index >= 0; f_index--) {
2158  if (BM_elem_flag_test(thick_faces[f_index].efa, BM_ELEM_TAG)) {
2159  continue;
2160  }
2161 
2162  if (dot_v3v3(thick_faces[f_index].efa->no, project_normal) > project_angle_limit_half_cos) {
2163  BLI_array_append(project_thick_faces, &thick_faces[f_index]);
2164  BM_elem_flag_set(thick_faces[f_index].efa, BM_ELEM_TAG, true);
2165  }
2166  }
2167 
2168  float average_normal[3] = {0.0f, 0.0f, 0.0f};
2169 
2170  if (area_weight <= 0.0f) {
2171  for (int f_proj_index = 0; f_proj_index < BLI_array_len(project_thick_faces);
2172  f_proj_index++) {
2173  const ThickFace *tf = project_thick_faces[f_proj_index];
2174  add_v3_v3(average_normal, tf->efa->no);
2175  }
2176  }
2177  else if (area_weight >= 1.0f) {
2178  for (int f_proj_index = 0; f_proj_index < BLI_array_len(project_thick_faces);
2179  f_proj_index++) {
2180  const ThickFace *tf = project_thick_faces[f_proj_index];
2181  madd_v3_v3fl(average_normal, tf->efa->no, tf->area);
2182  }
2183  }
2184  else {
2185  for (int f_proj_index = 0; f_proj_index < BLI_array_len(project_thick_faces);
2186  f_proj_index++) {
2187  const ThickFace *tf = project_thick_faces[f_proj_index];
2188  const float area_blend = (tf->area * area_weight) + (1.0f - area_weight);
2189  madd_v3_v3fl(average_normal, tf->efa->no, area_blend);
2190  }
2191  }
2192 
2193  /* Avoid NAN. */
2194  if (normalize_v3(average_normal) != 0.0f) {
2195  float(*normal)[3] = BLI_array_append_ret(project_normal_array);
2196  copy_v3_v3(*normal, average_normal);
2197  }
2198 
2199  /* Find the most unique angle that points away from other normals. */
2200  float anble_best = 1.0f;
2201  uint angle_best_index = 0;
2202 
2203  for (int f_index = thick_faces_len - 1; f_index >= 0; f_index--) {
2204  if (BM_elem_flag_test(thick_faces[f_index].efa, BM_ELEM_TAG)) {
2205  continue;
2206  }
2207 
2208  float angle_test = -1.0f;
2209  for (int p_index = 0; p_index < BLI_array_len(project_normal_array); p_index++) {
2210  angle_test = max_ff(angle_test,
2211  dot_v3v3(project_normal_array[p_index], thick_faces[f_index].efa->no));
2212  }
2213 
2214  if (angle_test < anble_best) {
2215  anble_best = angle_test;
2216  angle_best_index = f_index;
2217  }
2218  }
2219 
2220  if (anble_best < project_angle_limit_cos) {
2221  project_normal = thick_faces[angle_best_index].efa->no;
2222  BLI_array_clear(project_thick_faces);
2223  BLI_array_append(project_thick_faces, &thick_faces[angle_best_index]);
2224  BM_elem_flag_enable(thick_faces[angle_best_index].efa, BM_ELEM_TAG);
2225  }
2226  else {
2227  if (BLI_array_len(project_normal_array) >= 1) {
2228  break;
2229  }
2230  }
2231  }
2232 
2233  BLI_array_free(project_thick_faces);
2235 
2236  *r_project_normal_array = project_normal_array;
2237  return BLI_array_len(project_normal_array);
2238 }
2239 
2241 {
2243  ViewLayer *view_layer = CTX_data_view_layer(C);
2244 
2245  /* May be NULL. */
2246  View3D *v3d = CTX_wm_view3d(C);
2247 
2248  const float project_angle_limit = RNA_float_get(op->ptr, "angle_limit");
2249  const float island_margin = RNA_float_get(op->ptr, "island_margin");
2250  const float area_weight = RNA_float_get(op->ptr, "area_weight");
2251 
2252  const float project_angle_limit_cos = cosf(project_angle_limit);
2253  const float project_angle_limit_half_cos = cosf(project_angle_limit / 2);
2254 
2255  /* Memory arena for list links (cleared for each object). */
2257 
2258  uint objects_len = 0;
2260  view_layer, v3d, &objects_len);
2261 
2262  Object **objects_changed = MEM_mallocN(sizeof(*objects_changed) * objects_len, __func__);
2263  uint object_changed_len = 0;
2264 
2265  BMFace *efa;
2266  BMIter iter;
2267  uint ob_index;
2268 
2269  for (ob_index = 0; ob_index < objects_len; ob_index++) {
2270  Object *obedit = objects[ob_index];
2271  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2272  bool changed = false;
2273 
2274  if (!ED_uvedit_ensure_uvs(obedit)) {
2275  continue;
2276  }
2277 
2278  const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2279  ThickFace *thick_faces = MEM_mallocN(sizeof(*thick_faces) * em->bm->totface, __func__);
2280 
2281  uint thick_faces_len = 0;
2282  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2283  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2284  continue;
2285  }
2286  thick_faces[thick_faces_len].area = BM_face_calc_area(efa);
2287  thick_faces[thick_faces_len].efa = efa;
2288  thick_faces_len++;
2289  }
2290 
2291  qsort(thick_faces, thick_faces_len, sizeof(ThickFace), smart_uv_project_thickface_area_cmp_fn);
2292 
2293  /* Remove all zero area faces. */
2294  while ((thick_faces_len > 0) &&
2295  !(thick_faces[thick_faces_len - 1].area > smart_uv_project_area_ignore)) {
2296 
2297  /* Zero UV's so they don't overlap with other faces being unwrapped. */
2298  BMIter liter;
2299  BMLoop *l;
2300  BM_ITER_ELEM (l, &liter, thick_faces[thick_faces_len - 1].efa, BM_LOOPS_OF_FACE) {
2301  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2302  zero_v2(luv->uv);
2303  changed = true;
2304  }
2305 
2306  thick_faces_len -= 1;
2307  }
2308 
2309  float(*project_normal_array)[3] = NULL;
2310  int project_normals_len = smart_uv_project_calculate_project_normals(
2311  thick_faces,
2312  thick_faces_len,
2313  em->bm,
2314  project_angle_limit_half_cos,
2315  project_angle_limit_cos,
2316  area_weight,
2317  &project_normal_array);
2318 
2319  if (project_normals_len == 0) {
2320  MEM_freeN(thick_faces);
2321  BLI_assert(project_normal_array == NULL);
2322  continue;
2323  }
2324 
2325  /* After finding projection vectors, we find the uv positions. */
2326  LinkNode **thickface_project_groups = MEM_callocN(
2327  sizeof(*thickface_project_groups) * project_normals_len, __func__);
2328 
2329  BLI_memarena_clear(arena);
2330 
2331  for (int f_index = thick_faces_len - 1; f_index >= 0; f_index--) {
2332  const float *f_normal = thick_faces[f_index].efa->no;
2333 
2334  float angle_best = dot_v3v3(f_normal, project_normal_array[0]);
2335  uint angle_best_index = 0;
2336 
2337  for (int p_index = 1; p_index < project_normals_len; p_index++) {
2338  const float angle_test = dot_v3v3(f_normal, project_normal_array[p_index]);
2339  if (angle_test > angle_best) {
2340  angle_best = angle_test;
2341  angle_best_index = p_index;
2342  }
2343  }
2344 
2346  &thickface_project_groups[angle_best_index], &thick_faces[f_index], arena);
2347  }
2348 
2349  for (int p_index = 0; p_index < project_normals_len; p_index++) {
2350  if (thickface_project_groups[p_index] == NULL) {
2351  continue;
2352  }
2353 
2354  float axis_mat[3][3];
2355  axis_dominant_v3_to_m3(axis_mat, project_normal_array[p_index]);
2356 
2357  for (LinkNode *list = thickface_project_groups[p_index]; list; list = list->next) {
2358  ThickFace *tf = list->link;
2359  BMIter liter;
2360  BMLoop *l;
2361  BM_ITER_ELEM (l, &liter, tf->efa, BM_LOOPS_OF_FACE) {
2362  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2363  mul_v2_m3v3(luv->uv, axis_mat, l->v->co);
2364  }
2365  changed = true;
2366  }
2367  }
2368 
2369  MEM_freeN(thick_faces);
2370  MEM_freeN(project_normal_array);
2371 
2372  /* No need to free the lists in 'thickface_project_groups' values as the 'arena' is used. */
2373  MEM_freeN(thickface_project_groups);
2374 
2375  if (changed) {
2376  objects_changed[object_changed_len] = objects[ob_index];
2377  object_changed_len += 1;
2378  }
2379  }
2380 
2381  BLI_memarena_free(arena);
2382 
2383  MEM_freeN(objects);
2384 
2385  /* Pack islands & Stretch to UV bounds */
2386  if (object_changed_len > 0) {
2387 
2388  scene->toolsettings->uvcalc_margin = island_margin;
2389 
2390  /* Depsgraph refresh functions are called here. */
2391  const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
2393  objects_changed,
2394  object_changed_len,
2395  NULL,
2396  &(struct UVPackIsland_Params){
2397  .rotate = true,
2398  /* We could make this optional. */
2399  .rotate_align_axis = 1,
2400  .only_selected_faces = true,
2401  .correct_aspect = correct_aspect,
2402  .use_seams = true,
2403  });
2404 
2405  /* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */
2406  const bool per_face_aspect = false;
2407  uv_map_clip_correct_multi(objects_changed, object_changed_len, op, per_face_aspect);
2408  }
2409 
2410  MEM_freeN(objects_changed);
2411 
2412  return OPERATOR_FINISHED;
2413 }
2414 
2416 {
2417  PropertyRNA *prop;
2418 
2419  /* identifiers */
2420  ot->name = "Smart UV Project";
2421  ot->idname = "UV_OT_smart_project";
2422  ot->description = "Projection unwraps the selected faces of mesh objects";
2423 
2425 
2426  /* api callbacks */
2430 
2431  /* properties */
2432  prop = RNA_def_float_rotation(ot->srna,
2433  "angle_limit",
2434  0,
2435  NULL,
2436  DEG2RADF(0.0f),
2437  DEG2RADF(90.0f),
2438  "Angle Limit",
2439  "Lower for more projection groups, higher for less distortion",
2440  DEG2RADF(0.0f),
2441  DEG2RADF(89.0f));
2443 
2445  "island_margin",
2446  0.0f,
2447  0.0f,
2448  1.0f,
2449  "Island Margin",
2450  "Margin to reduce bleed from adjacent islands",
2451  0.0f,
2452  1.0f);
2454  "area_weight",
2455  0.0f,
2456  0.0f,
2457  1.0f,
2458  "Area Weight",
2459  "Weight projection's vector by faces with larger areas",
2460  0.0f,
2461  1.0f);
2462 
2464 }
2465 
2468 /* -------------------------------------------------------------------- */
2472 static int uv_from_view_exec(bContext *C, wmOperator *op);
2473 
2474 static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2475 {
2476  View3D *v3d = CTX_wm_view3d(C);
2478  Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
2479  PropertyRNA *prop;
2480 
2481  prop = RNA_struct_find_property(op->ptr, "camera_bounds");
2482  if (!RNA_property_is_set(op->ptr, prop)) {
2483  RNA_property_boolean_set(op->ptr, prop, (camera != NULL));
2484  }
2485  prop = RNA_struct_find_property(op->ptr, "correct_aspect");
2486  if (!RNA_property_is_set(op->ptr, prop)) {
2487  RNA_property_boolean_set(op->ptr, prop, (camera == NULL));
2488  }
2489 
2490  return uv_from_view_exec(C, op);
2491 }
2492 
2494 {
2495  ViewLayer *view_layer = CTX_data_view_layer(C);
2496  const Scene *scene = CTX_data_scene(C);
2497  ARegion *region = CTX_wm_region(C);
2498  View3D *v3d = CTX_wm_view3d(C);
2500  Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
2501  BMFace *efa;
2502  BMLoop *l;
2503  BMIter iter, liter;
2504  MLoopUV *luv;
2505  float rotmat[4][4];
2506  float objects_pos_offset[4];
2507  bool changed_multi = false;
2508 
2509  const bool use_orthographic = RNA_boolean_get(op->ptr, "orthographic");
2510 
2511  /* NOTE: objects that aren't touched are set to NULL (to skip clipping). */
2512  uint objects_len = 0;
2514  view_layer, v3d, &objects_len);
2515 
2516  if (use_orthographic) {
2517  /* Calculate average object position. */
2518  float objects_pos_avg[4] = {0};
2519 
2520  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2521  add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]);
2522  }
2523 
2524  mul_v4_fl(objects_pos_avg, 1.0f / objects_len);
2525  negate_v4_v4(objects_pos_offset, objects_pos_avg);
2526  }
2527 
2528  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2529  Object *obedit = objects[ob_index];
2530  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2531  bool changed = false;
2532 
2533  /* add uvs if they don't exist yet */
2534  if (!ED_uvedit_ensure_uvs(obedit)) {
2535  continue;
2536  }
2537 
2538  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2539 
2540  if (use_orthographic) {
2541  uv_map_rotation_matrix_ex(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f, objects_pos_offset);
2542 
2543  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2544  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2545  continue;
2546  }
2547 
2548  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2549  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2550  BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat);
2551  }
2552  changed = true;
2553  }
2554  }
2555  else if (camera) {
2556  const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds");
2558  v3d->camera,
2559  obedit->obmat,
2560  camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f,
2561  camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f);
2562 
2563  if (uci) {
2564  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2565  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2566  continue;
2567  }
2568 
2569  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2570  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2571  BLI_uvproject_from_camera(luv->uv, l->v->co, uci);
2572  }
2573  changed = true;
2574  }
2575 
2576  MEM_freeN(uci);
2577  }
2578  }
2579  else {
2580  copy_m4_m4(rotmat, obedit->obmat);
2581 
2582  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2583  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2584  continue;
2585  }
2586 
2587  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2588  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2590  luv->uv, l->v->co, rv3d->persmat, rotmat, region->winx, region->winy);
2591  }
2592  changed = true;
2593  }
2594  }
2595 
2596  if (changed) {
2597  changed_multi = true;
2600  }
2601  else {
2602  ARRAY_DELETE_REORDER_LAST(objects, ob_index, 1, objects_len);
2603  objects_len -= 1;
2604  ob_index -= 1;
2605  }
2606  }
2607 
2608  if (changed_multi) {
2609  uv_map_clip_correct_multi(objects, objects_len, op, true);
2610  }
2611 
2612  MEM_freeN(objects);
2613 
2614  if (changed_multi) {
2615  return OPERATOR_FINISHED;
2616  }
2617  return OPERATOR_CANCELLED;
2618 }
2619 
2621 {
2623 
2624  if (!ED_operator_uvmap(C)) {
2625  return 0;
2626  }
2627 
2628  return (rv3d != NULL);
2629 }
2630 
2632 {
2633  /* identifiers */
2634  ot->name = "Project from View";
2635  ot->idname = "UV_OT_project_from_view";
2636  ot->description = "Project the UV vertices of the mesh as seen in current 3D view";
2637 
2639 
2640  /* api callbacks */
2644 
2645  /* properties */
2646  RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", "Use orthographic projection");
2648  "camera_bounds",
2649  1,
2650  "Camera Bounds",
2651  "Map UVs to the camera region taking resolution and aspect into account");
2653 }
2654 
2657 /* -------------------------------------------------------------------- */
2662 {
2663  ViewLayer *view_layer = CTX_data_view_layer(C);
2664  View3D *v3d = CTX_wm_view3d(C);
2665 
2666  uint objects_len = 0;
2668  view_layer, v3d, &objects_len);
2669  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2670  Object *obedit = objects[ob_index];
2671  Mesh *me = (Mesh *)obedit->data;
2672  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2673 
2674  if (em->bm->totfacesel == 0) {
2675  continue;
2676  }
2677 
2678  /* add uvs if they don't exist yet */
2679  if (!ED_uvedit_ensure_uvs(obedit)) {
2680  continue;
2681  }
2682 
2683  ED_mesh_uv_loop_reset(C, me);
2684 
2687  }
2688  MEM_freeN(objects);
2689 
2690  return OPERATOR_FINISHED;
2691 }
2692 
2694 {
2695  /* identifiers */
2696  ot->name = "Reset";
2697  ot->idname = "UV_OT_reset";
2698  ot->description = "Reset UV projection";
2699 
2701 
2702  /* api callbacks */
2703  ot->exec = reset_exec;
2705 }
2706 
2709 /* -------------------------------------------------------------------- */
2713 static void uv_sphere_project(float target[2],
2714  const float source[3],
2715  const float center[3],
2716  const float rotmat[4][4])
2717 {
2718  float pv[3];
2719 
2720  sub_v3_v3v3(pv, source, center);
2721  mul_m4_v3(rotmat, pv);
2722 
2723  map_to_sphere(&target[0], &target[1], pv[0], pv[1], pv[2]);
2724 
2725  /* split line is always zero */
2726  if (target[0] >= 1.0f) {
2727  target[0] -= 1.0f;
2728  }
2729 }
2730 
2731 static void uv_map_mirror(BMEditMesh *em, BMFace *efa)
2732 {
2733  BMLoop *l;
2734  BMIter liter;
2735  MLoopUV *luv;
2736  float **uvs = BLI_array_alloca(uvs, efa->len);
2737  float dx;
2738  int i, mi;
2739 
2740  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2741 
2742  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
2743  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2744  uvs[i] = luv->uv;
2745  }
2746 
2747  mi = 0;
2748  for (i = 1; i < efa->len; i++) {
2749  if (uvs[i][0] > uvs[mi][0]) {
2750  mi = i;
2751  }
2752  }
2753 
2754  for (i = 0; i < efa->len; i++) {
2755  if (i != mi) {
2756  dx = uvs[mi][0] - uvs[i][0];
2757  if (dx > 0.5f) {
2758  uvs[i][0] += 1.0f;
2759  }
2760  }
2761  }
2762 }
2763 
2765 {
2766  const Scene *scene = CTX_data_scene(C);
2767  View3D *v3d = CTX_wm_view3d(C);
2768 
2769  ViewLayer *view_layer = CTX_data_view_layer(C);
2770  uint objects_len = 0;
2772  view_layer, v3d, &objects_len);
2773  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2774  Object *obedit = objects[ob_index];
2775  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2776  BMFace *efa;
2777  BMLoop *l;
2778  BMIter iter, liter;
2779  MLoopUV *luv;
2780 
2781  if (em->bm->totfacesel == 0) {
2782  continue;
2783  }
2784 
2785  /* add uvs if they don't exist yet */
2786  if (!ED_uvedit_ensure_uvs(obedit)) {
2787  continue;
2788  }
2789 
2790  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2791  float center[3], rotmat[4][4];
2792 
2793  uv_map_transform(C, op, rotmat);
2794  uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
2795 
2796  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2797  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2798  continue;
2799  }
2800 
2801  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2802  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2803 
2804  uv_sphere_project(luv->uv, l->v->co, center, rotmat);
2805  }
2806 
2807  uv_map_mirror(em, efa);
2808  }
2809 
2810  uv_map_clip_correct(obedit, op);
2811 
2814  }
2815  MEM_freeN(objects);
2816 
2817  return OPERATOR_FINISHED;
2818 }
2819 
2821 {
2822  /* identifiers */
2823  ot->name = "Sphere Projection";
2824  ot->idname = "UV_OT_sphere_project";
2825  ot->description = "Project the UV vertices of the mesh over the curved surface of a sphere";
2826 
2828 
2829  /* api callbacks */
2832 
2833  /* properties */
2836 }
2837 
2840 /* -------------------------------------------------------------------- */
2844 static void uv_cylinder_project(float target[2],
2845  const float source[3],
2846  const float center[3],
2847  const float rotmat[4][4])
2848 {
2849  float pv[3];
2850 
2851  sub_v3_v3v3(pv, source, center);
2852  mul_m4_v3(rotmat, pv);
2853 
2854  map_to_tube(&target[0], &target[1], pv[0], pv[1], pv[2]);
2855 
2856  /* split line is always zero */
2857  if (target[0] >= 1.0f) {
2858  target[0] -= 1.0f;
2859  }
2860 }
2861 
2863 {
2864  const Scene *scene = CTX_data_scene(C);
2865  View3D *v3d = CTX_wm_view3d(C);
2866 
2867  ViewLayer *view_layer = CTX_data_view_layer(C);
2868  uint objects_len = 0;
2870  view_layer, v3d, &objects_len);
2871  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2872  Object *obedit = objects[ob_index];
2873  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2874  BMFace *efa;
2875  BMLoop *l;
2876  BMIter iter, liter;
2877  MLoopUV *luv;
2878 
2879  if (em->bm->totfacesel == 0) {
2880  continue;
2881  }
2882 
2883  /* add uvs if they don't exist yet */
2884  if (!ED_uvedit_ensure_uvs(obedit)) {
2885  continue;
2886  }
2887 
2888  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2889  float center[3], rotmat[4][4];
2890 
2891  uv_map_transform(C, op, rotmat);
2892  uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
2893 
2894  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2895  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2896  continue;
2897  }
2898 
2899  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2900  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2901 
2902  uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
2903  }
2904 
2905  uv_map_mirror(em, efa);
2906  }
2907 
2908  uv_map_clip_correct(obedit, op);
2909 
2912  }
2913  MEM_freeN(objects);
2914 
2915  return OPERATOR_FINISHED;
2916 }
2917 
2919 {
2920  /* identifiers */
2921  ot->name = "Cylinder Projection";
2922  ot->idname = "UV_OT_cylinder_project";
2923  ot->description = "Project the UV vertices of the mesh over the curved wall of a cylinder";
2924 
2926 
2927  /* api callbacks */
2930 
2931  /* properties */
2934 }
2935 
2938 /* -------------------------------------------------------------------- */
2943  float cube_size,
2944  bool use_select,
2945  const float center[3])
2946 {
2947  BMFace *efa;
2948  BMLoop *l;
2949  BMIter iter, liter;
2950  MLoopUV *luv;
2951  float loc[3];
2952  int cox, coy;
2953 
2954  int cd_loop_uv_offset;
2955 
2956  cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
2957 
2958  if (center) {
2959  copy_v3_v3(loc, center);
2960  }
2961  else {
2962  zero_v3(loc);
2963  }
2964 
2965  if (UNLIKELY(cube_size == 0.0f)) {
2966  cube_size = 1.0f;
2967  }
2968 
2969  /* choose x,y,z axis for projection depending on the largest normal
2970  * component, but clusters all together around the center of map. */
2971 
2972  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2973  if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2974  continue;
2975  }
2976 
2977  axis_dominant_v3(&cox, &coy, efa->no);
2978 
2979  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2980  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2981  luv->uv[0] = 0.5f + ((l->v->co[cox] - loc[cox]) / cube_size);
2982  luv->uv[1] = 0.5f + ((l->v->co[coy] - loc[coy]) / cube_size);
2983  }
2984  }
2985 }
2986 
2988 {
2989  const Scene *scene = CTX_data_scene(C);
2990  View3D *v3d = CTX_wm_view3d(C);
2991 
2992  PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size");
2993  const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size);
2994 
2995  ViewLayer *view_layer = CTX_data_view_layer(C);
2996  uint objects_len = 0;
2998  view_layer, v3d, &objects_len);
2999  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
3000  Object *obedit = objects[ob_index];
3001  BMEditMesh *em = BKE_editmesh_from_object(obedit);
3002 
3003  if (em->bm->totfacesel == 0) {
3004  continue;
3005  }
3006 
3007  /* add uvs if they don't exist yet */
3008  if (!ED_uvedit_ensure_uvs(obedit)) {
3009  continue;
3010  }
3011 
3012  float bounds[2][3];
3013  float(*bounds_buf)[3] = NULL;
3014 
3015  if (!RNA_property_is_set(op->ptr, prop_cube_size)) {
3016  bounds_buf = bounds;
3017  }
3018 
3019  float center[3];
3020  uv_map_transform_center(scene, v3d, obedit, em, center, bounds_buf);
3021 
3022  /* calculate based on bounds */
3023  float cube_size = cube_size_init;
3024  if (bounds_buf) {
3025  float dims[3];
3026  sub_v3_v3v3(dims, bounds[1], bounds[0]);
3027  cube_size = max_fff(UNPACK3(dims));
3028  if (ob_index == 0) {
3029  /* This doesn't fit well with, multiple objects. */
3030  RNA_property_float_set(op->ptr, prop_cube_size, cube_size);
3031  }
3032  }
3033 
3034  uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
3035 
3036  uv_map_clip_correct(obedit, op);
3037 
3040  }
3041  MEM_freeN(objects);
3042 
3043  return OPERATOR_FINISHED;
3044 }
3045 
3047 {
3048  /* identifiers */
3049  ot->name = "Cube Projection";
3050  ot->idname = "UV_OT_cube_project";
3051  ot->description = "Project the UV vertices of the mesh over the six faces of a cube";
3052 
3054 
3055  /* api callbacks */
3058 
3059  /* properties */
3061  "cube_size",
3062  1.0f,
3063  0.0f,
3064  FLT_MAX,
3065  "Cube Size",
3066  "Size of the cube to project on",
3067  0.001f,
3068  100.0f);
3070 }
3071 
3074 /* -------------------------------------------------------------------- */
3079 {
3080  Mesh *me = ob->data;
3081  bool sync_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
3082 
3084  &((struct BMeshCreateParams){
3085  .use_toolflags = false,
3086  }));
3087 
3088  /* turn sync selection off,
3089  * since we are not in edit mode we need to ensure only the uv flags are tested */
3091 
3092  ED_mesh_uv_ensure(me, NULL);
3093 
3095  me,
3096  (&(struct BMeshFromMeshParams){
3097  .calc_face_normal = true,
3098  .calc_vert_normal = true,
3099  }));
3100  /* select all uv loops first - pack parameters needs this to make sure charts are registered */
3102  /* A cube size of 2.0 maps [-1..1] vertex coords to [0.0..1.0] in UV coords. */
3103  uvedit_unwrap_cube_project(bm, 2.0, false, NULL);
3104  /* Set the margin really quickly before the packing operation. */
3105  scene->toolsettings->uvcalc_margin = 0.001f;
3107  BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0}));
3108  BM_mesh_free(bm);
3109 
3110  if (sync_selection) {
3112  }
3113 }
3114 
typedef float(TangentPoint)[2]
struct DerivedMesh * CDDM_from_mesh(struct Mesh *mesh)
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:713
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
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
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:793
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_layer(const struct CustomData *data, int type)
#define ORIGINDEX_NONE
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(view_layer, v3d, r_len)
Definition: BKE_layer.h:542
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:550
void BKE_id_free(struct Main *bmain, void *idv)
General operations, lookup, etc. for materials.
struct Mesh * BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, const struct CustomData_MeshMasks *cd_mask_extra, const struct Mesh *me_settings)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
struct DerivedMesh * subsurf_make_derived_from_derived(struct DerivedMesh *dm, struct SubsurfModifierData *smd, const struct Scene *scene, float(*vertCos)[3], SubsurfFlags flags)
Definition: subsurf_ccg.c:1902
@ SUBSURF_IN_EDIT_MODE
Definition: BKE_subsurf.h:39
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:98
#define BLI_array_append_ret(arr)
Definition: BLI_array.h:111
#define BLI_array_declare(arr)
Definition: BLI_array.h:50
#define BLI_array_len(arr)
Definition: BLI_array.h:63
#define BLI_array_clear(arr)
Definition: BLI_array.h:128
#define BLI_array_free(arr)
Definition: BLI_array.h:113
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define ATTR_FALLTHROUGH
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_fff(float a, float b, float c)
MINLINE float max_ff(float a, float b)
#define M_PI
Definition: BLI_math_base.h:20
void map_to_tube(float *r_u, float *r_v, float x, float y, float z)
Definition: math_geom.c:4917
void map_to_sphere(float *r_u, float *r_v, float x, float y, float z)
Definition: math_geom.c:4932
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3527
MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3])
void zero_m4(float m[4][4])
Definition: math_matrix.c:28
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
Definition: math_matrix.c:917
void unit_m4(float m[4][4])
Definition: rct.c:1090
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
#define mul_m4_series(...)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
bool is_negative_m4(const float mat[4][4])
Definition: math_matrix.c:2509
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
void mat4_to_size(float size[3], const float M[4][4])
Definition: math_matrix.c:2138
#define DEG2RADF(_deg)
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void copy_vn_fl(float *array_tar, int size, float val)
Definition: math_vector.c:1259
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:890
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void negate_v4_v4(float r[4], const float a[4])
MINLINE void clamp_v2(float vec[2], float min, float max)
MINLINE void zero_v2(float r[2])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:237
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:94
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:64
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:20
void void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:208
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned int uint
Definition: BLI_sys_types.h:67
#define INIT_MINMAX2(min, max)
#define INIT_MINMAX(min, max)
#define ARRAY_DELETE_REORDER_LAST(arr, index, delete_len, arr_len)
#define UNUSED(x)
#define UNPACK3(a)
#define UNLIKELY(x)
void BLI_uvproject_from_view(float target[2], float source[3], float persmat[4][4], float rotmat[4][4], float winx, float winy)
Definition: uvproject.c:79
void BLI_uvproject_from_view_ortho(float target[2], float source[3], const float rotmat[4][4])
Definition: uvproject.c:169
void BLI_uvproject_from_camera(float target[2], float source[3], struct ProjCameraInfo *uci)
Definition: uvproject.c:27
struct ProjCameraInfo * BLI_uvproject_camera_info(struct Object *ob, float rotmat[4][4], float winx, float winy)
Definition: uvproject.c:120
#define TIP_(msgid)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ CD_ORIGINDEX
@ CD_MLOOPUV
@ IMA_SRC_TILED
@ MLOOPUV_PINNED
@ MLOOPUV_VERTSEL
@ MLOOPUV_EDGESEL
@ eModifierType_Subsurf
Object is a sort of wrapper for general info.
#define UVCALC_USESUBSURF
#define UV_SYNC_SELECTION
#define UVCALC_NO_ASPECT_CORRECT
#define UVCALC_FILLHOLES
@ V3D_AROUND_ACTIVE
@ V3D_AROUND_CENTER_BOUNDS
@ V3D_AROUND_CURSOR
@ V3D_AROUND_CENTER_MEDIAN
@ V3D_AROUND_LOCAL_ORIGINS
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
void ED_image_get_uv_aspect(struct Image *ima, struct ImageUser *iuser, float *r_aspx, float *r_aspy)
Definition: image_edit.c:282
void ED_mesh_uv_ensure(struct Mesh *me, const char *name)
Definition: mesh_data.cc:310
int ED_mesh_uv_add(struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports)
Definition: mesh_data.cc:244
void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
Definition: mesh_data.cc:234
void EDBM_mesh_elem_index_ensure_multi(struct Object **objects, uint objects_len, char htype)
Definition: meshtools.cc:1516
void ED_area_status_text(ScrArea *area, const char *str)
Definition: area.c:792
bool ED_operator_uvmap(struct bContext *C)
Definition: screen_ops.c:571
bool ED_operator_uvedit(struct bContext *C)
Definition: screen_ops.c:557
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:816
bool ED_object_get_active_image(struct Object *ob, int mat_nr, struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree)
Definition: uvedit_ops.c:109
void ED_uvedit_select_all(struct BMesh *bm)
Definition: uvedit_ops.c:240
bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset)
bool ED_uvedit_test(struct Object *obedit)
Definition: uvedit_ops.c:64
bool uv_coords_isect_udim(const struct Image *image, const int udim_grid[2], const float coords[2])
void ED_uvedit_pack_islands_multi(const struct Scene *scene, Object **objects, uint objects_len, const struct UVMapUDIM_Params *udim_params, const struct UVPackIsland_Params *params)
struct Camera * ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d)
Definition: view3d_utils.c:94
void GEO_uv_parametrizer_flush(ParamHandle *handle)
void GEO_uv_parametrizer_stretch_iter(ParamHandle *handle)
ParamHandle * GEO_uv_parametrizer_construct_begin(void)
void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
void GEO_uv_parametrizer_lscm_end(ParamHandle *handle)
void GEO_uv_parametrizer_stretch_begin(ParamHandle *handle)
void GEO_uv_parametrizer_face_add(ParamHandle *handle, const ParamKey key, const int nverts, const ParamKey *vkeys, const float **co, float **uv, const bool *pin, const bool *select)
void GEO_uv_parametrizer_average(ParamHandle *handle, bool ignore_pinned, bool scale_uv, bool shear)
void GEO_uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
void GEO_uv_parametrizer_flush_restore(ParamHandle *handle)
void GEO_uv_parametrizer_construct_end(ParamHandle *handle, bool fill, bool topology_from_uvs, int *count_fail)
void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed)
void GEO_uv_parametrizer_delete(ParamHandle *handle)
void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
void GEO_uv_parametrizer_stretch_end(ParamHandle *handle)
ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
intptr_t ParamKey
void GEO_uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy)
void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, bool live, bool abf)
void GEO_uv_parametrizer_stretch_blend(ParamHandle *handle, float blend)
NSNotificationCenter * center
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
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 Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
Platform independent time functions.
#define C
Definition: RandGen.cpp:25
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:91
@ KM_PRESS
Definition: WM_types.h:267
@ OPTYPE_BLOCKING
Definition: WM_types.h:150
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_GRAB_CURSOR_XY
Definition: WM_types.h:154
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ 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_TAG
Definition: bmesh_class.h:484
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#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)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_EDGE
@ BM_LOOPS_OF_FACE
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_editselection_center(BMEditSelection *ese, float r_center[3])
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
BMFace * BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
const BMAllocTemplate bm_mesh_allocsize_default
Definition: bmesh_mesh.cc:23
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
Definition: bmesh_mesh.cc:258
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
Definition: bmesh_mesh.cc:125
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:558
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:115
BLI_INLINE BMEdge * BM_edge_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:109
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
void BM_face_calc_bounds_expand(const BMFace *f, float min[3], float max[3])
float BM_face_calc_area(const BMFace *f)
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition: btDbvt.cpp:299
SIMD_FORCE_INLINE btVector3 rotate(const btVector3 &wAxis, const btScalar angle) const
Return a rotated version of this vector.
#define sinf(x)
Definition: cuda/compat.h:102
#define cosf(x)
Definition: cuda/compat.h:101
CCL_NAMESPACE_BEGIN struct Options options
Scene scene
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
#define str(s)
IconTextureDrawCall normal
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
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
#define floorf(x)
Definition: metal/compat.h:224
#define fabsf(x)
Definition: metal/compat.h:219
static void area(int d1, int d2, int e1, int e2, float weights[2])
const int faceMap[6][4]
Definition: octree.cpp:2817
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2767
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:4921
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4910
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
Definition: rna_access.c:2180
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:4968
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
Definition: rna_access.c:2790
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_enum_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:5015
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
void RNA_def_property_float_default(PropertyRNA *prop, float value)
Definition: rna_define.c:2022
PropertyRNA * RNA_def_float_factor(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:4144
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, int default_value, int hardmin, int hardmax, const char *ui_name, const char *ui_description, int softmin, int softmax)
Definition: rna_define.c:3597
PropertyRNA * RNA_def_float_rotation(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:4016
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
struct BMesh * bm
Definition: BKE_editmesh.h:40
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:267
float no[3]
Definition: bmesh_class.h:271
struct BMVert * v
Definition: bmesh_class.h:153
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
int totfacesel
Definition: bmesh_class.h:298
int totvertsel
Definition: bmesh_class.h:298
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
struct MLoop *(* getLoopArray)(DerivedMesh *dm)
void *(* getVertDataArray)(DerivedMesh *dm, int type)
struct MVert *(* getVertArray)(DerivedMesh *dm)
int(* getNumPolys)(DerivedMesh *dm)
int(* getNumEdges)(DerivedMesh *dm)
void *(* getPolyDataArray)(DerivedMesh *dm, int type)
void *(* getEdgeDataArray)(DerivedMesh *dm, int type)
struct MEdge *(* getEdgeArray)(DerivedMesh *dm)
struct MPoly *(* getPolyArray)(DerivedMesh *dm)
void(* release)(DerivedMesh *dm)
struct LinkNode * next
Definition: BLI_linklist.h:23
void * first
Definition: DNA_listBase.h:31
unsigned int v
float co[3]
Definition: BKE_main.h:121
wmTimer * timer
Object ** objects_edit
const Scene * scene
ParamHandle * handle
ListBase modifiers
float imat[4][4]
float obmat[4][4]
void * data
float rotmat[4][4]
Definition: uvproject.c:22
float persmat[4][4]
float viewmat[4][4]
struct ToolSettings * toolsettings
struct RenderData r
View3DCursor cursor
float cursor[2]
int tile_grid_shape[2]
struct Image * image
char transform_pivot_point
char edge_mode_live_unwrap
const struct Image * image
Definition: ED_uvedit.h:309
bool use_target_udim
Definition: ED_uvedit.h:312
int grid_shape[2]
Definition: ED_uvedit.h:311
bool topology_from_uvs_use_seams
struct Object * camera
short val
Definition: WM_types.h:680
short type
Definition: WM_types.h:678
void * customdata
Definition: WM_types.h:715
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
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:935
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:927
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 ReportList * reports
struct PointerRNA * ptr
double PIL_check_seconds_timer(void)
Definition: time.c:64
float max
static void uvedit_unwrap_multi(const Scene *scene, Object **objects, const int objects_len, const UnwrapOptions *options, UnwrapResultInfo *result_info)
static int uv_from_view_exec(bContext *C, wmOperator *op)
static void construct_param_handle_face_add(ParamHandle *handle, const Scene *scene, BMFace *efa, ParamKey face_index, const UnwrapOptions *options, const int cd_loop_uv_offset)
struct ThickFace ThickFace
static void uv_map_transform_center(const Scene *scene, View3D *v3d, Object *ob, BMEditMesh *em, float r_center[3], float r_bounds[2][3])
static int cube_project_exec(bContext *C, wmOperator *op)
static bool uv_from_view_poll(bContext *C)
static void uvedit_pack_islands_multi(const Scene *scene, Object **objects, const uint objects_len, const UnwrapOptions *options, bool rotate, bool ignore_pinned)
static int cylinder_project_exec(bContext *C, wmOperator *op)
static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob)
void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len)
static bool uvedit_have_selection_multi(const Scene *scene, Object **objects, const uint objects_len, const UnwrapOptions *options)
static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOperator *op, bool per_face_aspect)
static void construct_param_edge_set_seams(ParamHandle *handle, BMesh *bm, const UnwrapOptions *options)
void ED_uvedit_get_aspect_from_material(Object *ob, const int material_index, float *r_aspx, float *r_aspy)
#define POLAR_ZX
struct UnwrapResultInfo UnwrapResultInfo
bool ED_uvedit_udim_params_from_image_space(const SpaceImage *sima, bool use_active, struct UVMapUDIM_Params *udim_params)
static void minimize_stretch_cancel(bContext *C, wmOperator *op)
static void uv_sphere_project(float target[2], const float source[3], const float center[3], const float rotmat[4][4])
static void uv_transform_properties(wmOperatorType *ot, int radius)
static bool uvedit_is_face_affected(const Scene *scene, BMFace *efa, const UnwrapOptions *options, const int cd_loop_uv_offset)
void UV_OT_cylinder_project(wmOperatorType *ot)
void UV_OT_project_from_view(wmOperatorType *ot)
void UV_OT_smart_project(wmOperatorType *ot)
@ UNWRAP_ERROR_NEGATIVE
@ UNWRAP_ERROR_NONUNIFORM
static int minimize_stretch_modal(bContext *C, wmOperator *op, const wmEvent *event)
static void uvedit_unwrap_cube_project(BMesh *bm, float cube_size, bool use_select, const float center[3])
void UV_OT_unwrap(wmOperatorType *ot)
static int minimize_stretch_exec(bContext *C, wmOperator *op)
static int minimize_stretch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static const float smart_uv_project_area_ignore
static ParamHandle * construct_param_handle(const Scene *scene, Object *ob, BMesh *bm, const UnwrapOptions *options, UnwrapResultInfo *result_info)
static int unwrap_exec(bContext *C, wmOperator *op)
static int smart_uv_project_thickface_area_cmp_fn(const void *tf_a_p, const void *tf_b_p)
static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
static void modifier_unwrap_state(Object *obedit, const Scene *scene, bool *r_use_subsurf)
void UV_OT_sphere_project(wmOperatorType *ot)
static void correct_uv_aspect(Object *ob, BMEditMesh *em)
void UV_OT_cube_project(wmOperatorType *ot)
static int pack_islands_exec(bContext *C, wmOperator *op)
void ED_uvedit_live_unwrap_re_solve(void)
static void uvedit_unwrap(const Scene *scene, Object *obedit, const UnwrapOptions *options, UnwrapResultInfo *result_info)
static void uv_map_transform_calc_center_median(BMEditMesh *em, float r_center[3])
static void uv_map_clip_correct_properties(wmOperatorType *ot)
static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Object *ob, float upangledeg, float sideangledeg, float radius)
static void uv_map_clip_correct_properties_ex(wmOperatorType *ot, bool clip_to_bounds)
static void uv_map_clip_correct(Object *ob, wmOperator *op)
uint len_alloc
@ PACK_UDIM_SRC_CLOSEST
@ PACK_UDIM_SRC_ACTIVE
static void uv_map_rotation_matrix_ex(float result[4][4], RegionView3D *rv3d, Object *ob, float upangledeg, float sideangledeg, float radius, const float offset[4])
#define VIEW_ON_POLES
static ParamHandle * construct_param_handle_multi(const Scene *scene, Object **objects, const uint objects_len, const UnwrapOptions *options)
static void uvedit_prepare_pinned_indices(ParamHandle *handle, const Scene *scene, BMFace *efa, const UnwrapOptions *options, const int cd_loop_uv_offset)
static int average_islands_scale_exec(bContext *C, wmOperator *op)
static int sphere_project_exec(bContext *C, wmOperator *op)
static struct @632 g_live_unwrap
struct MinStretch MinStretch
static ParamHandle * construct_param_handle_subsurfed(const Scene *scene, Object *ob, BMEditMesh *em, const UnwrapOptions *options, UnwrapResultInfo *result_info)
static void uv_map_transform(bContext *C, wmOperator *op, float rotmat[4][4])
static int smart_project_exec(bContext *C, wmOperator *op)
static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interactive)
static uint smart_uv_project_calculate_project_normals(const ThickFace *thick_faces, const uint thick_faces_len, BMesh *bm, const float project_angle_limit_half_cos, const float project_angle_limit_cos, const float area_weight, float(**r_project_normal_array)[3])
void UV_OT_average_islands_scale(wmOperatorType *ot)
static bool uvedit_have_selection(const Scene *scene, BMEditMesh *em, const UnwrapOptions *options)
static void uv_cylinder_project(float target[2], const float source[3], const float center[3], const float rotmat[4][4])
void UV_OT_reset(wmOperatorType *ot)
void UV_OT_minimize_stretch(wmOperatorType *ot)
static void texface_from_original_index(const Scene *scene, const int cd_loop_uv_offset, BMFace *efa, int index, float **r_uv, bool *r_pin, bool *r_select)
static bool minimize_stretch_init(bContext *C, wmOperator *op)
static void uv_map_transform_calc_bounds(BMEditMesh *em, float r_min[3], float r_max[3])
static bool ED_uvedit_ensure_uvs(Object *obedit)
static void shrink_loop_uv_by_aspect_ratio(BMFace *efa, const int cd_loop_uv_offset, const float aspect_y)
static void correct_uv_aspect_per_face(Object *ob, BMEditMesh *em)
uint len
struct UnwrapOptions UnwrapOptions
#define ALIGN_TO_OBJECT
#define POLAR_ZY
ParamHandle ** handles
#define VIEW_ON_EQUATOR
static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
void UV_OT_pack_islands(wmOperatorType *ot)
static void uv_map_mirror(BMEditMesh *em, BMFace *efa)
void ED_uvedit_live_unwrap_end(short cancel)
static int reset_exec(bContext *C, wmOperator *UNUSED(op))
void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ RIGHTMOUSE
@ TIMER
@ WHEELUPMOUSE
@ EVT_PADENTER
@ WHEELDOWNMOUSE
@ EVT_PADMINUS
@ LEFTMOUSE
@ EVT_ESCKEY
@ EVT_PADPLUSKEY
@ EVT_RETKEY
wmOperatorType * ot
Definition: wm_files.c:3479
int WM_operator_props_popup_confirm(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
Definition: wm_window.c:1682
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1630