Blender  V2.93
uvedit_unwrap_ops.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "MEM_guardedalloc.h"
29 
30 #include "DNA_camera_types.h"
31 #include "DNA_mesh_types.h"
32 #include "DNA_meshdata_types.h"
33 #include "DNA_modifier_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_scene_types.h"
36 
37 #include "BLI_alloca.h"
38 #include "BLI_array.h"
39 #include "BLI_linklist.h"
40 #include "BLI_math.h"
41 #include "BLI_memarena.h"
42 #include "BLI_string.h"
43 #include "BLI_utildefines.h"
44 #include "BLI_uvproject.h"
45 
46 #include "BLT_translation.h"
47 
48 #include "BKE_cdderivedmesh.h"
49 #include "BKE_context.h"
50 #include "BKE_customdata.h"
51 #include "BKE_editmesh.h"
52 #include "BKE_image.h"
53 #include "BKE_layer.h"
54 #include "BKE_lib_id.h"
55 #include "BKE_main.h"
56 #include "BKE_material.h"
57 #include "BKE_mesh.h"
58 #include "BKE_report.h"
59 #include "BKE_scene.h"
60 #include "BKE_subsurf.h"
61 
62 #include "DEG_depsgraph.h"
63 
64 #include "PIL_time.h"
65 
66 #include "UI_interface.h"
67 
68 #include "ED_image.h"
69 #include "ED_mesh.h"
70 #include "ED_screen.h"
71 #include "ED_uvedit.h"
72 #include "ED_view3d.h"
73 
74 #include "RNA_access.h"
75 #include "RNA_define.h"
76 
77 #include "WM_api.h"
78 #include "WM_types.h"
79 
80 #include "uvedit_intern.h"
81 #include "uvedit_parametrizer.h"
82 
83 /* -------------------------------------------------------------------- */
87 static void modifier_unwrap_state(Object *obedit, const Scene *scene, bool *r_use_subsurf)
88 {
89  ModifierData *md;
90  bool subsurf = (scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF) != 0;
91 
92  md = obedit->modifiers.first;
93 
94  /* subsurf will take the modifier settings only if modifier is first or right after mirror */
95  if (subsurf) {
96  if (md && md->type == eModifierType_Subsurf) {
97  subsurf = true;
98  }
99  else {
100  subsurf = false;
101  }
102  }
103 
104  *r_use_subsurf = subsurf;
105 }
106 
107 static bool ED_uvedit_ensure_uvs(Object *obedit)
108 {
109  if (ED_uvedit_test(obedit)) {
110  return 1;
111  }
112 
113  BMEditMesh *em = BKE_editmesh_from_object(obedit);
114  BMFace *efa;
115  BMIter iter;
116  int cd_loop_uv_offset;
117 
118  if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
119  ED_mesh_uv_texture_add(obedit->data, NULL, true, true);
120  }
121 
122  /* Happens when there are no faces. */
123  if (!ED_uvedit_test(obedit)) {
124  return 0;
125  }
126 
127  cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
128 
129  /* select new UV's (ignore UV_SYNC_SELECTION in this case) */
130  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
131  BMIter liter;
132  BMLoop *l;
133 
134  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
135  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
136  luv->flag |= MLOOPUV_VERTSEL;
137  }
138  }
139 
140  return 1;
141 }
142 
145 /* -------------------------------------------------------------------- */
149 typedef struct UnwrapOptions {
167 
168 typedef struct UnwrapResultInfo {
172 
174 {
175  BMFace *efa;
176  BMLoop *l;
177  BMIter iter, liter;
178  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
179 
180  if (cd_loop_uv_offset == -1) {
181  return (em->bm->totfacesel != 0);
182  }
183 
184  /* verify if we have any selected uv's before unwrapping,
185  * so we can cancel the operator early */
186  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
188  if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
189  continue;
190  }
191  }
192  else if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
193  continue;
194  }
195 
196  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
197  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
198  break;
199  }
200  }
201 
202  if (options->topology_from_uvs && !l) {
203  continue;
204  }
205 
206  return true;
207  }
208 
209  return false;
210 }
211 
213  Object **objects,
214  const uint objects_len,
215  const UnwrapOptions *options)
216 {
217  bool have_select = false;
218  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
219  Object *obedit = objects[ob_index];
220  BMEditMesh *em = BKE_editmesh_from_object(obedit);
221  if (uvedit_have_selection(scene, em, options)) {
222  have_select = true;
223  break;
224  }
225  }
226  return have_select;
227 }
228 
229 void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
230 {
232  BLI_assert(em != NULL);
233  bool sloppy = true;
234  bool selected = false;
235  BMFace *efa;
236  Image *ima;
237 
238  efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
239 
240  if (efa) {
241  ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
242 
243  ED_image_get_uv_aspect(ima, NULL, r_aspx, r_aspy);
244  }
245  else {
246  *r_aspx = 1.0f;
247  *r_aspy = 1.0f;
248  }
249 }
250 
252  const Scene *scene,
253  BMFace *efa,
254  int face_index,
255  const int cd_loop_uv_offset)
256 {
257  ParamKey key;
258  ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
259  ParamBool *pin = BLI_array_alloca(pin, efa->len);
261  float **co = BLI_array_alloca(co, efa->len);
262  float **uv = BLI_array_alloca(uv, efa->len);
263  int i;
264 
265  BMIter liter;
266  BMLoop *l;
267 
268  key = (ParamKey)face_index;
269 
270  /* let parametrizer split the ngon, it can make better decisions
271  * about which split is best for unwrapping than poly-fill. */
272  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
273  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
274 
275  vkeys[i] = (ParamKey)BM_elem_index_get(l->v);
276  co[i] = l->v->co;
277  uv[i] = luv->uv;
278  pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
279  select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
280  }
281 
282  param_face_add(handle, key, i, vkeys, co, uv, pin, select);
283 }
284 
285 /* See: construct_param_handle_multi to handle multiple objects at once. */
287  Object *ob,
288  BMesh *bm,
289  const UnwrapOptions *options,
290  UnwrapResultInfo *result_info)
291 {
292  ParamHandle *handle;
293  BMFace *efa;
294  BMLoop *l;
295  BMEdge *eed;
296  BMIter iter, liter;
297  int i;
298 
299  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
300 
301  handle = param_construct_begin();
302 
303  if (options->correct_aspect) {
304  float aspx, aspy;
305 
306  ED_uvedit_get_aspect(ob, &aspx, &aspy);
307 
308  if (aspx != aspy) {
309  param_aspect_ratio(handle, aspx, aspy);
310  }
311  }
312 
313  /* we need the vert indices */
315 
316  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
317 
318  if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
319  (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
320  continue;
321  }
322 
323  if (options->topology_from_uvs) {
324  bool is_loopsel = false;
325 
326  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
327  if (options->only_selected_uvs &&
328  (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
329  continue;
330  }
331  is_loopsel = true;
332  break;
333  }
334  if (is_loopsel == false) {
335  continue;
336  }
337  }
338 
339  construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
340  }
341 
342  if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
343  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
344  if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
345  ParamKey vkeys[2];
346  vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
347  vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
348  param_edge_set_seam(handle, vkeys);
349  }
350  }
351  }
352 
353  param_construct_end(handle,
354  options->fill_holes,
355  options->topology_from_uvs,
356  result_info ? &result_info->count_failed : NULL);
357 
358  return handle;
359 }
360 
365  Object **objects,
366  const uint objects_len,
367  const UnwrapOptions *options,
368  int *count_fail)
369 {
370  ParamHandle *handle;
371  BMFace *efa;
372  BMLoop *l;
373  BMEdge *eed;
374  BMIter iter, liter;
375  int i;
376 
377  handle = param_construct_begin();
378 
379  if (options->correct_aspect) {
380  Object *ob = objects[0];
381  float aspx, aspy;
382 
383  ED_uvedit_get_aspect(ob, &aspx, &aspy);
384  if (aspx != aspy) {
385  param_aspect_ratio(handle, aspx, aspy);
386  }
387  }
388 
389  /* we need the vert indices */
390  EDBM_mesh_elem_index_ensure_multi(objects, objects_len, BM_VERT);
391 
392  int offset = 0;
393 
394  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
395  Object *obedit = objects[ob_index];
396  BMEditMesh *em = BKE_editmesh_from_object(obedit);
397  BMesh *bm = em->bm;
398 
399  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
400 
401  if (cd_loop_uv_offset == -1) {
402  continue;
403  }
404 
405  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
406 
407  if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) ||
408  (options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
409  continue;
410  }
411 
412  if (options->topology_from_uvs) {
413  bool is_loopsel = false;
414 
415  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
416  if (options->only_selected_uvs &&
417  (uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
418  continue;
419  }
420  is_loopsel = true;
421  break;
422  }
423  if (is_loopsel == false) {
424  continue;
425  }
426  }
427 
428  construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
429  }
430 
431  if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
432  BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
433  if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
434  ParamKey vkeys[2];
435  vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
436  vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
437  param_edge_set_seam(handle, vkeys);
438  }
439  }
440  }
441  offset += bm->totface;
442  }
443 
444  param_construct_end(handle, options->fill_holes, options->topology_from_uvs, count_fail);
445 
446  return handle;
447 }
448 
450  const int cd_loop_uv_offset,
451  BMFace *efa,
452  int index,
453  float **r_uv,
454  ParamBool *r_pin,
455  ParamBool *r_select)
456 {
457  BMLoop *l;
458  BMIter liter;
459  MLoopUV *luv;
460 
461  *r_uv = NULL;
462  *r_pin = 0;
463  *r_select = 1;
464 
465  if (index == ORIGINDEX_NONE) {
466  return;
467  }
468 
469  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
470  if (BM_elem_index_get(l->v) == index) {
471  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
472  *r_uv = luv->uv;
473  *r_pin = (luv->flag & MLOOPUV_PINNED) ? 1 : 0;
474  *r_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
475  break;
476  }
477  }
478 }
479 
486  Object *ob,
487  BMEditMesh *em,
488  const UnwrapOptions *options,
489  UnwrapResultInfo *result_info)
490 {
491  ParamHandle *handle;
492  /* index pointers */
493  MPoly *mpoly;
494  MLoop *mloop;
495  MEdge *edge;
496  int i;
497 
498  /* pointers to modifier data for unwrap control */
499  ModifierData *md;
500  SubsurfModifierData *smd_real;
501  /* modifier initialization data, will control what type of subdivision will happen*/
502  SubsurfModifierData smd = {{NULL}};
503  /* Used to hold subsurfed Mesh */
504  DerivedMesh *derivedMesh, *initialDerived;
505  /* holds original indices for subsurfed mesh */
506  const int *origVertIndices, *origEdgeIndices, *origPolyIndices;
507  /* Holds vertices of subsurfed mesh */
508  MVert *subsurfedVerts;
509  MEdge *subsurfedEdges;
510  MPoly *subsurfedPolys;
511  MLoop *subsurfedLoops;
512  /* number of vertices and faces for subsurfed mesh*/
513  int numOfEdges, numOfFaces;
514 
515  /* holds a map to editfaces for every subsurfed MFace.
516  * These will be used to get hidden/ selected flags etc. */
517  BMFace **faceMap;
518  /* similar to the above, we need a way to map edges to their original ones */
519  BMEdge **edgeMap;
520 
521  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
522 
523  handle = param_construct_begin();
524 
525  if (options->correct_aspect) {
526  float aspx, aspy;
527 
528  ED_uvedit_get_aspect(ob, &aspx, &aspy);
529 
530  if (aspx != aspy) {
531  param_aspect_ratio(handle, aspx, aspy);
532  }
533  }
534 
535  /* number of subdivisions to perform */
536  md = ob->modifiers.first;
537  smd_real = (SubsurfModifierData *)md;
538 
539  smd.levels = smd_real->levels;
540  smd.subdivType = smd_real->subdivType;
541 
542  {
543  Mesh *me_from_em = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, ob->data);
544  initialDerived = CDDM_from_mesh(me_from_em);
545  derivedMesh = subsurf_make_derived_from_derived(
546  initialDerived, &smd, scene, NULL, SUBSURF_IN_EDIT_MODE);
547 
548  initialDerived->release(initialDerived);
549  BKE_id_free(NULL, me_from_em);
550  }
551 
552  /* get the derived data */
553  subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
554  subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
555  subsurfedPolys = derivedMesh->getPolyArray(derivedMesh);
556  subsurfedLoops = derivedMesh->getLoopArray(derivedMesh);
557 
558  origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
559  origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
560  origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX);
561 
562  numOfEdges = derivedMesh->getNumEdges(derivedMesh);
563  numOfFaces = derivedMesh->getNumPolys(derivedMesh);
564 
565  faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map");
566 
569 
570  /* map subsurfed faces to original editFaces */
571  for (i = 0; i < numOfFaces; i++) {
572  faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]);
573  }
574 
575  edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map");
576 
577  /* map subsurfed edges to original editEdges */
578  for (i = 0; i < numOfEdges; i++) {
579  /* not all edges correspond to an old edge */
580  edgeMap[i] = (origEdgeIndices[i] != ORIGINDEX_NONE) ?
581  BM_edge_at_index(em->bm, origEdgeIndices[i]) :
582  NULL;
583  }
584 
585  /* Prepare and feed faces to the solver */
586  for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) {
587  ParamKey key, vkeys[4];
588  ParamBool pin[4], select[4];
589  float *co[4];
590  float *uv[4];
591  BMFace *origFace = faceMap[i];
592 
594  if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN)) {
595  continue;
596  }
597  }
598  else {
599  if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) ||
600  (options->only_selected_faces && !BM_elem_flag_test(origFace, BM_ELEM_SELECT))) {
601  continue;
602  }
603  }
604 
605  mloop = &subsurfedLoops[mpoly->loopstart];
606 
607  /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
608  BLI_assert(mpoly->totloop == 4);
609  key = (ParamKey)i;
610  vkeys[0] = (ParamKey)mloop[0].v;
611  vkeys[1] = (ParamKey)mloop[1].v;
612  vkeys[2] = (ParamKey)mloop[2].v;
613  vkeys[3] = (ParamKey)mloop[3].v;
614 
615  co[0] = subsurfedVerts[mloop[0].v].co;
616  co[1] = subsurfedVerts[mloop[1].v].co;
617  co[2] = subsurfedVerts[mloop[2].v].co;
618  co[3] = subsurfedVerts[mloop[3].v].co;
619 
620  /* This is where all the magic is done.
621  * If the vertex exists in the, we pass the original uv pointer to the solver, thus
622  * flushing the solution to the edit mesh. */
624  cd_loop_uv_offset,
625  origFace,
626  origVertIndices[mloop[0].v],
627  &uv[0],
628  &pin[0],
629  &select[0]);
631  cd_loop_uv_offset,
632  origFace,
633  origVertIndices[mloop[1].v],
634  &uv[1],
635  &pin[1],
636  &select[1]);
638  cd_loop_uv_offset,
639  origFace,
640  origVertIndices[mloop[2].v],
641  &uv[2],
642  &pin[2],
643  &select[2]);
645  cd_loop_uv_offset,
646  origFace,
647  origVertIndices[mloop[3].v],
648  &uv[3],
649  &pin[3],
650  &select[3]);
651 
652  param_face_add(handle, key, 4, vkeys, co, uv, pin, select);
653  }
654 
655  /* these are calculated from original mesh too */
656  for (edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) {
657  if ((edgeMap[i] != NULL) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) {
658  ParamKey vkeys[2];
659  vkeys[0] = (ParamKey)edge->v1;
660  vkeys[1] = (ParamKey)edge->v2;
661  param_edge_set_seam(handle, vkeys);
662  }
663  }
664 
665  param_construct_end(handle,
666  options->fill_holes,
667  options->topology_from_uvs,
668  result_info ? &result_info->count_failed : NULL);
669 
670  /* cleanup */
672  MEM_freeN(edgeMap);
673  derivedMesh->release(derivedMesh);
674 
675  return handle;
676 }
677 
680 /* -------------------------------------------------------------------- */
684 typedef struct MinStretch {
685  const Scene *scene;
689  float blend;
690  double lasttime;
691  int i, iterations;
694 
696 {
697  const Scene *scene = CTX_data_scene(C);
698  ViewLayer *view_layer = CTX_data_view_layer(C);
699 
700  const UnwrapOptions options = {
701  .topology_from_uvs = true,
702  .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
703  .only_selected_faces = true,
704  .only_selected_uvs = true,
705  .correct_aspect = true,
706  };
707 
708  uint objects_len = 0;
710  view_layer, CTX_wm_view3d(C), &objects_len);
711 
712  if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
713  MEM_freeN(objects);
714  return false;
715  }
716 
717  MinStretch *ms = MEM_callocN(sizeof(MinStretch), "MinStretch");
718  ms->scene = scene;
719  ms->objects_edit = objects;
720  ms->objects_len = objects_len;
721  ms->blend = RNA_float_get(op->ptr, "blend");
722  ms->iterations = RNA_int_get(op->ptr, "iterations");
723  ms->i = 0;
724  ms->handle = construct_param_handle_multi(scene, objects, objects_len, &options, NULL);
726 
728  if (ms->blend != 0.0f) {
729  param_stretch_blend(ms->handle, ms->blend);
730  }
731 
732  op->customdata = ms;
733 
734  return true;
735 }
736 
737 static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interactive)
738 {
739  MinStretch *ms = op->customdata;
741  const Scene *scene = CTX_data_scene(C);
743  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
744 
745  param_stretch_blend(ms->handle, ms->blend);
747 
748  ms->i++;
749  RNA_int_set(op->ptr, "iterations", ms->i);
750 
751  if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
752  char str[UI_MAX_DRAW_STR];
753 
754  param_flush(ms->handle);
755 
756  if (area) {
757  BLI_snprintf(str, sizeof(str), TIP_("Minimize Stretch. Blend %.2f"), ms->blend);
759  ED_workspace_status_text(C, TIP_("Press + and -, or scroll wheel to set blending"));
760  }
761 
763 
764  for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
765  Object *obedit = ms->objects_edit[ob_index];
766  BMEditMesh *em = BKE_editmesh_from_object(obedit);
767 
768  if (synced_selection && (em->bm->totfacesel == 0)) {
769  continue;
770  }
771 
774  }
775  }
776 }
777 
778 static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
779 {
780  MinStretch *ms = op->customdata;
782  const Scene *scene = CTX_data_scene(C);
784  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
785 
788 
789  if (ms->timer) {
791  }
792 
793  if (cancel) {
795  }
796  else {
797  param_flush(ms->handle);
798  }
799 
801  param_delete(ms->handle);
802 
803  for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
804  Object *obedit = ms->objects_edit[ob_index];
805  BMEditMesh *em = BKE_editmesh_from_object(obedit);
806 
807  if (synced_selection && (em->bm->totfacesel == 0)) {
808  continue;
809  }
810 
813  }
814 
815  MEM_freeN(ms->objects_edit);
816  MEM_freeN(ms);
817  op->customdata = NULL;
818 }
819 
821 {
822  int i, iterations;
823 
824  if (!minimize_stretch_init(C, op)) {
825  return OPERATOR_CANCELLED;
826  }
827 
828  iterations = RNA_int_get(op->ptr, "iterations");
829  for (i = 0; i < iterations; i++) {
830  minimize_stretch_iteration(C, op, false);
831  }
832  minimize_stretch_exit(C, op, false);
833 
834  return OPERATOR_FINISHED;
835 }
836 
837 static int minimize_stretch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
838 {
839  MinStretch *ms;
840 
841  if (!minimize_stretch_init(C, op)) {
842  return OPERATOR_CANCELLED;
843  }
844 
845  minimize_stretch_iteration(C, op, true);
846 
847  ms = op->customdata;
850 
851  return OPERATOR_RUNNING_MODAL;
852 }
853 
854 static int minimize_stretch_modal(bContext *C, wmOperator *op, const wmEvent *event)
855 {
856  MinStretch *ms = op->customdata;
857 
858  switch (event->type) {
859  case EVT_ESCKEY:
860  case RIGHTMOUSE:
861  minimize_stretch_exit(C, op, true);
862  return OPERATOR_CANCELLED;
863  case EVT_RETKEY:
864  case EVT_PADENTER:
865  case LEFTMOUSE:
866  minimize_stretch_exit(C, op, false);
867  return OPERATOR_FINISHED;
868  case EVT_PADPLUSKEY:
869  case WHEELUPMOUSE:
870  if (event->val == KM_PRESS) {
871  if (ms->blend < 0.95f) {
872  ms->blend += 0.1f;
873  ms->lasttime = 0.0f;
874  RNA_float_set(op->ptr, "blend", ms->blend);
875  minimize_stretch_iteration(C, op, true);
876  }
877  }
878  break;
879  case EVT_PADMINUS:
880  case WHEELDOWNMOUSE:
881  if (event->val == KM_PRESS) {
882  if (ms->blend > 0.05f) {
883  ms->blend -= 0.1f;
884  ms->lasttime = 0.0f;
885  RNA_float_set(op->ptr, "blend", ms->blend);
886  minimize_stretch_iteration(C, op, true);
887  }
888  }
889  break;
890  case TIMER:
891  if (ms->timer == event->customdata) {
892  double start = PIL_check_seconds_timer();
893 
894  do {
895  minimize_stretch_iteration(C, op, true);
896  } while (PIL_check_seconds_timer() - start < 0.01);
897  }
898  break;
899  }
900 
901  if (ms->iterations && ms->i >= ms->iterations) {
902  minimize_stretch_exit(C, op, false);
903  return OPERATOR_FINISHED;
904  }
905 
906  return OPERATOR_RUNNING_MODAL;
907 }
908 
910 {
911  minimize_stretch_exit(C, op, true);
912 }
913 
915 {
916  /* identifiers */
917  ot->name = "Minimize Stretch";
918  ot->idname = "UV_OT_minimize_stretch";
920  ot->description = "Reduce UV stretching by relaxing angles";
921 
922  /* api callbacks */
928 
929  /* properties */
931  "fill_holes",
932  1,
933  "Fill Holes",
934  "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and "
935  "preserve symmetry");
937  "blend",
938  0.0f,
939  0.0f,
940  1.0f,
941  "Blend",
942  "Blend factor between stretch minimized and original",
943  0.0f,
944  1.0f);
946  "iterations",
947  0,
948  0,
949  INT_MAX,
950  "Iterations",
951  "Number of iterations to run, 0 is unlimited when run interactively",
952  0,
953  100);
954 }
955 
958 /* -------------------------------------------------------------------- */
962 static void uvedit_pack_islands(const Scene *scene, Object *ob, BMesh *bm)
963 {
964  const UnwrapOptions options = {
965  .topology_from_uvs = true,
966  .only_selected_faces = false,
967  .only_selected_uvs = true,
968  .fill_holes = false,
969  .correct_aspect = false,
970  };
971 
972  bool rotate = true;
973  bool ignore_pinned = false;
974 
975  ParamHandle *handle;
976  handle = construct_param_handle(scene, ob, bm, &options, NULL);
977  param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
978  param_flush(handle);
979  param_delete(handle);
980 }
981 
989  Object **objects,
990  const uint objects_len,
991  const UnwrapOptions *options,
992  bool rotate,
993  bool ignore_pinned)
994 {
995  ParamHandle *handle;
996  handle = construct_param_handle_multi(scene, objects, objects_len, options, NULL);
997  param_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
998  param_flush(handle);
999  param_delete(handle);
1000 
1001  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1002  Object *obedit = objects[ob_index];
1005  }
1006 }
1007 
1009 {
1010  ViewLayer *view_layer = CTX_data_view_layer(C);
1011  const Scene *scene = CTX_data_scene(C);
1012 
1013  const UnwrapOptions options = {
1014  .topology_from_uvs = true,
1015  .only_selected_faces = true,
1016  .only_selected_uvs = true,
1017  .fill_holes = false,
1018  .correct_aspect = true,
1019  };
1020 
1021  bool rotate = RNA_boolean_get(op->ptr, "rotate");
1022 
1023  uint objects_len = 0;
1025  view_layer, CTX_wm_view3d(C), &objects_len);
1026 
1027  if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
1028  MEM_freeN(objects);
1029  return OPERATOR_CANCELLED;
1030  }
1031 
1032  if (RNA_struct_property_is_set(op->ptr, "margin")) {
1033  scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
1034  }
1035  else {
1036  RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
1037  }
1038 
1040  objects,
1041  objects_len,
1042  &(struct UVPackIsland_Params){
1043  .rotate = rotate,
1044  .rotate_align_axis = -1,
1045  .only_selected_uvs = true,
1046  .only_selected_faces = true,
1047  .correct_aspect = true,
1048  });
1049 
1050  MEM_freeN(objects);
1051 
1052  return OPERATOR_FINISHED;
1053 }
1054 
1056 {
1057  /* identifiers */
1058  ot->name = "Pack Islands";
1059  ot->idname = "UV_OT_pack_islands";
1060  ot->description = "Transform all islands so that they fill up the UV space as much as possible";
1061 
1063 
1064  /* api callbacks */
1067 
1068  /* properties */
1069  RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
1071  ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
1072 }
1073 
1076 /* -------------------------------------------------------------------- */
1081 {
1082  const Scene *scene = CTX_data_scene(C);
1083  ViewLayer *view_layer = CTX_data_view_layer(C);
1085  const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
1086 
1087  const UnwrapOptions options = {
1088  .topology_from_uvs = true,
1089  .only_selected_faces = true,
1090  .only_selected_uvs = true,
1091  .fill_holes = false,
1092  .correct_aspect = true,
1093  };
1094 
1095  uint objects_len = 0;
1097  view_layer, CTX_wm_view3d(C), &objects_len);
1098 
1099  if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
1100  MEM_freeN(objects);
1101  return OPERATOR_CANCELLED;
1102  }
1103 
1104  ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, &options, NULL);
1105  param_average(handle, false);
1106  param_flush(handle);
1107  param_delete(handle);
1108 
1109  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1110  Object *obedit = objects[ob_index];
1111  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1112 
1113  if (synced_selection && (em->bm->totvertsel == 0)) {
1114  continue;
1115  }
1116 
1119  }
1120  MEM_freeN(objects);
1121  return OPERATOR_FINISHED;
1122 }
1123 
1125 {
1126  /* identifiers */
1127  ot->name = "Average Islands Scale";
1128  ot->idname = "UV_OT_average_islands_scale";
1129  ot->description = "Average the size of separate UV islands, based on their area in 3D space";
1130 
1132 
1133  /* api callbacks */
1136 }
1137 
1140 /* -------------------------------------------------------------------- */
1144 static struct {
1148 
1150 {
1151  ParamHandle *handle = NULL;
1152  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1153  const bool abf = (scene->toolsettings->unwrapper == 0);
1154  bool use_subsurf;
1155 
1156  modifier_unwrap_state(obedit, scene, &use_subsurf);
1157 
1158  if (!ED_uvedit_test(obedit)) {
1159  return;
1160  }
1161 
1162  const UnwrapOptions options = {
1163  .topology_from_uvs = false,
1164  .only_selected_faces = false,
1165  .only_selected_uvs = true,
1166  .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
1167  .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
1168  };
1169 
1170  if (use_subsurf) {
1171  handle = construct_param_handle_subsurfed(scene, obedit, em, &options, NULL);
1172  }
1173  else {
1174  handle = construct_param_handle(scene, obedit, em->bm, &options, NULL);
1175  }
1176 
1177  param_lscm_begin(handle, PARAM_TRUE, abf);
1178 
1179  /* Create or increase size of g_live_unwrap.handles array */
1180  if (g_live_unwrap.handles == NULL) {
1181  g_live_unwrap.len_alloc = 32;
1182  g_live_unwrap.handles = MEM_mallocN(sizeof(ParamHandle *) * g_live_unwrap.len_alloc,
1183  "uvedit_live_unwrap_liveHandles");
1184  g_live_unwrap.len = 0;
1185  }
1186  if (g_live_unwrap.len >= g_live_unwrap.len_alloc) {
1187  g_live_unwrap.len_alloc *= 2;
1188  g_live_unwrap.handles = MEM_reallocN(g_live_unwrap.handles,
1189  sizeof(ParamHandle *) * g_live_unwrap.len_alloc);
1190  }
1191  g_live_unwrap.handles[g_live_unwrap.len] = handle;
1192  g_live_unwrap.len++;
1193 }
1194 
1196 {
1197  if (g_live_unwrap.handles) {
1198  for (int i = 0; i < g_live_unwrap.len; i++) {
1199  param_lscm_solve(g_live_unwrap.handles[i], NULL, NULL);
1200  param_flush(g_live_unwrap.handles[i]);
1201  }
1202  }
1203 }
1204 
1205 void ED_uvedit_live_unwrap_end(short cancel)
1206 {
1207  if (g_live_unwrap.handles) {
1208  for (int i = 0; i < g_live_unwrap.len; i++) {
1209  param_lscm_end(g_live_unwrap.handles[i]);
1210  if (cancel) {
1211  param_flush_restore(g_live_unwrap.handles[i]);
1212  }
1213  param_delete(g_live_unwrap.handles[i]);
1214  }
1215  MEM_freeN(g_live_unwrap.handles);
1216  g_live_unwrap.handles = NULL;
1217  g_live_unwrap.len = 0;
1218  g_live_unwrap.len_alloc = 0;
1219  }
1220 }
1221 
1224 /* -------------------------------------------------------------------- */
1228 #define VIEW_ON_EQUATOR 0
1229 #define VIEW_ON_POLES 1
1230 #define ALIGN_TO_OBJECT 2
1231 
1232 #define POLAR_ZX 0
1233 #define POLAR_ZY 1
1234 
1235 static void uv_map_transform_calc_bounds(BMEditMesh *em, float r_min[3], float r_max[3])
1236 {
1237  BMFace *efa;
1238  BMIter iter;
1239  INIT_MINMAX(r_min, r_max);
1240  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1241  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1242  BM_face_calc_bounds_expand(efa, r_min, r_max);
1243  }
1244  }
1245 }
1246 
1247 static void uv_map_transform_calc_center_median(BMEditMesh *em, float r_center[3])
1248 {
1249  BMFace *efa;
1250  BMIter iter;
1251  uint center_accum_num = 0;
1252  zero_v3(r_center);
1253  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1254  if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1255  float center[3];
1257  add_v3_v3(r_center, center);
1258  center_accum_num += 1;
1259  }
1260  }
1261  mul_v3_fl(r_center, 1.0f / (float)center_accum_num);
1262 }
1263 
1265  View3D *v3d,
1266  Object *ob,
1267  BMEditMesh *em,
1268  float r_center[3],
1269  float r_bounds[2][3])
1270 {
1271  /* only operates on the edit object - this is all that's needed now */
1272  const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS;
1273 
1274  float bounds[2][3];
1275  INIT_MINMAX(bounds[0], bounds[1]);
1276  bool is_minmax_set = false;
1277 
1278  switch (around) {
1279  case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */
1280  {
1282  is_minmax_set = true;
1283  mid_v3_v3v3(r_center, bounds[0], bounds[1]);
1284  break;
1285  }
1286  case V3D_AROUND_CENTER_MEDIAN: {
1288  break;
1289  }
1290  case V3D_AROUND_CURSOR: /* cursor center */
1291  {
1292  invert_m4_m4(ob->imat, ob->obmat);
1293  mul_v3_m4v3(r_center, ob->imat, scene->cursor.location);
1294  break;
1295  }
1296  case V3D_AROUND_ACTIVE: {
1297  BMEditSelection ese;
1298  if (BM_select_history_active_get(em->bm, &ese)) {
1299  BM_editselection_center(&ese, r_center);
1300  break;
1301  }
1303  }
1304  case V3D_AROUND_LOCAL_ORIGINS: /* object center */
1305  default:
1306  zero_v3(r_center);
1307  break;
1308  }
1309 
1310  /* if this is passed, always set! */
1311  if (r_bounds) {
1312  if (!is_minmax_set) {
1314  }
1315  copy_v3_v3(r_bounds[0], bounds[0]);
1316  copy_v3_v3(r_bounds[1], bounds[1]);
1317  }
1318 }
1319 
1320 static void uv_map_rotation_matrix_ex(float result[4][4],
1321  RegionView3D *rv3d,
1322  Object *ob,
1323  float upangledeg,
1324  float sideangledeg,
1325  float radius,
1326  const float offset[4])
1327 {
1328  float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
1329  float sideangle = 0.0f, upangle = 0.0f;
1330 
1331  /* get rotation of the current view matrix */
1332  if (rv3d) {
1333  copy_m4_m4(viewmatrix, rv3d->viewmat);
1334  }
1335  else {
1336  unit_m4(viewmatrix);
1337  }
1338 
1339  /* but shifting */
1340  zero_v3(viewmatrix[3]);
1341 
1342  /* get rotation of the current object matrix */
1343  copy_m4_m4(rotobj, ob->obmat);
1344  zero_v3(rotobj[3]);
1345 
1346  /* but shifting */
1347  add_v4_v4(rotobj[3], offset);
1348  rotobj[3][3] = 0.0f;
1349 
1350  zero_m4(rotup);
1351  zero_m4(rotside);
1352 
1353  /* Compensate front/side.. against opengl x,y,z world definition.
1354  * This is "a sledgehammer to crack a nut" (overkill), a few plus minus 1 will do here.
1355  * I wanted to keep the reason here, so we're rotating. */
1356  sideangle = (float)M_PI * (sideangledeg + 180.0f) / 180.0f;
1357  rotside[0][0] = cosf(sideangle);
1358  rotside[0][1] = -sinf(sideangle);
1359  rotside[1][0] = sinf(sideangle);
1360  rotside[1][1] = cosf(sideangle);
1361  rotside[2][2] = 1.0f;
1362 
1363  upangle = (float)M_PI * upangledeg / 180.0f;
1364  rotup[1][1] = cosf(upangle) / radius;
1365  rotup[1][2] = -sinf(upangle) / radius;
1366  rotup[2][1] = sinf(upangle) / radius;
1367  rotup[2][2] = cosf(upangle) / radius;
1368  rotup[0][0] = 1.0f / radius;
1369 
1370  /* calculate transforms*/
1371  mul_m4_series(result, rotup, rotside, viewmatrix, rotobj);
1372 }
1373 
1374 static void uv_map_rotation_matrix(float result[4][4],
1375  RegionView3D *rv3d,
1376  Object *ob,
1377  float upangledeg,
1378  float sideangledeg,
1379  float radius)
1380 {
1381  const float offset[4] = {0};
1382  uv_map_rotation_matrix_ex(result, rv3d, ob, upangledeg, sideangledeg, radius, offset);
1383 }
1384 
1385 static void uv_map_transform(bContext *C, wmOperator *op, float rotmat[4][4])
1386 {
1387  /* context checks are messy here, making it work in both 3d view and uv editor */
1388  Object *obedit = CTX_data_edit_object(C);
1390  /* common operator properties */
1391  int align = RNA_enum_get(op->ptr, "align");
1392  int direction = RNA_enum_get(op->ptr, "direction");
1393  float radius = RNA_struct_find_property(op->ptr, "radius") ? RNA_float_get(op->ptr, "radius") :
1394  1.0f;
1395  float upangledeg, sideangledeg;
1396 
1397  if (direction == VIEW_ON_EQUATOR) {
1398  upangledeg = 90.0f;
1399  sideangledeg = 0.0f;
1400  }
1401  else {
1402  upangledeg = 0.0f;
1403  if (align == POLAR_ZY) {
1404  sideangledeg = 0.0f;
1405  }
1406  else {
1407  sideangledeg = 90.0f;
1408  }
1409  }
1410 
1411  /* be compatible to the "old" sphere/cylinder mode */
1412  if (direction == ALIGN_TO_OBJECT) {
1413  unit_m4(rotmat);
1414  }
1415  else {
1416  uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius);
1417  }
1418 }
1419 
1420 static void uv_transform_properties(wmOperatorType *ot, int radius)
1421 {
1422  static const EnumPropertyItem direction_items[] = {
1423  {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"},
1424  {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"},
1425  {ALIGN_TO_OBJECT,
1426  "ALIGN_TO_OBJECT",
1427  0,
1428  "Align to Object",
1429  "Align according to object transform"},
1430  {0, NULL, 0, NULL, NULL},
1431  };
1432  static const EnumPropertyItem align_items[] = {
1433  {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"},
1434  {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"},
1435  {0, NULL, 0, NULL, NULL},
1436  };
1437 
1438  RNA_def_enum(ot->srna,
1439  "direction",
1440  direction_items,
1442  "Direction",
1443  "Direction of the sphere or cylinder");
1444  RNA_def_enum(ot->srna,
1445  "align",
1446  align_items,
1448  "Align",
1449  "How to determine rotation around the pole");
1450  if (radius) {
1452  "radius",
1453  1.0f,
1454  0.0f,
1455  FLT_MAX,
1456  "Radius",
1457  "Radius of the sphere or cylinder",
1458  0.0001f,
1459  100.0f);
1460  }
1461 }
1462 
1463 static void correct_uv_aspect(Object *ob, BMEditMesh *em)
1464 {
1465  BMLoop *l;
1466  BMIter iter, liter;
1467  MLoopUV *luv;
1468  BMFace *efa;
1469  float scale, aspx, aspy;
1470 
1471  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1472 
1473  ED_uvedit_get_aspect(ob, &aspx, &aspy);
1474 
1475  if (aspx == aspy) {
1476  return;
1477  }
1478 
1479  if (aspx > aspy) {
1480  scale = aspy / aspx;
1481 
1482  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1483  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1484  continue;
1485  }
1486 
1487  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1488  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1489  luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f;
1490  }
1491  }
1492  }
1493  else {
1494  scale = aspx / aspy;
1495 
1496  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1497  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1498  continue;
1499  }
1500 
1501  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1502  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1503  luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f;
1504  }
1505  }
1506  }
1507 }
1508 
1509 #undef VIEW_ON_EQUATOR
1510 #undef VIEW_ON_POLES
1511 #undef ALIGN_TO_OBJECT
1512 
1513 #undef POLAR_ZX
1514 #undef POLAR_ZY
1515 
1518 /* -------------------------------------------------------------------- */
1522 static void uv_map_clip_correct_properties_ex(wmOperatorType *ot, bool clip_to_bounds)
1523 {
1525  "correct_aspect",
1526  1,
1527  "Correct Aspect",
1528  "Map UVs taking image aspect ratio into account");
1529  /* Optional, since not all unwrapping types need to be clipped. */
1530  if (clip_to_bounds) {
1532  "clip_to_bounds",
1533  0,
1534  "Clip to Bounds",
1535  "Clip UV coordinates to bounds after unwrapping");
1536  }
1538  "scale_to_bounds",
1539  0,
1540  "Scale to Bounds",
1541  "Scale UV coordinates to bounds after unwrapping");
1542 }
1543 
1545 {
1547 }
1548 
1549 static void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOperator *op)
1550 {
1551  BMFace *efa;
1552  BMLoop *l;
1553  BMIter iter, liter;
1554  MLoopUV *luv;
1555  float dx, dy, min[2], max[2];
1556  const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
1557  const bool clip_to_bounds = (RNA_struct_find_property(op->ptr, "clip_to_bounds") &&
1558  RNA_boolean_get(op->ptr, "clip_to_bounds"));
1559  const bool scale_to_bounds = RNA_boolean_get(op->ptr, "scale_to_bounds");
1560 
1561  INIT_MINMAX2(min, max);
1562 
1563  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1564  Object *ob = objects[ob_index];
1565 
1567  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1568 
1569  /* correct for image aspect ratio */
1570  if (correct_aspect) {
1571  correct_uv_aspect(ob, em);
1572  }
1573 
1574  if (scale_to_bounds) {
1575  /* find uv limits */
1576  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1577  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1578  continue;
1579  }
1580 
1581  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1582  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1583  minmax_v2v2_v2(min, max, luv->uv);
1584  }
1585  }
1586  }
1587  else if (clip_to_bounds) {
1588  /* clipping and wrapping */
1589  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1590  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1591  continue;
1592  }
1593 
1594  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1595  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1596  clamp_v2(luv->uv, 0.0f, 1.0f);
1597  }
1598  }
1599  }
1600  }
1601 
1602  if (scale_to_bounds) {
1603  /* rescale UV to be in 1/1 */
1604  dx = (max[0] - min[0]);
1605  dy = (max[1] - min[1]);
1606 
1607  if (dx > 0.0f) {
1608  dx = 1.0f / dx;
1609  }
1610  if (dy > 0.0f) {
1611  dy = 1.0f / dy;
1612  }
1613 
1614  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1615  Object *ob = objects[ob_index];
1616 
1618  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1619 
1620  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1621  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1622  continue;
1623  }
1624 
1625  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1626  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1627 
1628  luv->uv[0] = (luv->uv[0] - min[0]) * dx;
1629  luv->uv[1] = (luv->uv[1] - min[1]) * dy;
1630  }
1631  }
1632  }
1633  }
1634 }
1635 
1637 {
1638  uv_map_clip_correct_multi(&ob, 1, op);
1639 }
1640 
1643 /* -------------------------------------------------------------------- */
1647 /* Assumes UV Map exists, doesn't run update funcs. */
1648 static void uvedit_unwrap(const Scene *scene,
1649  Object *obedit,
1650  const UnwrapOptions *options,
1651  UnwrapResultInfo *result_info)
1652 {
1653  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1654  if (!CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV)) {
1655  return;
1656  }
1657 
1658  bool use_subsurf;
1659  modifier_unwrap_state(obedit, scene, &use_subsurf);
1660 
1661  ParamHandle *handle;
1662  if (use_subsurf) {
1663  handle = construct_param_handle_subsurfed(scene, obedit, em, options, result_info);
1664  }
1665  else {
1666  handle = construct_param_handle(scene, obedit, em->bm, options, result_info);
1667  }
1668 
1670  param_lscm_solve(handle,
1671  result_info ? &result_info->count_changed : NULL,
1672  result_info ? &result_info->count_failed : NULL);
1673  param_lscm_end(handle);
1674 
1675  param_average(handle, true);
1676 
1677  param_flush(handle);
1678 
1679  param_delete(handle);
1680 }
1681 
1682 static void uvedit_unwrap_multi(const Scene *scene,
1683  Object **objects,
1684  const int objects_len,
1685  const UnwrapOptions *options,
1686  UnwrapResultInfo *result_info)
1687 {
1688  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1689  Object *obedit = objects[ob_index];
1690  uvedit_unwrap(scene, obedit, options, result_info);
1693  }
1694 }
1695 
1696 void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len)
1697 {
1699  const UnwrapOptions options = {
1700  .topology_from_uvs = false,
1701  .only_selected_faces = false,
1702  .only_selected_uvs = true,
1703  .fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
1704  .correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
1705  };
1706 
1707  bool rotate = true;
1708  bool ignore_pinned = true;
1709 
1710  uvedit_unwrap_multi(scene, objects, objects_len, &options, NULL);
1711  uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
1712  }
1713 }
1714 
1715 enum {
1718 };
1719 
1721 {
1722  ViewLayer *view_layer = CTX_data_view_layer(C);
1723  const Scene *scene = CTX_data_scene(C);
1724  int method = RNA_enum_get(op->ptr, "method");
1725  const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
1726  int reported_errors = 0;
1727  /* We will report an error unless at least one object
1728  * has the subsurf modifier in the right place. */
1729  bool subsurf_error = use_subsurf;
1730 
1731  uint objects_len = 0;
1733  view_layer, CTX_wm_view3d(C), &objects_len);
1734 
1735  const UnwrapOptions options = {
1736  .topology_from_uvs = false,
1737  .only_selected_faces = true,
1738  .only_selected_uvs = true,
1739  .fill_holes = RNA_boolean_get(op->ptr, "fill_holes"),
1740  .correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
1741  };
1742 
1743  bool rotate = true;
1744  bool ignore_pinned = true;
1745 
1746  if (!uvedit_have_selection_multi(scene, objects, objects_len, &options)) {
1747  MEM_freeN(objects);
1748  return OPERATOR_CANCELLED;
1749  }
1750 
1751  /* add uvs if they don't exist yet */
1752  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1753  Object *obedit = objects[ob_index];
1754  float obsize[3];
1755  bool use_subsurf_final;
1756 
1757  if (!ED_uvedit_ensure_uvs(obedit)) {
1758  continue;
1759  }
1760 
1761  if (subsurf_error) {
1762  /* Double up the check here but better keep uvedit_unwrap interface simple and not
1763  * pass operator for warning append. */
1764  modifier_unwrap_state(obedit, scene, &use_subsurf_final);
1765  if (use_subsurf_final) {
1766  subsurf_error = false;
1767  }
1768  }
1769 
1770  if (reported_errors & (UNWRAP_ERROR_NONUNIFORM | UNWRAP_ERROR_NEGATIVE)) {
1771  continue;
1772  }
1773 
1774  mat4_to_size(obsize, obedit->obmat);
1775  if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) {
1776  if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) {
1777  BKE_report(op->reports,
1778  RPT_INFO,
1779  "Object has non-uniform scale, unwrap will operate on a non-scaled version of "
1780  "the mesh");
1781  reported_errors |= UNWRAP_ERROR_NONUNIFORM;
1782  }
1783  }
1784  else if (is_negative_m4(obedit->obmat)) {
1785  if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) {
1786  BKE_report(
1787  op->reports,
1788  RPT_INFO,
1789  "Object has negative scale, unwrap will operate on a non-flipped version of the mesh");
1790  reported_errors |= UNWRAP_ERROR_NEGATIVE;
1791  }
1792  }
1793  }
1794 
1795  if (subsurf_error) {
1796  BKE_report(op->reports,
1797  RPT_INFO,
1798  "Subdivision Surface modifier needs to be first to work with unwrap");
1799  }
1800 
1801  /* remember last method for live unwrap */
1802  if (RNA_struct_property_is_set(op->ptr, "method")) {
1803  scene->toolsettings->unwrapper = method;
1804  }
1805  else {
1806  RNA_enum_set(op->ptr, "method", scene->toolsettings->unwrapper);
1807  }
1808 
1809  /* remember packing margin */
1810  if (RNA_struct_property_is_set(op->ptr, "margin")) {
1811  scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
1812  }
1813  else {
1814  RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
1815  }
1816 
1817  if (options.fill_holes) {
1819  }
1820  else {
1822  }
1823 
1824  if (options.correct_aspect) {
1826  }
1827  else {
1829  }
1830 
1831  if (use_subsurf) {
1833  }
1834  else {
1836  }
1837 
1838  /* execute unwrap */
1839  UnwrapResultInfo result_info = {
1840  .count_changed = 0,
1841  .count_failed = 0,
1842  };
1843  uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info);
1844  uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
1845 
1846  MEM_freeN(objects);
1847 
1848  if (result_info.count_failed == 0 && result_info.count_changed == 0) {
1849  BKE_report(op->reports,
1850  RPT_WARNING,
1851  "Unwrap could not solve any island(s), edge seams may need to be added");
1852  }
1853  else if (result_info.count_failed) {
1854  BKE_reportf(op->reports,
1855  RPT_WARNING,
1856  "Unwrap failed to solve %d of %d island(s), edge seams may need to be added",
1857  result_info.count_failed,
1858  result_info.count_changed + result_info.count_failed);
1859  }
1860 
1861  return OPERATOR_FINISHED;
1862 }
1863 
1865 {
1866  static const EnumPropertyItem method_items[] = {
1867  {0, "ANGLE_BASED", 0, "Angle Based", ""},
1868  {1, "CONFORMAL", 0, "Conformal", ""},
1869  {0, NULL, 0, NULL, NULL},
1870  };
1871 
1872  /* identifiers */
1873  ot->name = "Unwrap";
1874  ot->description = "Unwrap the mesh of the object being edited";
1875  ot->idname = "UV_OT_unwrap";
1877 
1878  /* api callbacks */
1879  ot->exec = unwrap_exec;
1881 
1882  /* properties */
1883  RNA_def_enum(ot->srna,
1884  "method",
1885  method_items,
1886  0,
1887  "Method",
1888  "Unwrapping method (Angle Based usually gives better results than Conformal, while "
1889  "being somewhat slower)");
1891  "fill_holes",
1892  1,
1893  "Fill Holes",
1894  "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and "
1895  "preserve symmetry");
1897  "correct_aspect",
1898  1,
1899  "Correct Aspect",
1900  "Map UVs taking image aspect ratio into account");
1902  ot->srna,
1903  "use_subsurf_data",
1904  0,
1905  "Use Subdivision Surface",
1906  "Map UVs taking vertex position after Subdivision Surface modifier has been applied");
1908  ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
1909 }
1910 
1913 /* -------------------------------------------------------------------- */
1917 /* Ignore all areas below this, as the UV's get zeroed. */
1918 static const float smart_uv_project_area_ignore = 1e-12f;
1919 
1920 typedef struct ThickFace {
1921  float area;
1924 
1925 static int smart_uv_project_thickface_area_cmp_fn(const void *tf_a_p, const void *tf_b_p)
1926 {
1927 
1928  const ThickFace *tf_a = (ThickFace *)tf_a_p;
1929  const ThickFace *tf_b = (ThickFace *)tf_b_p;
1930 
1931  /* Ignore the area of small faces.
1932  * Also, order checks so `!isfinite(...)` values are counted as zero area. */
1933  if (!((tf_a->area > smart_uv_project_area_ignore) ||
1934  (tf_b->area > smart_uv_project_area_ignore))) {
1935  return 0;
1936  }
1937 
1938  if (tf_a->area < tf_b->area) {
1939  return 1;
1940  }
1941  if (tf_a->area > tf_b->area) {
1942  return -1;
1943  }
1944  return 0;
1945 }
1946 
1948  const uint thick_faces_len,
1949  BMesh *bm,
1950  const float project_angle_limit_half_cos,
1951  const float project_angle_limit_cos,
1952  const float area_weight,
1953  float (**r_project_normal_array)[3])
1954 {
1955  if (UNLIKELY(thick_faces_len == 0)) {
1956  *r_project_normal_array = NULL;
1957  return 0;
1958  }
1959 
1960  const float *project_normal = thick_faces[0].efa->no;
1961 
1962  const ThickFace **project_thick_faces = NULL;
1963  BLI_array_declare(project_thick_faces);
1964 
1965  float(*project_normal_array)[3] = NULL;
1966  BLI_array_declare(project_normal_array);
1967 
1969 
1970  while (true) {
1971  for (int f_index = thick_faces_len - 1; f_index >= 0; f_index--) {
1972  if (BM_elem_flag_test(thick_faces[f_index].efa, BM_ELEM_TAG)) {
1973  continue;
1974  }
1975 
1976  if (dot_v3v3(thick_faces[f_index].efa->no, project_normal) > project_angle_limit_half_cos) {
1977  BLI_array_append(project_thick_faces, &thick_faces[f_index]);
1978  BM_elem_flag_set(thick_faces[f_index].efa, BM_ELEM_TAG, true);
1979  }
1980  }
1981 
1982  float average_normal[3] = {0.0f, 0.0f, 0.0f};
1983 
1984  if (area_weight <= 0.0f) {
1985  for (int f_proj_index = 0; f_proj_index < BLI_array_len(project_thick_faces);
1986  f_proj_index++) {
1987  const ThickFace *tf = project_thick_faces[f_proj_index];
1988  add_v3_v3(average_normal, tf->efa->no);
1989  }
1990  }
1991  else if (area_weight >= 1.0f) {
1992  for (int f_proj_index = 0; f_proj_index < BLI_array_len(project_thick_faces);
1993  f_proj_index++) {
1994  const ThickFace *tf = project_thick_faces[f_proj_index];
1995  madd_v3_v3fl(average_normal, tf->efa->no, tf->area);
1996  }
1997  }
1998  else {
1999  for (int f_proj_index = 0; f_proj_index < BLI_array_len(project_thick_faces);
2000  f_proj_index++) {
2001  const ThickFace *tf = project_thick_faces[f_proj_index];
2002  const float area_blend = (tf->area * area_weight) + (1.0f - area_weight);
2003  madd_v3_v3fl(average_normal, tf->efa->no, area_blend);
2004  }
2005  }
2006 
2007  /* Avoid NAN. */
2008  if (normalize_v3(average_normal) != 0.0f) {
2009  float(*normal)[3] = BLI_array_append_ret(project_normal_array);
2010  copy_v3_v3(*normal, average_normal);
2011  }
2012 
2013  /* Find the most unique angle that points away from other normals. */
2014  float anble_best = 1.0f;
2015  uint angle_best_index = 0;
2016 
2017  for (int f_index = thick_faces_len - 1; f_index >= 0; f_index--) {
2018  if (BM_elem_flag_test(thick_faces[f_index].efa, BM_ELEM_TAG)) {
2019  continue;
2020  }
2021 
2022  float angle_test = -1.0f;
2023  for (int p_index = 0; p_index < BLI_array_len(project_normal_array); p_index++) {
2024  angle_test = max_ff(angle_test,
2025  dot_v3v3(project_normal_array[p_index], thick_faces[f_index].efa->no));
2026  }
2027 
2028  if (angle_test < anble_best) {
2029  anble_best = angle_test;
2030  angle_best_index = f_index;
2031  }
2032  }
2033 
2034  if (anble_best < project_angle_limit_cos) {
2035  project_normal = thick_faces[angle_best_index].efa->no;
2036  BLI_array_clear(project_thick_faces);
2037  BLI_array_append(project_thick_faces, &thick_faces[angle_best_index]);
2038  BM_elem_flag_enable(thick_faces[angle_best_index].efa, BM_ELEM_TAG);
2039  }
2040  else {
2041  if (BLI_array_len(project_normal_array) >= 1) {
2042  break;
2043  }
2044  }
2045  }
2046 
2047  BLI_array_free(project_thick_faces);
2049 
2050  *r_project_normal_array = project_normal_array;
2051  return BLI_array_len(project_normal_array);
2052 }
2053 
2055 {
2057  ViewLayer *view_layer = CTX_data_view_layer(C);
2058 
2059  /* May be NULL. */
2060  View3D *v3d = CTX_wm_view3d(C);
2061 
2062  const float project_angle_limit = RNA_float_get(op->ptr, "angle_limit");
2063  const float island_margin = RNA_float_get(op->ptr, "island_margin");
2064  const float area_weight = RNA_float_get(op->ptr, "area_weight");
2065 
2066  const float project_angle_limit_cos = cosf(project_angle_limit);
2067  const float project_angle_limit_half_cos = cosf(project_angle_limit / 2);
2068 
2069  /* Memory arena for list links (cleared for each object). */
2071 
2072  uint objects_len = 0;
2074  view_layer, v3d, &objects_len);
2075 
2076  Object **objects_changed = MEM_mallocN(sizeof(*objects_changed) * objects_len, __func__);
2077  uint object_changed_len = 0;
2078 
2079  BMFace *efa;
2080  BMIter iter;
2081  uint ob_index;
2082 
2083  for (ob_index = 0; ob_index < objects_len; ob_index++) {
2084  Object *obedit = objects[ob_index];
2085  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2086  bool changed = false;
2087 
2088  if (!ED_uvedit_ensure_uvs(obedit)) {
2089  continue;
2090  }
2091 
2092  const uint cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2093  ThickFace *thick_faces = MEM_mallocN(sizeof(*thick_faces) * em->bm->totface, __func__);
2094 
2095  uint thick_faces_len = 0;
2096  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2097  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2098  continue;
2099  }
2100  thick_faces[thick_faces_len].area = BM_face_calc_area(efa);
2101  thick_faces[thick_faces_len].efa = efa;
2102  thick_faces_len++;
2103  }
2104 
2105  qsort(thick_faces, thick_faces_len, sizeof(ThickFace), smart_uv_project_thickface_area_cmp_fn);
2106 
2107  /* Remove all zero area faces. */
2108  while ((thick_faces_len > 0) &&
2109  !(thick_faces[thick_faces_len - 1].area > smart_uv_project_area_ignore)) {
2110 
2111  /* Zero UV's so they don't overlap with other faces being unwrapped. */
2112  BMIter liter;
2113  BMLoop *l;
2114  BM_ITER_ELEM (l, &liter, thick_faces[thick_faces_len - 1].efa, BM_LOOPS_OF_FACE) {
2115  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2116  zero_v2(luv->uv);
2117  changed = true;
2118  }
2119 
2120  thick_faces_len -= 1;
2121  }
2122 
2123  float(*project_normal_array)[3] = NULL;
2124  int project_normals_len = smart_uv_project_calculate_project_normals(
2125  thick_faces,
2126  thick_faces_len,
2127  em->bm,
2128  project_angle_limit_half_cos,
2129  project_angle_limit_cos,
2130  area_weight,
2131  &project_normal_array);
2132 
2133  if (project_normals_len == 0) {
2134  MEM_freeN(thick_faces);
2135  BLI_assert(project_normal_array == NULL);
2136  continue;
2137  }
2138 
2139  /* After finding projection vectors, we find the uv positions. */
2140  LinkNode **thickface_project_groups = MEM_callocN(
2141  sizeof(*thickface_project_groups) * project_normals_len, __func__);
2142 
2143  BLI_memarena_clear(arena);
2144 
2145  for (int f_index = thick_faces_len - 1; f_index >= 0; f_index--) {
2146  const float *f_normal = thick_faces[f_index].efa->no;
2147 
2148  float angle_best = dot_v3v3(f_normal, project_normal_array[0]);
2149  uint angle_best_index = 0;
2150 
2151  for (int p_index = 1; p_index < project_normals_len; p_index++) {
2152  const float angle_test = dot_v3v3(f_normal, project_normal_array[p_index]);
2153  if (angle_test > angle_best) {
2154  angle_best = angle_test;
2155  angle_best_index = p_index;
2156  }
2157  }
2158 
2160  &thickface_project_groups[angle_best_index], &thick_faces[f_index], arena);
2161  }
2162 
2163  for (int p_index = 0; p_index < project_normals_len; p_index++) {
2164  if (thickface_project_groups[p_index] == NULL) {
2165  continue;
2166  }
2167 
2168  float axis_mat[3][3];
2169  axis_dominant_v3_to_m3(axis_mat, project_normal_array[p_index]);
2170 
2171  for (LinkNode *list = thickface_project_groups[p_index]; list; list = list->next) {
2172  ThickFace *tf = list->link;
2173  BMIter liter;
2174  BMLoop *l;
2175  BM_ITER_ELEM (l, &liter, tf->efa, BM_LOOPS_OF_FACE) {
2176  MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2177  mul_v2_m3v3(luv->uv, axis_mat, l->v->co);
2178  }
2179  changed = true;
2180  }
2181  }
2182 
2183  MEM_freeN(thick_faces);
2184  MEM_freeN(project_normal_array);
2185 
2186  /* No need to free the lists in 'thickface_project_groups' values as the 'arena' is used. */
2187  MEM_freeN(thickface_project_groups);
2188 
2189  if (changed) {
2190  objects_changed[object_changed_len] = objects[ob_index];
2191  object_changed_len += 1;
2192  }
2193  }
2194 
2195  BLI_memarena_free(arena);
2196 
2197  MEM_freeN(objects);
2198 
2199  /* Pack islands & Stretch to UV bounds */
2200  if (object_changed_len > 0) {
2201 
2202  scene->toolsettings->uvcalc_margin = island_margin;
2203 
2204  /* Depsgraph refresh functions are called here. */
2205  const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
2207  objects_changed,
2208  object_changed_len,
2209  &(struct UVPackIsland_Params){
2210  .rotate = true,
2211  /* We could make this optional. */
2212  .rotate_align_axis = 1,
2213  .only_selected_faces = true,
2214  .correct_aspect = correct_aspect,
2215  .use_seams = true,
2216  });
2217 
2218  uv_map_clip_correct_multi(objects_changed, object_changed_len, op);
2219  }
2220 
2221  MEM_freeN(objects_changed);
2222 
2223  return OPERATOR_FINISHED;
2224 }
2225 
2227 {
2228  PropertyRNA *prop;
2229 
2230  /* identifiers */
2231  ot->name = "Smart UV Project";
2232  ot->idname = "UV_OT_smart_project";
2233  ot->description = "Projection unwraps the selected faces of mesh objects";
2234 
2236 
2237  /* api callbacks */
2241 
2242  /* properties */
2243  prop = RNA_def_float_rotation(ot->srna,
2244  "angle_limit",
2245  0,
2246  NULL,
2247  DEG2RADF(0.0f),
2248  DEG2RADF(90.0f),
2249  "Angle Limit",
2250  "Lower for more projection groups, higher for less distortion",
2251  DEG2RADF(0.0f),
2252  DEG2RADF(89.0f));
2254 
2256  "island_margin",
2257  0.0f,
2258  0.0f,
2259  1.0f,
2260  "Island Margin",
2261  "Margin to reduce bleed from adjacent islands",
2262  0.0f,
2263  1.0f);
2265  "area_weight",
2266  0.0f,
2267  0.0f,
2268  1.0f,
2269  "Area Weight",
2270  "Weight projection's vector by faces with larger areas",
2271  0.0f,
2272  1.0f);
2273 
2275 }
2276 
2279 /* -------------------------------------------------------------------- */
2283 static int uv_from_view_exec(bContext *C, wmOperator *op);
2284 
2285 static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
2286 {
2287  View3D *v3d = CTX_wm_view3d(C);
2289  Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
2290  PropertyRNA *prop;
2291 
2292  prop = RNA_struct_find_property(op->ptr, "camera_bounds");
2293  if (!RNA_property_is_set(op->ptr, prop)) {
2294  RNA_property_boolean_set(op->ptr, prop, (camera != NULL));
2295  }
2296  prop = RNA_struct_find_property(op->ptr, "correct_aspect");
2297  if (!RNA_property_is_set(op->ptr, prop)) {
2298  RNA_property_boolean_set(op->ptr, prop, (camera == NULL));
2299  }
2300 
2301  return uv_from_view_exec(C, op);
2302 }
2303 
2305 {
2306  ViewLayer *view_layer = CTX_data_view_layer(C);
2307  const Scene *scene = CTX_data_scene(C);
2308  ARegion *region = CTX_wm_region(C);
2309  View3D *v3d = CTX_wm_view3d(C);
2311  Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
2312  BMFace *efa;
2313  BMLoop *l;
2314  BMIter iter, liter;
2315  MLoopUV *luv;
2316  float rotmat[4][4];
2317  float objects_pos_offset[4];
2318  bool changed_multi = false;
2319 
2320  const bool use_orthographic = RNA_boolean_get(op->ptr, "orthographic");
2321 
2322  /* Note: objects that aren't touched are set to NULL (to skip clipping). */
2323  uint objects_len = 0;
2325  view_layer, v3d, &objects_len);
2326 
2327  if (use_orthographic) {
2328  /* Calculate average object position. */
2329  float objects_pos_avg[4] = {0};
2330 
2331  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2332  add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]);
2333  }
2334 
2335  mul_v4_fl(objects_pos_avg, 1.0f / objects_len);
2336  negate_v4_v4(objects_pos_offset, objects_pos_avg);
2337  }
2338 
2339  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2340  Object *obedit = objects[ob_index];
2341  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2342  bool changed = false;
2343 
2344  /* add uvs if they don't exist yet */
2345  if (!ED_uvedit_ensure_uvs(obedit)) {
2346  continue;
2347  }
2348 
2349  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2350 
2351  if (use_orthographic) {
2352  uv_map_rotation_matrix_ex(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f, objects_pos_offset);
2353 
2354  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2355  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2356  continue;
2357  }
2358 
2359  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2360  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2361  BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat);
2362  }
2363  changed = true;
2364  }
2365  }
2366  else if (camera) {
2367  const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds");
2369  v3d->camera,
2370  obedit->obmat,
2371  camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f,
2372  camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f);
2373 
2374  if (uci) {
2375  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2376  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2377  continue;
2378  }
2379 
2380  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2381  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2382  BLI_uvproject_from_camera(luv->uv, l->v->co, uci);
2383  }
2384  changed = true;
2385  }
2386 
2387  MEM_freeN(uci);
2388  }
2389  }
2390  else {
2391  copy_m4_m4(rotmat, obedit->obmat);
2392 
2393  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2394  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2395  continue;
2396  }
2397 
2398  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2399  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2401  luv->uv, l->v->co, rv3d->persmat, rotmat, region->winx, region->winy);
2402  }
2403  changed = true;
2404  }
2405  }
2406 
2407  if (changed) {
2408  changed_multi = true;
2411  }
2412  else {
2413  ARRAY_DELETE_REORDER_LAST(objects, ob_index, 1, objects_len);
2414  objects_len -= 1;
2415  ob_index -= 1;
2416  }
2417  }
2418 
2419  if (changed_multi) {
2420  uv_map_clip_correct_multi(objects, objects_len, op);
2421  }
2422 
2423  MEM_freeN(objects);
2424 
2425  if (changed_multi) {
2426  return OPERATOR_FINISHED;
2427  }
2428  return OPERATOR_CANCELLED;
2429 }
2430 
2432 {
2434 
2435  if (!ED_operator_uvmap(C)) {
2436  return 0;
2437  }
2438 
2439  return (rv3d != NULL);
2440 }
2441 
2443 {
2444  /* identifiers */
2445  ot->name = "Project from View";
2446  ot->idname = "UV_OT_project_from_view";
2447  ot->description = "Project the UV vertices of the mesh as seen in current 3D view";
2448 
2450 
2451  /* api callbacks */
2455 
2456  /* properties */
2457  RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", "Use orthographic projection");
2459  "camera_bounds",
2460  1,
2461  "Camera Bounds",
2462  "Map UVs to the camera region taking resolution and aspect into account");
2464 }
2465 
2468 /* -------------------------------------------------------------------- */
2473 {
2474  ViewLayer *view_layer = CTX_data_view_layer(C);
2475  View3D *v3d = CTX_wm_view3d(C);
2476 
2477  uint objects_len = 0;
2479  view_layer, v3d, &objects_len);
2480  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2481  Object *obedit = objects[ob_index];
2482  Mesh *me = (Mesh *)obedit->data;
2483  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2484 
2485  if (em->bm->totfacesel == 0) {
2486  continue;
2487  }
2488 
2489  /* add uvs if they don't exist yet */
2490  if (!ED_uvedit_ensure_uvs(obedit)) {
2491  continue;
2492  }
2493 
2494  ED_mesh_uv_loop_reset(C, me);
2495 
2498  }
2499  MEM_freeN(objects);
2500 
2501  return OPERATOR_FINISHED;
2502 }
2503 
2505 {
2506  /* identifiers */
2507  ot->name = "Reset";
2508  ot->idname = "UV_OT_reset";
2509  ot->description = "Reset UV projection";
2510 
2512 
2513  /* api callbacks */
2514  ot->exec = reset_exec;
2516 }
2517 
2520 /* -------------------------------------------------------------------- */
2524 static void uv_sphere_project(float target[2],
2525  const float source[3],
2526  const float center[3],
2527  const float rotmat[4][4])
2528 {
2529  float pv[3];
2530 
2531  sub_v3_v3v3(pv, source, center);
2532  mul_m4_v3(rotmat, pv);
2533 
2534  map_to_sphere(&target[0], &target[1], pv[0], pv[1], pv[2]);
2535 
2536  /* split line is always zero */
2537  if (target[0] >= 1.0f) {
2538  target[0] -= 1.0f;
2539  }
2540 }
2541 
2542 static void uv_map_mirror(BMEditMesh *em, BMFace *efa)
2543 {
2544  BMLoop *l;
2545  BMIter liter;
2546  MLoopUV *luv;
2547  float **uvs = BLI_array_alloca(uvs, efa->len);
2548  float dx;
2549  int i, mi;
2550 
2551  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2552 
2553  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
2554  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2555  uvs[i] = luv->uv;
2556  }
2557 
2558  mi = 0;
2559  for (i = 1; i < efa->len; i++) {
2560  if (uvs[i][0] > uvs[mi][0]) {
2561  mi = i;
2562  }
2563  }
2564 
2565  for (i = 0; i < efa->len; i++) {
2566  if (i != mi) {
2567  dx = uvs[mi][0] - uvs[i][0];
2568  if (dx > 0.5f) {
2569  uvs[i][0] += 1.0f;
2570  }
2571  }
2572  }
2573 }
2574 
2576 {
2577  const Scene *scene = CTX_data_scene(C);
2578  View3D *v3d = CTX_wm_view3d(C);
2579 
2580  ViewLayer *view_layer = CTX_data_view_layer(C);
2581  uint objects_len = 0;
2583  view_layer, v3d, &objects_len);
2584  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2585  Object *obedit = objects[ob_index];
2586  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2587  BMFace *efa;
2588  BMLoop *l;
2589  BMIter iter, liter;
2590  MLoopUV *luv;
2591 
2592  if (em->bm->totfacesel == 0) {
2593  continue;
2594  }
2595 
2596  /* add uvs if they don't exist yet */
2597  if (!ED_uvedit_ensure_uvs(obedit)) {
2598  continue;
2599  }
2600 
2601  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2602  float center[3], rotmat[4][4];
2603 
2604  uv_map_transform(C, op, rotmat);
2605  uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
2606 
2607  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2608  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2609  continue;
2610  }
2611 
2612  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2613  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2614 
2615  uv_sphere_project(luv->uv, l->v->co, center, rotmat);
2616  }
2617 
2618  uv_map_mirror(em, efa);
2619  }
2620 
2621  uv_map_clip_correct(obedit, op);
2622 
2625  }
2626  MEM_freeN(objects);
2627 
2628  return OPERATOR_FINISHED;
2629 }
2630 
2632 {
2633  /* identifiers */
2634  ot->name = "Sphere Projection";
2635  ot->idname = "UV_OT_sphere_project";
2636  ot->description = "Project the UV vertices of the mesh over the curved surface of a sphere";
2637 
2639 
2640  /* api callbacks */
2643 
2644  /* properties */
2647 }
2648 
2651 /* -------------------------------------------------------------------- */
2655 static void uv_cylinder_project(float target[2],
2656  const float source[3],
2657  const float center[3],
2658  const float rotmat[4][4])
2659 {
2660  float pv[3];
2661 
2662  sub_v3_v3v3(pv, source, center);
2663  mul_m4_v3(rotmat, pv);
2664 
2665  map_to_tube(&target[0], &target[1], pv[0], pv[1], pv[2]);
2666 
2667  /* split line is always zero */
2668  if (target[0] >= 1.0f) {
2669  target[0] -= 1.0f;
2670  }
2671 }
2672 
2674 {
2675  const Scene *scene = CTX_data_scene(C);
2676  View3D *v3d = CTX_wm_view3d(C);
2677 
2678  ViewLayer *view_layer = CTX_data_view_layer(C);
2679  uint objects_len = 0;
2681  view_layer, v3d, &objects_len);
2682  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2683  Object *obedit = objects[ob_index];
2684  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2685  BMFace *efa;
2686  BMLoop *l;
2687  BMIter iter, liter;
2688  MLoopUV *luv;
2689 
2690  if (em->bm->totfacesel == 0) {
2691  continue;
2692  }
2693 
2694  /* add uvs if they don't exist yet */
2695  if (!ED_uvedit_ensure_uvs(obedit)) {
2696  continue;
2697  }
2698 
2699  const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
2700  float center[3], rotmat[4][4];
2701 
2702  uv_map_transform(C, op, rotmat);
2703  uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
2704 
2705  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
2706  if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2707  continue;
2708  }
2709 
2710  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2711  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2712 
2713  uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
2714  }
2715 
2716  uv_map_mirror(em, efa);
2717  }
2718 
2719  uv_map_clip_correct(obedit, op);
2720 
2723  }
2724  MEM_freeN(objects);
2725 
2726  return OPERATOR_FINISHED;
2727 }
2728 
2730 {
2731  /* identifiers */
2732  ot->name = "Cylinder Projection";
2733  ot->idname = "UV_OT_cylinder_project";
2734  ot->description = "Project the UV vertices of the mesh over the curved wall of a cylinder";
2735 
2737 
2738  /* api callbacks */
2741 
2742  /* properties */
2745 }
2746 
2747 /* -------------------------------------------------------------------- */
2752  float cube_size,
2753  bool use_select,
2754  const float center[3])
2755 {
2756  BMFace *efa;
2757  BMLoop *l;
2758  BMIter iter, liter;
2759  MLoopUV *luv;
2760  float loc[3];
2761  int cox, coy;
2762 
2763  int cd_loop_uv_offset;
2764 
2765  cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
2766 
2767  if (center) {
2768  copy_v3_v3(loc, center);
2769  }
2770  else {
2771  zero_v3(loc);
2772  }
2773 
2774  /* choose x,y,z axis for projection depending on the largest normal
2775  * component, but clusters all together around the center of map. */
2776 
2777  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2778  if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
2779  continue;
2780  }
2781 
2782  axis_dominant_v3(&cox, &coy, efa->no);
2783 
2784  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2785  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2786  luv->uv[0] = 0.5f + 0.5f * cube_size * (l->v->co[cox] - loc[cox]);
2787  luv->uv[1] = 0.5f + 0.5f * cube_size * (l->v->co[coy] - loc[coy]);
2788  }
2789  }
2790 }
2791 
2793 {
2794  const Scene *scene = CTX_data_scene(C);
2795  View3D *v3d = CTX_wm_view3d(C);
2796 
2797  PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size");
2798  const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size);
2799 
2800  ViewLayer *view_layer = CTX_data_view_layer(C);
2801  uint objects_len = 0;
2803  view_layer, v3d, &objects_len);
2804  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2805  Object *obedit = objects[ob_index];
2806  BMEditMesh *em = BKE_editmesh_from_object(obedit);
2807 
2808  if (em->bm->totfacesel == 0) {
2809  continue;
2810  }
2811 
2812  /* add uvs if they don't exist yet */
2813  if (!ED_uvedit_ensure_uvs(obedit)) {
2814  continue;
2815  }
2816 
2817  float bounds[2][3];
2818  float(*bounds_buf)[3] = NULL;
2819 
2820  if (!RNA_property_is_set(op->ptr, prop_cube_size)) {
2821  bounds_buf = bounds;
2822  }
2823 
2824  float center[3];
2825  uv_map_transform_center(scene, v3d, obedit, em, center, bounds_buf);
2826 
2827  /* calculate based on bounds */
2828  float cube_size = cube_size_init;
2829  if (bounds_buf) {
2830  float dims[3];
2831  sub_v3_v3v3(dims, bounds[1], bounds[0]);
2832  cube_size = max_fff(UNPACK3(dims));
2833  cube_size = cube_size ? 2.0f / cube_size : 1.0f;
2834  if (ob_index == 0) {
2835  /* This doesn't fit well with, multiple objects. */
2836  RNA_property_float_set(op->ptr, prop_cube_size, cube_size);
2837  }
2838  }
2839 
2840  uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
2841 
2842  uv_map_clip_correct(obedit, op);
2843 
2846  }
2847  MEM_freeN(objects);
2848 
2849  return OPERATOR_FINISHED;
2850 }
2851 
2853 {
2854  /* identifiers */
2855  ot->name = "Cube Projection";
2856  ot->idname = "UV_OT_cube_project";
2857  ot->description = "Project the UV vertices of the mesh over the six faces of a cube";
2858 
2860 
2861  /* api callbacks */
2864 
2865  /* properties */
2867  "cube_size",
2868  1.0f,
2869  0.0f,
2870  FLT_MAX,
2871  "Cube Size",
2872  "Size of the cube to project on",
2873  0.001f,
2874  100.0f);
2876 }
2877 
2880 /* -------------------------------------------------------------------- */
2885 {
2886  Mesh *me = ob->data;
2887  bool sync_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
2888 
2890  &((struct BMeshCreateParams){
2891  .use_toolflags = false,
2892  }));
2893 
2894  /* turn sync selection off,
2895  * since we are not in edit mode we need to ensure only the uv flags are tested */
2897 
2899 
2901  me,
2902  (&(struct BMeshFromMeshParams){
2903  .calc_face_normal = true,
2904  }));
2905  /* select all uv loops first - pack parameters needs this to make sure charts are registered */
2907  uvedit_unwrap_cube_project(bm, 1.0, false, NULL);
2908  /* set the margin really quickly before the packing operation*/
2909  scene->toolsettings->uvcalc_margin = 0.001f;
2911  BM_mesh_bm_to_me(bmain, bm, me, (&(struct BMeshToMeshParams){0}));
2912  BM_mesh_free(bm);
2913 
2914  if (sync_selection) {
2916  }
2917 }
2918 
typedef float(TangentPoint)[2]
struct DerivedMesh * CDDM_from_mesh(struct Mesh *mesh)
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
struct wmWindowManager * CTX_wm_manager(const bContext *C)
Definition: context.c:689
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:769
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
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:85
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:426
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, v3d, r_len)
Definition: BKE_layer.h:434
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_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
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:2343
@ SUBSURF_IN_EDIT_MODE
Definition: BKE_subsurf.h:55
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:104
#define BLI_array_append_ret(arr)
Definition: BLI_array.h:114
#define BLI_array_declare(arr)
Definition: BLI_array.h:62
#define BLI_array_len(arr)
Definition: BLI_array.h:74
#define BLI_array_clear(arr)
Definition: BLI_array.h:130
#define BLI_array_free(arr)
Definition: BLI_array.h:116
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define ATTR_FALLTHROUGH
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:38
void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z)
Definition: math_geom.c:5236
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3752
void map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z)
Definition: math_geom.c:5221
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:46
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
Definition: math_matrix.c:921
void unit_m4(float m[4][4])
Definition: rct.c:1140
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
#define mul_m4_series(...)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:95
bool is_negative_m4(const float mat[4][4])
Definition: math_matrix.c:2590
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
void mat4_to_size(float size[3], const float M[4][4])
Definition: math_matrix.c:2145
#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 minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
Definition: math_vector.c:1043
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void clamp_v2(float vec[2], const float min, const 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:270
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE void negate_v4_v4(float r[4], const float a[3])
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:109
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:36
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:185
struct MemArena * BLI_memarena_new(const size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:79
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:83
#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:94
void BLI_uvproject_from_view_ortho(float target[2], float source[3], const float rotmat[4][4])
Definition: uvproject.c:186
void BLI_uvproject_from_camera(float target[2], float source[3], struct ProjCameraInfo *uci)
Definition: uvproject.c:41
struct ProjCameraInfo * BLI_uvproject_camera_info(struct Object *ob, float rotmat[4][4], float winx, float winy)
#define TIP_(msgid)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
@ CD_ORIGINDEX
@ CD_MLOOPUV
@ MLOOPUV_PINNED
@ MLOOPUV_VERTSEL
@ 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:302
void EDBM_mesh_elem_index_ensure_multi(struct Object **objects, const uint objects_len, const char htype)
Definition: meshtools.c:1556
void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me)
Definition: mesh_data.c:246
void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name)
Definition: mesh_data.c:318
int ED_mesh_uv_texture_add(struct Mesh *me, const char *name, const bool active_set, const bool do_init)
Definition: mesh_data.c:257
void ED_area_status_text(ScrArea *area, const char *str)
Definition: area.c:815
bool ED_operator_uvmap(struct bContext *C)
Definition: screen_ops.c:525
bool ED_operator_uvedit(struct bContext *C)
Definition: screen_ops.c:511
void ED_workspace_status_text(struct bContext *C, const char *str)
Definition: area.c:840
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:125
void ED_uvedit_pack_islands_multi(const struct Scene *scene, Object **objects, const uint objects_len, const struct UVPackIsland_Params *params)
void ED_uvedit_select_all(struct BMesh *bm)
Definition: uvedit_ops.c:257
bool ED_uvedit_test(struct Object *obedit)
Definition: uvedit_ops.c:80
bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset)
struct Camera * ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d)
Definition: view3d_utils.c:109
NSNotificationCenter * center
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
Platform independent time functions.
#define C
Definition: RandGen.cpp:39
#define UI_MAX_DRAW_STR
Definition: UI_interface.h:90
#define NC_GEOM
Definition: WM_types.h:294
@ OPTYPE_BLOCKING
Definition: WM_types.h:157
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_GRAB_CURSOR_XY
Definition: WM_types.h:161
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define ND_DATA
Definition: WM_types.h:408
#define KM_PRESS
Definition: WM_types.h:242
@ 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:530
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_FACES_OF_MESH
@ 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.c:46
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
Definition: bmesh_mesh.c:307
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
BMesh Make Mesh.
Definition: bmesh_mesh.c:157
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2276
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:110
BLI_INLINE BMEdge * BM_edge_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:104
void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshParams *params)
Mesh -> BMesh.
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.
CCL_NAMESPACE_BEGIN struct Options options
Scene scene
#define str(s)
IconTextureDrawCall normal
#define sinf(x)
#define cosf(x)
#define fabsf(x)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static void area(int d1, int d2, int e1, int e2, float weights[2])
const int faceMap[6][4]
Definition: octree.cpp:2827
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2941
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:6655
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6319
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:866
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
Definition: rna_access.c:2358
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6355
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
Definition: rna_access.c:6366
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
Definition: rna_access.c:2964
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:6685
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
Definition: rna_access.c:6413
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3825
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
void RNA_def_property_float_default(PropertyRNA *prop, float value)
Definition: rna_define.c:2042
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:4133
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:3585
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:4005
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
#define min(a, b)
Definition: sort.c:51
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMesh * bm
Definition: BKE_editmesh.h:52
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:279
float no[3]
Definition: bmesh_class.h:280
struct BMVert * v
Definition: bmesh_class.h:165
float co[3]
Definition: bmesh_class.h:99
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:39
void * first
Definition: DNA_listBase.h:47
unsigned int v1
unsigned int v2
unsigned int v
float co[3]
Definition: BKE_main.h:116
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:36
float persmat[4][4]
float viewmat[4][4]
struct ToolSettings * toolsettings
struct RenderData r
View3DCursor cursor
char transform_pivot_point
char edge_mode_live_unwrap
bool topology_from_uvs_use_seams
struct Object * camera
short val
Definition: WM_types.h:579
short type
Definition: WM_types.h:577
void * customdata
Definition: WM_types.h:631
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
struct ReportList * reports
struct PointerRNA * ptr
double PIL_check_seconds_timer(void)
Definition: time.c:80
float max
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
void param_stretch_begin(ParamHandle *handle)
void param_stretch_iter(ParamHandle *handle)
void param_stretch_end(ParamHandle *handle)
void param_delete(ParamHandle *handle)
void param_flush_restore(ParamHandle *handle)
void param_aspect_ratio(ParamHandle *handle, float aspx, float aspy)
void param_flush(ParamHandle *handle)
ParamHandle * param_construct_begin(void)
void param_average(ParamHandle *handle, bool ignore_pinned)
void param_face_add(ParamHandle *handle, ParamKey key, int nverts, ParamKey *vkeys, float *co[4], float *uv[4], ParamBool *pin, ParamBool *select)
void param_lscm_begin(ParamHandle *handle, ParamBool live, ParamBool abf)
void param_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
void param_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
void param_construct_end(ParamHandle *handle, ParamBool fill, ParamBool topology_from_uvs, int *count_fail)
void param_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed)
void param_lscm_end(ParamHandle *handle)
void param_stretch_blend(ParamHandle *handle, float blend)
@ PARAM_TRUE
@ PARAM_FALSE
void ParamHandle
intptr_t ParamKey
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)
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)
uint len
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 struct @603 g_live_unwrap
#define POLAR_ZX
struct UnwrapResultInfo UnwrapResultInfo
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)
void UV_OT_cylinder_project(wmOperatorType *ot)
void UV_OT_project_from_view(wmOperatorType *ot)
void UV_OT_smart_project(wmOperatorType *ot)
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)
static void construct_param_handle_face_add(ParamHandle *handle, const Scene *scene, BMFace *efa, int face_index, const int cd_loop_uv_offset)
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
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])
static ParamHandle * construct_param_handle_multi(const Scene *scene, Object **objects, const uint objects_len, const UnwrapOptions *options, int *count_fail)
#define VIEW_ON_POLES
static int sphere_project_exec(bContext *C, wmOperator *op)
struct MinStretch MinStretch
static void texface_from_original_index(const Scene *scene, const int cd_loop_uv_offset, BMFace *efa, int index, float **r_uv, ParamBool *r_pin, ParamBool *r_select)
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 void uv_map_clip_correct_multi(Object **objects, uint objects_len, wmOperator *op)
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])
static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
@ UNWRAP_ERROR_NEGATIVE
@ UNWRAP_ERROR_NONUNIFORM
void UV_OT_reset(wmOperatorType *ot)
void UV_OT_minimize_stretch(wmOperatorType *ot)
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)
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:3156
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:1669
wmTimer * WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
Definition: wm_window.c:1632