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