Fix shadows of sun type lights on some Intel gpus
[blender.git] / source / blender / editors / uvedit / uvedit_unwrap_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/uvedit/uvedit_unwrap_ops.c
29  *  \ingroup eduv
30  */
31
32
33 #include <string.h>
34 #include <stdlib.h>
35 #include <math.h>
36
37 #include "MEM_guardedalloc.h"
38
39 #include "DNA_camera_types.h"
40 #include "DNA_mesh_types.h"
41 #include "DNA_meshdata_types.h"
42 #include "DNA_object_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_modifier_types.h"
45
46 #include "BLI_utildefines.h"
47 #include "BLI_alloca.h"
48 #include "BLI_math.h"
49 #include "BLI_uvproject.h"
50 #include "BLI_string.h"
51
52 #include "BLT_translation.h"
53
54 #include "BKE_cdderivedmesh.h"
55 #include "BKE_subsurf.h"
56 #include "BKE_context.h"
57 #include "BKE_customdata.h"
58 #include "BKE_image.h"
59 #include "BKE_main.h"
60 #include "BKE_material.h"
61 #include "BKE_report.h"
62 #include "BKE_scene.h"
63 #include "BKE_editmesh.h"
64 #include "BKE_layer.h"
65
66 #include "DEG_depsgraph.h"
67
68 #include "PIL_time.h"
69
70 #include "UI_interface.h"
71
72 #include "ED_image.h"
73 #include "ED_mesh.h"
74 #include "ED_screen.h"
75 #include "ED_uvedit.h"
76 #include "ED_view3d.h"
77
78 #include "RNA_access.h"
79 #include "RNA_define.h"
80
81
82 #include "WM_api.h"
83 #include "WM_types.h"
84
85 #include "uvedit_intern.h"
86 #include "uvedit_parametrizer.h"
87
88 static void modifier_unwrap_state(Object *obedit, Scene *scene, bool *r_use_subsurf)
89 {
90         ModifierData *md;
91         bool subsurf = (scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF) != 0;
92
93         md = obedit->modifiers.first;
94
95         /* subsurf will take the modifier settings only if modifier is first or right after mirror */
96         if (subsurf) {
97                 if (md && md->type == eModifierType_Subsurf)
98                         subsurf = true;
99                 else
100                         subsurf = false;
101         }
102
103         *r_use_subsurf = subsurf;
104 }
105
106 static bool ED_uvedit_ensure_uvs(bContext *C, Scene *UNUSED(scene), Object *obedit)
107 {
108         BMEditMesh *em = BKE_editmesh_from_object(obedit);
109         BMFace *efa;
110         BMIter iter;
111         Image *ima;
112         bScreen *sc;
113         ScrArea *sa;
114         SpaceLink *slink;
115         SpaceImage *sima;
116         int cd_loop_uv_offset;
117
118         if (ED_uvedit_test(obedit))
119                 return 1;
120
121         if (em && em->bm->totface && !CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV))
122                 ED_mesh_uv_texture_add(obedit->data, NULL, true);
123
124         if (!ED_uvedit_test(obedit))
125                 return 0;
126
127         cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
128
129         ima = CTX_data_edit_image(C);
130
131         if (!ima) {
132                 /* no image in context in the 3d view, we find first image window .. */
133                 sc = CTX_wm_screen(C);
134
135                 for (sa = sc->areabase.first; sa; sa = sa->next) {
136                         slink = sa->spacedata.first;
137                         if (slink->spacetype == SPACE_IMAGE) {
138                                 sima = (SpaceImage *)slink;
139
140                                 ima = sima->image;
141                                 if (ima) {
142                                         if (ima->type == IMA_TYPE_R_RESULT || ima->type == IMA_TYPE_COMPOSITE)
143                                                 ima = NULL;
144                                         else
145                                                 break;
146                                 }
147                         }
148                 }
149         }
150
151         /* select new UV's (ignore UV_SYNC_SELECTION in this case) */
152         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
153                 BMIter liter;
154                 BMLoop *l;
155
156                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
157                         MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
158                         luv->flag |= MLOOPUV_VERTSEL;
159                 }
160         }
161
162         return 1;
163 }
164
165 /****************** Parametrizer Conversion ***************/
166
167 static bool uvedit_have_selection(Scene *scene, BMEditMesh *em, bool implicit)
168 {
169         BMFace *efa;
170         BMLoop *l;
171         BMIter iter, liter;
172         const int cd_loop_uv_offset  = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
173
174         if (cd_loop_uv_offset == -1) {
175                 return (em->bm->totfacesel != 0);
176         }
177
178         /* verify if we have any selected uv's before unwrapping,
179          * so we can cancel the operator early */
180         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
181                 if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
182                         if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN))
183                                 continue;
184                 }
185                 else if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
186                         continue;
187
188                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
189                         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))
190                                 break;
191                 }
192
193                 if (implicit && !l)
194                         continue;
195
196                 return true;
197         }
198
199         return false;
200 }
201
202 static bool uvedit_have_selection_multi(
203         Scene *scene, Object **objects, const uint objects_len, bool implicit)
204 {
205         bool have_select = false;
206         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
207                 Object *obedit = objects[ob_index];
208                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
209                 if (uvedit_have_selection(scene, em, implicit)) {
210                         have_select = true;
211                         break;
212                 }
213         }
214         return have_select;
215 }
216
217 void ED_uvedit_get_aspect(Scene *UNUSED(scene), Object *ob, BMesh *bm, float *aspx, float *aspy)
218 {
219         bool sloppy = true;
220         bool selected = false;
221         BMFace *efa;
222         Image *ima;
223
224         efa = BM_mesh_active_face_get(bm, sloppy, selected);
225
226         if (efa) {
227                 ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
228
229                 ED_image_get_uv_aspect(ima, NULL, aspx, aspy);
230         }
231         else {
232                 *aspx = 1.0f;
233                 *aspy = 1.0f;
234         }
235 }
236
237 static void construct_param_handle_face_add(ParamHandle *handle, Scene *scene,
238                                             BMFace *efa, int face_index, const int cd_loop_uv_offset)
239 {
240         ParamKey key;
241         ParamKey *vkeys = BLI_array_alloca(vkeys, efa->len);
242         ParamBool *pin = BLI_array_alloca(pin, efa->len);
243         ParamBool *select = BLI_array_alloca(select, efa->len);
244         float **co = BLI_array_alloca(co, efa->len);
245         float **uv = BLI_array_alloca(uv, efa->len);
246         int i;
247
248         BMIter liter;
249         BMLoop *l;
250
251         key = (ParamKey)face_index;
252
253         /* let parametrizer split the ngon, it can make better decisions
254          * about which split is best for unwrapping than scanfill */
255         BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
256                 MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
257
258                 vkeys[i] = (ParamKey)BM_elem_index_get(l->v);
259                 co[i] = l->v->co;
260                 uv[i] = luv->uv;
261                 pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
262                 select[i] = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
263         }
264
265         param_face_add(handle, key, i, vkeys, co, uv, pin, select, efa->no);
266 }
267
268 /* See: construct_param_handle_multi to handle multiple objects at once. */
269 static ParamHandle *construct_param_handle(
270         Scene *scene, Object *ob, BMesh *bm,
271         const bool implicit, const bool fill, const bool sel,
272         const bool correct_aspect)
273 {
274         ParamHandle *handle;
275         BMFace *efa;
276         BMLoop *l;
277         BMEdge *eed;
278         BMIter iter, liter;
279         int i;
280
281         const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
282
283         handle = param_construct_begin();
284
285         if (correct_aspect) {
286                 float aspx, aspy;
287
288                 ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
289
290                 if (aspx != aspy)
291                         param_aspect_ratio(handle, aspx, aspy);
292         }
293
294         /* we need the vert indices */
295         BM_mesh_elem_index_ensure(bm, BM_VERT);
296
297         BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
298
299                 if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
300                         continue;
301                 }
302
303                 if (implicit) {
304                         bool is_loopsel = false;
305
306                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
307                                 if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
308                                         is_loopsel = true;
309                                         break;
310                                 }
311                         }
312                         if (is_loopsel == false) {
313                                 continue;
314                         }
315                 }
316
317                 construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
318         }
319
320         if (!implicit) {
321                 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
322                         if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
323                                 ParamKey vkeys[2];
324                                 vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
325                                 vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
326                                 param_edge_set_seam(handle, vkeys);
327                         }
328                 }
329         }
330
331         param_construct_end(handle, fill, implicit);
332
333         return handle;
334 }
335
336 /**
337  * Version of #construct_param_handle_single that handles multiple objects.
338  */
339 static ParamHandle *construct_param_handle_multi(
340         Scene *scene, Object **objects, const uint objects_len,
341         const bool implicit, const bool fill, const bool sel,
342         const bool correct_aspect)
343 {
344         ParamHandle *handle;
345         BMFace *efa;
346         BMLoop *l;
347         BMEdge *eed;
348         BMIter iter, liter;
349         int i;
350
351
352         handle = param_construct_begin();
353
354         if (correct_aspect) {
355                 Object *ob = objects[0];
356                 BMEditMesh *em = BKE_editmesh_from_object(ob);
357                 BMesh *bm = em->bm;
358                 float aspx, aspy;
359
360                 ED_uvedit_get_aspect(scene, ob, bm, &aspx, &aspy);
361                 if (aspx != aspy) {
362                         param_aspect_ratio(handle, aspx, aspy);
363                 }
364         }
365
366         /* we need the vert indices */
367         EDBM_mesh_elem_index_ensure_multi(objects, objects_len, BM_VERT);
368
369         int offset = 0;
370
371         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
372                 Object *obedit = objects[ob_index];
373                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
374                 BMesh *bm = em->bm;
375
376                 const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
377
378                 BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
379
380                         if ((BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || (sel && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
381                                 continue;
382                         }
383
384                         if (implicit) {
385                                 bool is_loopsel = false;
386
387                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
388                                         if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
389                                                 is_loopsel = true;
390                                                 break;
391                                         }
392                                 }
393                                 if (is_loopsel == false) {
394                                         continue;
395                                 }
396                         }
397
398                         construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
399                 }
400
401                 if (!implicit) {
402                         BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
403                                 if (BM_elem_flag_test(eed, BM_ELEM_SEAM)) {
404                                         ParamKey vkeys[2];
405                                         vkeys[0] = (ParamKey)BM_elem_index_get(eed->v1);
406                                         vkeys[1] = (ParamKey)BM_elem_index_get(eed->v2);
407                                         param_edge_set_seam(handle, vkeys);
408                                 }
409                         }
410                 }
411                 offset += bm->totface;
412         }
413
414         param_construct_end(handle, fill, implicit);
415
416         return handle;
417 }
418
419
420 static void texface_from_original_index(BMFace *efa, int index, float **uv, ParamBool *pin, ParamBool *select,
421                                         Scene *scene, const int cd_loop_uv_offset)
422 {
423         BMLoop *l;
424         BMIter liter;
425         MLoopUV *luv;
426
427         *uv = NULL;
428         *pin = 0;
429         *select = 1;
430
431         if (index == ORIGINDEX_NONE)
432                 return;
433
434         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
435                 if (BM_elem_index_get(l->v) == index) {
436                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
437                         *uv = luv->uv;
438                         *pin = (luv->flag & MLOOPUV_PINNED) ? 1 : 0;
439                         *select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
440                         break;
441                 }
442         }
443 }
444
445 /* unwrap handle initialization for subsurf aware-unwrapper. The many modifications required to make the original function(see above)
446  * work justified the existence of a new function. */
447 static ParamHandle *construct_param_handle_subsurfed(Scene *scene, Object *ob, BMEditMesh *em, short fill, short sel, short correct_aspect)
448 {
449         ParamHandle *handle;
450         /* index pointers */
451         MPoly *mpoly;
452         MLoop *mloop;
453         MEdge *edge;
454         int i;
455
456         /* pointers to modifier data for unwrap control */
457         ModifierData *md;
458         SubsurfModifierData *smd_real;
459         /* modifier initialization data, will  control what type of subdivision will happen*/
460         SubsurfModifierData smd = {{NULL}};
461         /* Used to hold subsurfed Mesh */
462         DerivedMesh *derivedMesh, *initialDerived;
463         /* holds original indices for subsurfed mesh */
464         const int *origVertIndices, *origEdgeIndices, *origPolyIndices;
465         /* Holds vertices of subsurfed mesh */
466         MVert *subsurfedVerts;
467         MEdge *subsurfedEdges;
468         MPoly *subsurfedPolys;
469         MLoop *subsurfedLoops;
470         /* number of vertices and faces for subsurfed mesh*/
471         int numOfEdges, numOfFaces;
472
473         /* holds a map to editfaces for every subsurfed MFace. These will be used to get hidden/ selected flags etc. */
474         BMFace **faceMap;
475         /* similar to the above, we need a way to map edges to their original ones */
476         BMEdge **edgeMap;
477
478         const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
479
480         handle = param_construct_begin();
481
482         if (correct_aspect) {
483                 float aspx, aspy;
484
485                 ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
486
487                 if (aspx != aspy)
488                         param_aspect_ratio(handle, aspx, aspy);
489         }
490
491         /* number of subdivisions to perform */
492         md = ob->modifiers.first;
493         smd_real = (SubsurfModifierData *)md;
494
495         smd.levels = smd_real->levels;
496         smd.subdivType = smd_real->subdivType;
497
498         initialDerived = CDDM_from_editbmesh(em, false, false);
499         derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd, scene,
500                                                         NULL, SUBSURF_IN_EDIT_MODE);
501
502         initialDerived->release(initialDerived);
503
504         /* get the derived data */
505         subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
506         subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
507         subsurfedPolys = derivedMesh->getPolyArray(derivedMesh);
508         subsurfedLoops = derivedMesh->getLoopArray(derivedMesh);
509
510         origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
511         origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
512         origPolyIndices = derivedMesh->getPolyDataArray(derivedMesh, CD_ORIGINDEX);
513
514         numOfEdges = derivedMesh->getNumEdges(derivedMesh);
515         numOfFaces = derivedMesh->getNumPolys(derivedMesh);
516
517         faceMap = MEM_mallocN(numOfFaces * sizeof(BMFace *), "unwrap_edit_face_map");
518
519         BM_mesh_elem_index_ensure(em->bm, BM_VERT);
520         BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_FACE);
521
522         /* map subsurfed faces to original editFaces */
523         for (i = 0; i < numOfFaces; i++)
524                 faceMap[i] = BM_face_at_index(em->bm, origPolyIndices[i]);
525
526         edgeMap = MEM_mallocN(numOfEdges * sizeof(BMEdge *), "unwrap_edit_edge_map");
527
528         /* map subsurfed edges to original editEdges */
529         for (i = 0; i < numOfEdges; i++) {
530                 /* not all edges correspond to an old edge */
531                 edgeMap[i] = (origEdgeIndices[i] != ORIGINDEX_NONE) ?
532                              BM_edge_at_index(em->bm, origEdgeIndices[i]) : NULL;
533         }
534
535         /* Prepare and feed faces to the solver */
536         for (i = 0, mpoly = subsurfedPolys; i < numOfFaces; i++, mpoly++) {
537                 ParamKey key, vkeys[4];
538                 ParamBool pin[4], select[4];
539                 float *co[4];
540                 float *uv[4];
541                 BMFace *origFace = faceMap[i];
542
543                 if (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
544                         if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN))
545                                 continue;
546                 }
547                 else {
548                         if (BM_elem_flag_test(origFace, BM_ELEM_HIDDEN) || (sel && !BM_elem_flag_test(origFace, BM_ELEM_SELECT)))
549                                 continue;
550                 }
551
552                 mloop = &subsurfedLoops[mpoly->loopstart];
553
554                 /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
555                 BLI_assert(mpoly->totloop == 4);
556                 key = (ParamKey)i;
557                 vkeys[0] = (ParamKey)mloop[0].v;
558                 vkeys[1] = (ParamKey)mloop[1].v;
559                 vkeys[2] = (ParamKey)mloop[2].v;
560                 vkeys[3] = (ParamKey)mloop[3].v;
561
562                 co[0] = subsurfedVerts[mloop[0].v].co;
563                 co[1] = subsurfedVerts[mloop[1].v].co;
564                 co[2] = subsurfedVerts[mloop[2].v].co;
565                 co[3] = subsurfedVerts[mloop[3].v].co;
566
567                 /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus
568                  * flushing the solution to the edit mesh. */
569                 texface_from_original_index(origFace, origVertIndices[mloop[0].v], &uv[0], &pin[0], &select[0], scene, cd_loop_uv_offset);
570                 texface_from_original_index(origFace, origVertIndices[mloop[1].v], &uv[1], &pin[1], &select[1], scene, cd_loop_uv_offset);
571                 texface_from_original_index(origFace, origVertIndices[mloop[2].v], &uv[2], &pin[2], &select[2], scene, cd_loop_uv_offset);
572                 texface_from_original_index(origFace, origVertIndices[mloop[3].v], &uv[3], &pin[3], &select[3], scene, cd_loop_uv_offset);
573
574                 param_face_add(handle, key, 4, vkeys, co, uv, pin, select, NULL);
575         }
576
577         /* these are calculated from original mesh too */
578         for (edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) {
579                 if ((edgeMap[i] != NULL) && BM_elem_flag_test(edgeMap[i], BM_ELEM_SEAM)) {
580                         ParamKey vkeys[2];
581                         vkeys[0] = (ParamKey)edge->v1;
582                         vkeys[1] = (ParamKey)edge->v2;
583                         param_edge_set_seam(handle, vkeys);
584                 }
585         }
586
587         param_construct_end(handle, fill, 0);
588
589         /* cleanup */
590         MEM_freeN(faceMap);
591         MEM_freeN(edgeMap);
592         derivedMesh->release(derivedMesh);
593
594         return handle;
595 }
596
597 /* ******************** Minimize Stretch operator **************** */
598
599 typedef struct MinStretch {
600         Scene *scene;
601         Object **objects_edit;
602         uint objects_len;
603         ParamHandle *handle;
604         float blend;
605         double lasttime;
606         int i, iterations;
607         wmTimer *timer;
608 } MinStretch;
609
610 static bool minimize_stretch_init(bContext *C, wmOperator *op)
611 {
612         Scene *scene = CTX_data_scene(C);
613         ViewLayer *view_layer = CTX_data_view_layer(C);
614
615         MinStretch *ms;
616         const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
617         bool implicit = true;
618
619         uint objects_len = 0;
620         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
621
622         if (!uvedit_have_selection_multi(scene, objects, objects_len, implicit)) {
623                 MEM_freeN(objects);
624                 return false;
625         }
626
627         ms = MEM_callocN(sizeof(MinStretch), "MinStretch");
628         ms->scene = scene;
629         ms->objects_edit = objects;
630         ms->objects_len = objects_len;
631         ms->blend = RNA_float_get(op->ptr, "blend");
632         ms->iterations = RNA_int_get(op->ptr, "iterations");
633         ms->i = 0;
634         ms->handle = construct_param_handle_multi(scene, objects, objects_len, implicit, fill_holes, true, true);
635         ms->lasttime = PIL_check_seconds_timer();
636
637         param_stretch_begin(ms->handle);
638         if (ms->blend != 0.0f)
639                 param_stretch_blend(ms->handle, ms->blend);
640
641         op->customdata = ms;
642
643         return true;
644 }
645
646 static void minimize_stretch_iteration(bContext *C, wmOperator *op, bool interactive)
647 {
648         MinStretch *ms = op->customdata;
649         ScrArea *sa = CTX_wm_area(C);
650         Scene *scene = CTX_data_scene(C);
651         ToolSettings *ts = scene->toolsettings;
652         const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
653
654         param_stretch_blend(ms->handle, ms->blend);
655         param_stretch_iter(ms->handle);
656
657         ms->i++;
658         RNA_int_set(op->ptr, "iterations", ms->i);
659
660         if (interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
661                 char str[UI_MAX_DRAW_STR];
662
663                 param_flush(ms->handle);
664
665                 if (sa) {
666                         BLI_snprintf(str, sizeof(str), IFACE_("Minimize Stretch. Blend %.2f"), ms->blend);
667                         ED_area_status_text(sa, str);
668                         ED_workspace_status_text(C, IFACE_("Press + and -, or scroll wheel to set blending"));
669                 }
670
671                 ms->lasttime = PIL_check_seconds_timer();
672
673                 for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
674                         Object *obedit = ms->objects_edit[ob_index];
675                         BMEditMesh *em = BKE_editmesh_from_object(obedit);
676
677                         if (synced_selection && (em->bm->totfacesel == 0)) {
678                                 continue;
679                         }
680
681                         DEG_id_tag_update(obedit->data, 0);
682                         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
683                 }
684         }
685 }
686
687 static void minimize_stretch_exit(bContext *C, wmOperator *op, bool cancel)
688 {
689         MinStretch *ms = op->customdata;
690         ScrArea *sa = CTX_wm_area(C);
691         Scene *scene = CTX_data_scene(C);
692         ToolSettings *ts = scene->toolsettings;
693         const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
694
695         ED_area_status_text(sa, NULL);
696         ED_workspace_status_text(C, NULL);
697
698         if (ms->timer)
699                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer);
700
701         if (cancel)
702                 param_flush_restore(ms->handle);
703         else
704                 param_flush(ms->handle);
705
706         param_stretch_end(ms->handle);
707         param_delete(ms->handle);
708
709         for (uint ob_index = 0; ob_index < ms->objects_len; ob_index++) {
710                 Object *obedit = ms->objects_edit[ob_index];
711                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
712
713                 if (synced_selection && (em->bm->totfacesel == 0)) {
714                         continue;
715                 }
716
717                 DEG_id_tag_update(obedit->data, 0);
718                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
719         }
720
721         MEM_freeN(ms->objects_edit);
722         MEM_freeN(ms);
723         op->customdata = NULL;
724 }
725
726 static int minimize_stretch_exec(bContext *C, wmOperator *op)
727 {
728         int i, iterations;
729
730         if (!minimize_stretch_init(C, op))
731                 return OPERATOR_CANCELLED;
732
733         iterations = RNA_int_get(op->ptr, "iterations");
734         for (i = 0; i < iterations; i++)
735                 minimize_stretch_iteration(C, op, false);
736         minimize_stretch_exit(C, op, false);
737
738         return OPERATOR_FINISHED;
739 }
740
741 static int minimize_stretch_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
742 {
743         MinStretch *ms;
744
745         if (!minimize_stretch_init(C, op))
746                 return OPERATOR_CANCELLED;
747
748         minimize_stretch_iteration(C, op, true);
749
750         ms = op->customdata;
751         WM_event_add_modal_handler(C, op);
752         ms->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
753
754         return OPERATOR_RUNNING_MODAL;
755 }
756
757 static int minimize_stretch_modal(bContext *C, wmOperator *op, const wmEvent *event)
758 {
759         MinStretch *ms = op->customdata;
760
761         switch (event->type) {
762                 case ESCKEY:
763                 case RIGHTMOUSE:
764                         minimize_stretch_exit(C, op, true);
765                         return OPERATOR_CANCELLED;
766                 case RETKEY:
767                 case PADENTER:
768                 case LEFTMOUSE:
769                         minimize_stretch_exit(C, op, false);
770                         return OPERATOR_FINISHED;
771                 case PADPLUSKEY:
772                 case WHEELUPMOUSE:
773                         if (event->val == KM_PRESS) {
774                                 if (ms->blend < 0.95f) {
775                                         ms->blend += 0.1f;
776                                         ms->lasttime = 0.0f;
777                                         RNA_float_set(op->ptr, "blend", ms->blend);
778                                         minimize_stretch_iteration(C, op, true);
779                                 }
780                         }
781                         break;
782                 case PADMINUS:
783                 case WHEELDOWNMOUSE:
784                         if (event->val == KM_PRESS) {
785                                 if (ms->blend > 0.05f) {
786                                         ms->blend -= 0.1f;
787                                         ms->lasttime = 0.0f;
788                                         RNA_float_set(op->ptr, "blend", ms->blend);
789                                         minimize_stretch_iteration(C, op, true);
790                                 }
791                         }
792                         break;
793                 case TIMER:
794                         if (ms->timer == event->customdata) {
795                                 double start = PIL_check_seconds_timer();
796
797                                 do {
798                                         minimize_stretch_iteration(C, op, true);
799                                 } while (PIL_check_seconds_timer() - start < 0.01);
800                         }
801                         break;
802         }
803
804         if (ms->iterations && ms->i >= ms->iterations) {
805                 minimize_stretch_exit(C, op, false);
806                 return OPERATOR_FINISHED;
807         }
808
809         return OPERATOR_RUNNING_MODAL;
810 }
811
812 static void minimize_stretch_cancel(bContext *C, wmOperator *op)
813 {
814         minimize_stretch_exit(C, op, true);
815 }
816
817 void UV_OT_minimize_stretch(wmOperatorType *ot)
818 {
819         /* identifiers */
820         ot->name = "Minimize Stretch";
821         ot->idname = "UV_OT_minimize_stretch";
822         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING;
823         ot->description = "Reduce UV stretching by relaxing angles";
824
825         /* api callbacks */
826         ot->exec = minimize_stretch_exec;
827         ot->invoke = minimize_stretch_invoke;
828         ot->modal = minimize_stretch_modal;
829         ot->cancel = minimize_stretch_cancel;
830         ot->poll = ED_operator_uvedit;
831
832         /* properties */
833         RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry");
834         RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original", 0.0f, 1.0f);
835         RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively", 0, 100);
836 }
837
838 /* ******************** Pack Islands operator **************** */
839
840
841 void ED_uvedit_pack_islands(Scene *scene, Object *ob, BMesh *bm, bool selected, bool correct_aspect, bool do_rotate)
842 {
843         ParamHandle *handle;
844         handle = construct_param_handle(scene, ob, bm, true, false, selected, correct_aspect);
845         param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate);
846         param_flush(handle);
847         param_delete(handle);
848 }
849
850 void ED_uvedit_pack_islands_multi(
851         Scene *scene, Object **objects, const uint objects_len,
852         bool selected, bool correct_aspect, bool do_rotate)
853 {
854         ParamHandle *handle;
855         handle = construct_param_handle_multi(
856                 scene, objects, objects_len, true, false, selected, correct_aspect);
857         param_pack(handle, scene->toolsettings->uvcalc_margin, do_rotate);
858         param_flush(handle);
859         param_delete(handle);
860 }
861
862 static int pack_islands_exec(bContext *C, wmOperator *op)
863 {
864         ViewLayer *view_layer = CTX_data_view_layer(C);
865         Scene *scene = CTX_data_scene(C);
866         bool do_rotate = RNA_boolean_get(op->ptr, "rotate");
867
868         uint objects_len = 0;
869         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
870
871         if (!uvedit_have_selection_multi(scene, objects, objects_len, true)) {
872                 MEM_freeN(objects);
873                 return OPERATOR_CANCELLED;
874         }
875
876         if (RNA_struct_property_is_set(op->ptr, "margin"))
877                 scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
878         else
879                 RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
880
881         ED_uvedit_pack_islands_multi(scene, objects, objects_len, true, true, do_rotate);
882
883         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
884                 Object *obedit = objects[ob_index];
885                 DEG_id_tag_update(obedit->data, 0);
886                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
887         }
888
889         MEM_freeN(objects);
890
891         return OPERATOR_FINISHED;
892 }
893
894 void UV_OT_pack_islands(wmOperatorType *ot)
895 {
896         /* identifiers */
897         ot->name = "Pack Islands";
898         ot->idname = "UV_OT_pack_islands";
899         ot->description = "Transform all islands so that they fill up the UV space as much as possible";
900
901         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
902
903         /* api callbacks */
904         ot->exec = pack_islands_exec;
905         ot->poll = ED_operator_uvedit;
906
907         /* properties */
908         RNA_def_boolean(ot->srna, "rotate", true, "Rotate", "Rotate islands for best fit");
909         RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
910 }
911
912 /* ******************** Average Islands Scale operator **************** */
913
914 static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
915 {
916         Scene *scene = CTX_data_scene(C);
917         ViewLayer *view_layer = CTX_data_view_layer(C);
918         ToolSettings *ts = scene->toolsettings;
919         const bool synced_selection = (ts->uv_flag & UV_SYNC_SELECTION) != 0;
920         const bool implicit = true;
921         ParamHandle *handle;
922
923         uint objects_len = 0;
924         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(view_layer, &objects_len);
925
926         if (!uvedit_have_selection_multi(scene, objects, objects_len, implicit)) {
927                 MEM_freeN(objects);
928                 return OPERATOR_CANCELLED;
929         }
930
931         handle = construct_param_handle_multi(scene, objects, objects_len, implicit, false, true, true);
932         param_average(handle);
933         param_flush(handle);
934         param_delete(handle);
935
936         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
937                 Object *obedit = objects[ob_index];
938                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
939
940                 if (synced_selection && (em->bm->totvertsel == 0)) {
941                         continue;
942                 }
943
944                 DEG_id_tag_update(obedit->data, 0);
945                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
946         }
947         MEM_freeN(objects);
948         return OPERATOR_FINISHED;
949 }
950
951 void UV_OT_average_islands_scale(wmOperatorType *ot)
952 {
953         /* identifiers */
954         ot->name = "Average Islands Scale";
955         ot->idname = "UV_OT_average_islands_scale";
956         ot->description = "Average the size of separate UV islands, based on their area in 3D space";
957
958         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
959
960         /* api callbacks */
961         ot->exec = average_islands_scale_exec;
962         ot->poll = ED_operator_uvedit;
963 }
964
965 /**************** Live Unwrap *****************/
966
967 static struct {
968         ParamHandle **handles;
969         uint len, len_alloc;
970 } g_live_unwrap = {NULL};
971
972 void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
973 {
974         ParamHandle *handle = NULL;
975         BMEditMesh *em = BKE_editmesh_from_object(obedit);
976         const bool abf = (scene->toolsettings->unwrapper == 0);
977         const bool fillholes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0;
978         bool use_subsurf;
979
980         modifier_unwrap_state(obedit, scene, &use_subsurf);
981
982         if (!ED_uvedit_test(obedit)) {
983                 return;
984         }
985
986         if (use_subsurf)
987                 handle = construct_param_handle_subsurfed(scene, obedit, em, fillholes, false, true);
988         else
989                 handle = construct_param_handle(scene, obedit, em->bm, false, fillholes, false, true);
990
991         param_lscm_begin(handle, PARAM_TRUE, abf);
992
993         /* Create or increase size of g_live_unwrap.handles array */
994         if (g_live_unwrap.handles == NULL) {
995                 g_live_unwrap.len_alloc = 32;
996                 g_live_unwrap.handles = MEM_mallocN(sizeof(ParamHandle *) * g_live_unwrap.len_alloc, "uvedit_live_unwrap_liveHandles");
997                 g_live_unwrap.len = 0;
998         }
999         if (g_live_unwrap.len >= g_live_unwrap.len_alloc) {
1000                 g_live_unwrap.len_alloc *= 2;
1001                 g_live_unwrap.handles = MEM_reallocN(g_live_unwrap.handles, sizeof(ParamHandle *) * g_live_unwrap.len_alloc);
1002         }
1003         g_live_unwrap.handles[g_live_unwrap.len] = handle;
1004         g_live_unwrap.len++;
1005 }
1006
1007 void ED_uvedit_live_unwrap_re_solve(void)
1008 {
1009         if (g_live_unwrap.handles) {
1010                 for (int i = 0; i < g_live_unwrap.len; i++) {
1011                         param_lscm_solve(g_live_unwrap.handles[i]);
1012                         param_flush(g_live_unwrap.handles[i]);
1013                 }
1014         }
1015 }
1016
1017 void ED_uvedit_live_unwrap_end(short cancel)
1018 {
1019         if (g_live_unwrap.handles) {
1020                 for (int i = 0; i < g_live_unwrap.len; i++) {
1021                         param_lscm_end(g_live_unwrap.handles[i]);
1022                         if (cancel)
1023                                 param_flush_restore(g_live_unwrap.handles[i]);
1024                         param_delete(g_live_unwrap.handles[i]);
1025                 }
1026                 MEM_freeN(g_live_unwrap.handles);
1027                 g_live_unwrap.handles = NULL;
1028                 g_live_unwrap.len = 0;
1029                 g_live_unwrap.len_alloc = 0;
1030         }
1031 }
1032
1033 void ED_uvedit_live_unwrap(Scene *scene, Object *obedit)
1034 {
1035         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1036
1037         if (scene->toolsettings->edge_mode_live_unwrap &&
1038             CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV))
1039         {
1040                 ED_unwrap_lscm(scene, obedit, false, false); /* unwrap all not just sel */
1041         }
1042 }
1043
1044 /*************** UV Map Common Transforms *****************/
1045
1046 #define VIEW_ON_EQUATOR 0
1047 #define VIEW_ON_POLES   1
1048 #define ALIGN_TO_OBJECT 2
1049
1050 #define POLAR_ZX    0
1051 #define POLAR_ZY    1
1052
1053 static void uv_map_transform_calc_bounds(BMEditMesh *em, float r_min[3], float r_max[3])
1054 {
1055         BMFace *efa;
1056         BMIter iter;
1057         INIT_MINMAX(r_min, r_max);
1058         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1059                 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1060                         BM_face_calc_bounds_expand(efa, r_min, r_max);
1061                 }
1062         }
1063 }
1064
1065 static void uv_map_transform_calc_center_median(BMEditMesh *em, float r_center[3])
1066 {
1067         BMFace *efa;
1068         BMIter iter;
1069         uint center_accum_num = 0;
1070         zero_v3(r_center);
1071         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1072                 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
1073                         float center[3];
1074                         BM_face_calc_center_mean(efa, center);
1075                         add_v3_v3(r_center, center);
1076                         center_accum_num += 1;
1077                 }
1078         }
1079         mul_v3_fl(r_center, 1.0f / (float)center_accum_num);
1080 }
1081
1082 static void uv_map_transform_center(
1083         Scene *scene, View3D *v3d, Object *ob, BMEditMesh *em,
1084         float r_center[3],
1085         float r_bounds[2][3])
1086 {
1087         /* only operates on the edit object - this is all that's needed now */
1088         const int around = (v3d) ? scene->toolsettings->transform_pivot_point : V3D_AROUND_CENTER_BOUNDS;
1089
1090         float bounds[2][3];
1091         INIT_MINMAX(bounds[0], bounds[1]);
1092         bool is_minmax_set = false;
1093
1094         switch (around) {
1095                 case V3D_AROUND_CENTER_BOUNDS: /* bounding box center */
1096                 {
1097                         uv_map_transform_calc_bounds(em, bounds[0], bounds[1]);
1098                         is_minmax_set = true;
1099                         mid_v3_v3v3(r_center, bounds[0], bounds[1]);
1100                         break;
1101                 }
1102                 case V3D_AROUND_CENTER_MEAN:
1103                 {
1104                         uv_map_transform_calc_center_median(em, r_center);
1105                         break;
1106                 }
1107                 case V3D_AROUND_CURSOR:  /* cursor center */
1108                 {
1109                         invert_m4_m4(ob->imat, ob->obmat);
1110                         mul_v3_m4v3(r_center, ob->imat, ED_view3d_cursor3d_get(scene, v3d)->location);
1111                         break;
1112                 }
1113                 case V3D_AROUND_ACTIVE:
1114                 {
1115                         BMEditSelection ese;
1116                         if (BM_select_history_active_get(em->bm, &ese)) {
1117                                 BM_editselection_center(&ese, r_center);
1118                                 break;
1119                         }
1120                         ATTR_FALLTHROUGH;
1121                 }
1122                 case V3D_AROUND_LOCAL_ORIGINS:  /* object center */
1123                 default:
1124                         zero_v3(r_center);
1125                         break;
1126         }
1127
1128         /* if this is passed, always set! */
1129         if (r_bounds) {
1130                 if (!is_minmax_set) {
1131                         uv_map_transform_calc_bounds(em, bounds[0], bounds[1]);
1132                 }
1133                 copy_v3_v3(r_bounds[0], bounds[0]);
1134                 copy_v3_v3(r_bounds[1], bounds[1]);
1135         }
1136 }
1137
1138 static void uv_map_rotation_matrix_ex(
1139         float result[4][4], RegionView3D *rv3d, Object *ob,
1140         float upangledeg, float sideangledeg, float radius, float offset[4])
1141 {
1142         float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
1143         float sideangle = 0.0f, upangle = 0.0f;
1144
1145         /* get rotation of the current view matrix */
1146         if (rv3d)
1147                 copy_m4_m4(viewmatrix, rv3d->viewmat);
1148         else
1149                 unit_m4(viewmatrix);
1150
1151         /* but shifting */
1152         copy_v4_fl(viewmatrix[3], 0.0f);
1153
1154         /* get rotation of the current object matrix */
1155         copy_m4_m4(rotobj, ob->obmat);
1156
1157         /* but shifting */
1158         add_v4_v4(rotobj[3], offset);
1159         rotobj[3][3] = 0.0f;
1160
1161         zero_m4(rotup);
1162         zero_m4(rotside);
1163
1164         /* compensate front/side.. against opengl x,y,z world definition */
1165         /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */
1166         /* i wanted to keep the reason here, so we're rotating*/
1167         sideangle = (float)M_PI * (sideangledeg + 180.0f) / 180.0f;
1168         rotside[0][0] =  cosf(sideangle);
1169         rotside[0][1] = -sinf(sideangle);
1170         rotside[1][0] =  sinf(sideangle);
1171         rotside[1][1] =  cosf(sideangle);
1172         rotside[2][2] =  1.0f;
1173
1174         upangle = (float)M_PI * upangledeg / 180.0f;
1175         rotup[1][1] =  cosf(upangle) / radius;
1176         rotup[1][2] = -sinf(upangle) / radius;
1177         rotup[2][1] =  sinf(upangle) / radius;
1178         rotup[2][2] =  cosf(upangle) / radius;
1179         rotup[0][0] =  1.0f / radius;
1180
1181         /* calculate transforms*/
1182         mul_m4_series(result, rotup, rotside, viewmatrix, rotobj);
1183 }
1184
1185 static void uv_map_rotation_matrix(
1186         float result[4][4], RegionView3D *rv3d, Object *ob,
1187         float upangledeg, float sideangledeg, float radius)
1188 {
1189         float offset[4] = {0};
1190         uv_map_rotation_matrix_ex(result, rv3d, ob, upangledeg, sideangledeg, radius, offset);
1191 }
1192
1193 static void uv_map_transform(bContext *C, wmOperator *op, float rotmat[4][4])
1194 {
1195         /* context checks are messy here, making it work in both 3d view and uv editor */
1196         Object *obedit = CTX_data_edit_object(C);
1197         RegionView3D *rv3d = CTX_wm_region_view3d(C);
1198         /* common operator properties */
1199         int align = RNA_enum_get(op->ptr, "align");
1200         int direction = RNA_enum_get(op->ptr, "direction");
1201         float radius = RNA_struct_find_property(op->ptr, "radius") ? RNA_float_get(op->ptr, "radius") : 1.0f;
1202         float upangledeg, sideangledeg;
1203
1204         if (direction == VIEW_ON_EQUATOR) {
1205                 upangledeg = 90.0f;
1206                 sideangledeg = 0.0f;
1207         }
1208         else {
1209                 upangledeg = 0.0f;
1210                 if (align == POLAR_ZY) sideangledeg = 0.0f;
1211                 else sideangledeg = 90.0f;
1212         }
1213
1214         /* be compatible to the "old" sphere/cylinder mode */
1215         if (direction == ALIGN_TO_OBJECT)
1216                 unit_m4(rotmat);
1217         else
1218                 uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius);
1219
1220 }
1221
1222 static void uv_transform_properties(wmOperatorType *ot, int radius)
1223 {
1224         static const EnumPropertyItem direction_items[] = {
1225                 {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"},
1226                 {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"},
1227                 {ALIGN_TO_OBJECT, "ALIGN_TO_OBJECT", 0, "Align to Object", "Align according to object transform"},
1228                 {0, NULL, 0, NULL, NULL}
1229         };
1230         static const EnumPropertyItem align_items[] = {
1231                 {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"},
1232                 {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"},
1233                 {0, NULL, 0, NULL, NULL}
1234         };
1235
1236         RNA_def_enum(ot->srna, "direction", direction_items, VIEW_ON_EQUATOR, "Direction",
1237                      "Direction of the sphere or cylinder");
1238         RNA_def_enum(ot->srna, "align", align_items, VIEW_ON_EQUATOR, "Align",
1239                      "How to determine rotation around the pole");
1240         if (radius)
1241                 RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius",
1242                               "Radius of the sphere or cylinder", 0.0001f, 100.0f);
1243 }
1244
1245 static void correct_uv_aspect(Scene *scene, Object *ob, BMEditMesh *em)
1246 {
1247         BMLoop *l;
1248         BMIter iter, liter;
1249         MLoopUV *luv;
1250         BMFace *efa;
1251         float scale, aspx, aspy;
1252
1253         const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1254
1255         ED_uvedit_get_aspect(scene, ob, em->bm, &aspx, &aspy);
1256
1257         if (aspx == aspy)
1258                 return;
1259
1260         if (aspx > aspy) {
1261                 scale = aspy / aspx;
1262
1263                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1264                         if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1265                                 continue;
1266
1267                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1268                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1269                                 luv->uv[0] = ((luv->uv[0] - 0.5f) * scale) + 0.5f;
1270                         }
1271                 }
1272         }
1273         else {
1274                 scale = aspx / aspy;
1275
1276                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1277                         if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1278                                 continue;
1279
1280                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1281                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1282                                 luv->uv[1] = ((luv->uv[1] - 0.5f) * scale) + 0.5f;
1283                         }
1284                 }
1285         }
1286 }
1287
1288 /******************** Map Clip & Correct ******************/
1289
1290 static void uv_map_clip_correct_properties(wmOperatorType *ot)
1291 {
1292         RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect",
1293                         "Map UVs taking image aspect ratio into account");
1294         RNA_def_boolean(ot->srna, "clip_to_bounds", 0, "Clip to Bounds",
1295                         "Clip UV coordinates to bounds after unwrapping");
1296         RNA_def_boolean(ot->srna, "scale_to_bounds", 0, "Scale to Bounds",
1297                         "Scale UV coordinates to bounds after unwrapping");
1298 }
1299
1300 static void uv_map_clip_correct_multi(Scene *scene, Object **objects, uint objects_len, wmOperator *op)
1301 {
1302         BMFace *efa;
1303         BMLoop *l;
1304         BMIter iter, liter;
1305         MLoopUV *luv;
1306         float dx, dy, min[2], max[2];
1307         const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
1308         const bool clip_to_bounds = RNA_boolean_get(op->ptr, "clip_to_bounds");
1309         const bool scale_to_bounds = RNA_boolean_get(op->ptr, "scale_to_bounds");
1310
1311         INIT_MINMAX2(min, max);
1312
1313         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1314                 Object *ob = objects[ob_index];
1315
1316                 BMEditMesh *em = BKE_editmesh_from_object(ob);
1317                 const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1318
1319                 /* correct for image aspect ratio */
1320                 if (correct_aspect)
1321                         correct_uv_aspect(scene, ob, em);
1322
1323                 if (scale_to_bounds) {
1324                         /* find uv limits */
1325                         BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
1326                                 if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1327                                         continue;
1328
1329                                 BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
1330                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1331                                         minmax_v2v2_v2(min, max, luv->uv);
1332                                 }
1333                         }
1334                 }
1335                 else if (clip_to_bounds) {
1336                         /* clipping and wrapping */
1337                         BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
1338                                 if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1339                                         continue;
1340
1341                                 BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
1342                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1343                                         CLAMP(luv->uv[0], 0.0f, 1.0f);
1344                                         CLAMP(luv->uv[1], 0.0f, 1.0f);
1345                                 }
1346                         }
1347                 }
1348         }
1349
1350         if (scale_to_bounds) {
1351                 /* rescale UV to be in 1/1 */
1352                 dx = (max[0] - min[0]);
1353                 dy = (max[1] - min[1]);
1354
1355                 if (dx > 0.0f)
1356                         dx = 1.0f / dx;
1357                 if (dy > 0.0f)
1358                         dy = 1.0f / dy;
1359
1360                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1361                         Object *ob = objects[ob_index];
1362
1363                         BMEditMesh *em = BKE_editmesh_from_object(ob);
1364                         const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1365
1366                         BM_ITER_MESH(efa, &iter, em->bm, BM_FACES_OF_MESH) {
1367                                 if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1368                                         continue;
1369
1370                                 BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) {
1371                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1372
1373                                         luv->uv[0] = (luv->uv[0] - min[0]) * dx;
1374                                         luv->uv[1] = (luv->uv[1] - min[1]) * dy;
1375                                 }
1376                         }
1377                 }
1378         }
1379 }
1380
1381 static void uv_map_clip_correct(Scene *scene, Object *ob, wmOperator *op)
1382 {
1383         uv_map_clip_correct_multi(scene, &ob, 1, op);
1384 }
1385
1386 /* ******************** Unwrap operator **************** */
1387
1388 /* assumes UV Map is checked, doesn't run update funcs */
1389 void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel, const bool pack)
1390 {
1391         BMEditMesh *em = BKE_editmesh_from_object(obedit);
1392         ParamHandle *handle;
1393
1394         const bool fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0;
1395         const bool correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0;
1396         bool use_subsurf;
1397
1398         modifier_unwrap_state(obedit, scene, &use_subsurf);
1399
1400         if (use_subsurf)
1401                 handle = construct_param_handle_subsurfed(scene, obedit, em, fill_holes, sel, correct_aspect);
1402         else
1403                 handle = construct_param_handle(scene, obedit, em->bm, false, fill_holes, sel, correct_aspect);
1404
1405         param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
1406         param_lscm_solve(handle);
1407         param_lscm_end(handle);
1408
1409         param_average(handle);
1410
1411         if (pack) {
1412                 param_pack(handle, scene->toolsettings->uvcalc_margin, false);
1413         }
1414
1415         param_flush(handle);
1416
1417         param_delete(handle);
1418 }
1419
1420 enum {
1421         UNWRAP_ERROR_NONUNIFORM = (1 << 0),
1422         UNWRAP_ERROR_NEGATIVE = (1 << 1),
1423 };
1424
1425 static int unwrap_exec(bContext *C, wmOperator *op)
1426 {
1427         ViewLayer *view_layer = CTX_data_view_layer(C);
1428         Scene *scene = CTX_data_scene(C);
1429         int method = RNA_enum_get(op->ptr, "method");
1430         const bool fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
1431         const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
1432         const bool use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
1433         bool implicit = false;
1434         int reported_errors = 0;
1435         /* We will report an error unless at least one object has the subsurf modifier in the right place. */
1436         bool subsurf_error = use_subsurf;
1437
1438         uint objects_len = 0;
1439         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
1440
1441         if (!uvedit_have_selection_multi(scene, objects, objects_len, implicit)) {
1442                 MEM_freeN(objects);
1443                 return OPERATOR_CANCELLED;
1444         }
1445
1446         /* add uvs if they don't exist yet */
1447         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1448                 Object *obedit = objects[ob_index];
1449                 float obsize[3];
1450                 bool use_subsurf_final;
1451
1452                 if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1453                         continue;
1454                 }
1455
1456                 if (subsurf_error) {
1457                         /* Double up the check here but better keep ED_unwrap_lscm interface simple and not
1458                          * pass operator for warning append. */
1459                         modifier_unwrap_state(obedit, scene, &use_subsurf_final);
1460                         if (use_subsurf_final) {
1461                                 subsurf_error = false;
1462                         }
1463                 }
1464
1465                 if (reported_errors & (UNWRAP_ERROR_NONUNIFORM | UNWRAP_ERROR_NEGATIVE)) {
1466                         continue;
1467                 }
1468
1469                 mat4_to_size(obsize, obedit->obmat);
1470                 if (!(fabsf(obsize[0] - obsize[1]) < 1e-4f && fabsf(obsize[1] - obsize[2]) < 1e-4f)) {
1471                         if ((reported_errors & UNWRAP_ERROR_NONUNIFORM) == 0) {
1472                                 BKE_report(op->reports, RPT_INFO,
1473                                           "Object has non-uniform scale, unwrap will operate on a non-scaled version of the mesh");
1474                                 reported_errors |= UNWRAP_ERROR_NONUNIFORM;
1475                         }
1476                 }
1477                 else if (is_negative_m4(obedit->obmat)) {
1478                         if ((reported_errors & UNWRAP_ERROR_NEGATIVE) == 0) {
1479                                 BKE_report(op->reports, RPT_INFO,
1480                                            "Object has negative scale, unwrap will operate on a non-flipped version of the mesh");
1481                                 reported_errors |= UNWRAP_ERROR_NEGATIVE;
1482                         }
1483                 }
1484         }
1485
1486         if (subsurf_error) {
1487                 BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap");
1488         }
1489
1490         /* remember last method for live unwrap */
1491         if (RNA_struct_property_is_set(op->ptr, "method"))
1492                 scene->toolsettings->unwrapper = method;
1493         else
1494                 RNA_enum_set(op->ptr, "method", scene->toolsettings->unwrapper);
1495
1496         /* remember packing margin */
1497         if (RNA_struct_property_is_set(op->ptr, "margin"))
1498                 scene->toolsettings->uvcalc_margin = RNA_float_get(op->ptr, "margin");
1499         else
1500                 RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
1501
1502         if (fill_holes) scene->toolsettings->uvcalc_flag |=  UVCALC_FILLHOLES;
1503         else scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES;
1504
1505         if (correct_aspect) scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT;
1506         else scene->toolsettings->uvcalc_flag |=  UVCALC_NO_ASPECT_CORRECT;
1507
1508         if (use_subsurf) scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF;
1509         else scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF;
1510
1511         /* execute unwrap */
1512         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1513                 Object *obedit = objects[ob_index];
1514                 ED_unwrap_lscm(scene, obedit, true, false);
1515                 DEG_id_tag_update(obedit->data, 0);
1516                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1517         }
1518
1519         ED_uvedit_pack_islands_multi(scene, objects, objects_len, true, true, true);
1520
1521         MEM_freeN(objects);
1522
1523         return OPERATOR_FINISHED;
1524 }
1525
1526 void UV_OT_unwrap(wmOperatorType *ot)
1527 {
1528         static const EnumPropertyItem method_items[] = {
1529                 {0, "ANGLE_BASED", 0, "Angle Based", ""},
1530                 {1, "CONFORMAL", 0, "Conformal", ""},
1531                 {0, NULL, 0, NULL, NULL}
1532         };
1533
1534         /* identifiers */
1535         ot->name = "Unwrap";
1536         ot->description = "Unwrap the mesh of the object being edited";
1537         ot->idname = "UV_OT_unwrap";
1538         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1539
1540         /* api callbacks */
1541         ot->exec = unwrap_exec;
1542         ot->poll = ED_operator_uvmap;
1543
1544         /* properties */
1545         RNA_def_enum(ot->srna, "method", method_items, 0, "Method",
1546                      "Unwrapping method (Angle Based usually gives better results than Conformal, while being somewhat slower)");
1547         RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes",
1548                         "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry");
1549         RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect",
1550                         "Map UVs taking image aspect ratio into account");
1551         RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Modifier",
1552                         "Map UVs taking vertex position after Subdivision Surface modifier has been applied");
1553         RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
1554 }
1555
1556 /**************** Project From View operator **************/
1557 static int uv_from_view_exec(bContext *C, wmOperator *op);
1558
1559 static int uv_from_view_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1560 {
1561         View3D *v3d = CTX_wm_view3d(C);
1562         RegionView3D *rv3d = CTX_wm_region_view3d(C);
1563         Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
1564         PropertyRNA *prop;
1565
1566         prop = RNA_struct_find_property(op->ptr, "camera_bounds");
1567         if (!RNA_property_is_set(op->ptr, prop)) RNA_property_boolean_set(op->ptr, prop, (camera != NULL));
1568         prop = RNA_struct_find_property(op->ptr, "correct_aspect");
1569         if (!RNA_property_is_set(op->ptr, prop)) RNA_property_boolean_set(op->ptr, prop, (camera == NULL));
1570
1571         return uv_from_view_exec(C, op);
1572 }
1573
1574 static int uv_from_view_exec(bContext *C, wmOperator *op)
1575 {
1576         ViewLayer *view_layer = CTX_data_view_layer(C);
1577         Scene *scene = CTX_data_scene(C);
1578         ARegion *ar = CTX_wm_region(C);
1579         View3D *v3d = CTX_wm_view3d(C);
1580         RegionView3D *rv3d = CTX_wm_region_view3d(C);
1581         Camera *camera = ED_view3d_camera_data_get(v3d, rv3d);
1582         BMFace *efa;
1583         BMLoop *l;
1584         BMIter iter, liter;
1585         MLoopUV *luv;
1586         float rotmat[4][4];
1587         float objects_pos_offset[4];
1588         bool changed_multi = false;
1589
1590         const bool use_orthographic = RNA_boolean_get(op->ptr, "orthographic");
1591
1592         /* Note: objects that aren't touched are set to NULL (to skip clipping). */
1593         uint objects_len = 0;
1594         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
1595
1596         if (use_orthographic) {
1597                 /* Calculate average object position. */
1598                 float objects_pos_avg[4] = {0};
1599
1600                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1601                         add_v4_v4(objects_pos_avg, objects[ob_index]->obmat[3]);
1602                 }
1603
1604                 mul_v4_fl(objects_pos_avg, 1.0f / objects_len);
1605                 negate_v4_v4(objects_pos_offset, objects_pos_avg);
1606         }
1607
1608         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1609                 Object *obedit = objects[ob_index];
1610                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1611                 bool changed = false;
1612
1613                 /* add uvs if they don't exist yet */
1614                 if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1615                         continue;
1616                 }
1617
1618                 const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1619
1620                 if (use_orthographic) {
1621                         uv_map_rotation_matrix_ex(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f, objects_pos_offset);
1622
1623                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1624                                 if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1625                                         continue;
1626
1627                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1628                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1629                                         BLI_uvproject_from_view_ortho(luv->uv, l->v->co, rotmat);
1630                                 }
1631                                 changed = true;
1632                         }
1633                 }
1634                 else if (camera) {
1635                         const bool camera_bounds = RNA_boolean_get(op->ptr, "camera_bounds");
1636                         struct ProjCameraInfo *uci = BLI_uvproject_camera_info(
1637                                 v3d->camera, obedit->obmat,
1638                                 camera_bounds ? (scene->r.xsch * scene->r.xasp) : 1.0f,
1639                                 camera_bounds ? (scene->r.ysch * scene->r.yasp) : 1.0f);
1640
1641                         if (uci) {
1642                                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1643                                         if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1644                                                 continue;
1645
1646                                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1647                                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1648                                                 BLI_uvproject_from_camera(luv->uv, l->v->co, uci);
1649                                         }
1650                                         changed = true;
1651                                 }
1652
1653                                 MEM_freeN(uci);
1654                         }
1655                 }
1656                 else {
1657                         copy_m4_m4(rotmat, obedit->obmat);
1658
1659                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1660                                 if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1661                                         continue;
1662
1663                                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1664                                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1665                                         BLI_uvproject_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
1666                                 }
1667                                 changed = true;
1668                         }
1669                 }
1670
1671                 if (changed) {
1672                         changed_multi = true;
1673                         DEG_id_tag_update(obedit->data, 0);
1674                         WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1675                 }
1676                 else {
1677                         ARRAY_DELETE_REORDER_LAST(objects, ob_index, 1, objects_len);
1678                         objects_len -= 1;
1679                         ob_index -= 1;
1680                 }
1681         }
1682
1683         if (changed_multi) {
1684                 uv_map_clip_correct_multi(scene, objects, objects_len, op);
1685         }
1686
1687         MEM_freeN(objects);
1688
1689         if (changed_multi) {
1690                 return OPERATOR_FINISHED;
1691         }
1692         else {
1693                 return OPERATOR_CANCELLED;
1694         }
1695 }
1696
1697 static bool uv_from_view_poll(bContext *C)
1698 {
1699         RegionView3D *rv3d = CTX_wm_region_view3d(C);
1700
1701         if (!ED_operator_uvmap(C))
1702                 return 0;
1703
1704         return (rv3d != NULL);
1705 }
1706
1707 void UV_OT_project_from_view(wmOperatorType *ot)
1708 {
1709         /* identifiers */
1710         ot->name = "Project From View";
1711         ot->idname = "UV_OT_project_from_view";
1712         ot->description = "Project the UV vertices of the mesh as seen in current 3D view";
1713
1714         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1715
1716         /* api callbacks */
1717         ot->invoke = uv_from_view_invoke;
1718         ot->exec = uv_from_view_exec;
1719         ot->poll = uv_from_view_poll;
1720
1721         /* properties */
1722         RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic",
1723                         "Use orthographic projection");
1724         RNA_def_boolean(ot->srna, "camera_bounds", 1, "Camera Bounds",
1725                         "Map UVs to the camera region taking resolution and aspect into account");
1726         uv_map_clip_correct_properties(ot);
1727 }
1728
1729 /********************** Reset operator ********************/
1730
1731 static int reset_exec(bContext *C, wmOperator *UNUSED(op))
1732 {
1733         Scene *scene = CTX_data_scene(C);
1734
1735         ViewLayer *view_layer = CTX_data_view_layer(C);
1736         uint objects_len = 0;
1737         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
1738         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1739                 Object *obedit = objects[ob_index];
1740                 Mesh *me = (Mesh *)obedit->data;
1741                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1742
1743                 if (em->bm->totfacesel == 0) {
1744                         continue;
1745                 }
1746
1747                 /* add uvs if they don't exist yet */
1748                 if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1749                         continue;
1750                 }
1751
1752                 ED_mesh_uv_loop_reset(C, me);
1753
1754                 DEG_id_tag_update(obedit->data, 0);
1755                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1756         }
1757         MEM_freeN(objects);
1758
1759         return OPERATOR_FINISHED;
1760 }
1761
1762 void UV_OT_reset(wmOperatorType *ot)
1763 {
1764         /* identifiers */
1765         ot->name = "Reset";
1766         ot->idname = "UV_OT_reset";
1767         ot->description = "Reset UV projection";
1768
1769         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1770
1771         /* api callbacks */
1772         ot->exec = reset_exec;
1773         ot->poll = ED_operator_uvmap;
1774 }
1775
1776 /****************** Sphere Project operator ***************/
1777
1778 static void uv_sphere_project(float target[2], float source[3], float center[3], float rotmat[4][4])
1779 {
1780         float pv[3];
1781
1782         sub_v3_v3v3(pv, source, center);
1783         mul_m4_v3(rotmat, pv);
1784
1785         map_to_sphere(&target[0], &target[1], pv[0], pv[1], pv[2]);
1786
1787         /* split line is always zero */
1788         if (target[0] >= 1.0f)
1789                 target[0] -= 1.0f;
1790 }
1791
1792 static void uv_map_mirror(BMEditMesh *em, BMFace *efa)
1793 {
1794         BMLoop *l;
1795         BMIter liter;
1796         MLoopUV *luv;
1797         float **uvs = BLI_array_alloca(uvs, efa->len);
1798         float dx;
1799         int i, mi;
1800
1801         const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1802
1803         BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
1804                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1805                 uvs[i] = luv->uv;
1806         }
1807
1808         mi = 0;
1809         for (i = 1; i < efa->len; i++)
1810                 if (uvs[i][0] > uvs[mi][0])
1811                         mi = i;
1812
1813         for (i = 0; i < efa->len; i++) {
1814                 if (i != mi) {
1815                         dx = uvs[mi][0] - uvs[i][0];
1816                         if (dx > 0.5f) uvs[i][0] += 1.0f;
1817                 }
1818         }
1819 }
1820
1821 static int sphere_project_exec(bContext *C, wmOperator *op)
1822 {
1823         Scene *scene = CTX_data_scene(C);
1824         View3D *v3d = CTX_wm_view3d(C);
1825
1826         ViewLayer *view_layer = CTX_data_view_layer(C);
1827         uint objects_len = 0;
1828         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
1829         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1830                 Object *obedit = objects[ob_index];
1831                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1832                 BMFace *efa;
1833                 BMLoop *l;
1834                 BMIter iter, liter;
1835                 MLoopUV *luv;
1836
1837                 if (em->bm->totfacesel == 0) {
1838                         continue;
1839                 }
1840
1841                 /* add uvs if they don't exist yet */
1842                 if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1843                         continue;
1844                 }
1845
1846                 const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1847                 float center[3], rotmat[4][4];
1848
1849                 uv_map_transform(C, op, rotmat);
1850                 uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
1851
1852                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1853                         if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1854                                 continue;
1855
1856                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1857                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1858
1859                                 uv_sphere_project(luv->uv, l->v->co, center, rotmat);
1860                         }
1861
1862                         uv_map_mirror(em, efa);
1863                 }
1864
1865                 uv_map_clip_correct(scene, obedit, op);
1866
1867                 DEG_id_tag_update(obedit->data, 0);
1868                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1869         }
1870         MEM_freeN(objects);
1871
1872         return OPERATOR_FINISHED;
1873 }
1874
1875 void UV_OT_sphere_project(wmOperatorType *ot)
1876 {
1877         /* identifiers */
1878         ot->name = "Sphere Projection";
1879         ot->idname = "UV_OT_sphere_project";
1880         ot->description = "Project the UV vertices of the mesh over the curved surface of a sphere";
1881
1882         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1883
1884         /* api callbacks */
1885         ot->exec = sphere_project_exec;
1886         ot->poll = ED_operator_uvmap;
1887
1888         /* properties */
1889         uv_transform_properties(ot, 0);
1890         uv_map_clip_correct_properties(ot);
1891 }
1892
1893 /***************** Cylinder Project operator **************/
1894
1895 static void uv_cylinder_project(float target[2], float source[3], float center[3], float rotmat[4][4])
1896 {
1897         float pv[3];
1898
1899         sub_v3_v3v3(pv, source, center);
1900         mul_m4_v3(rotmat, pv);
1901
1902         map_to_tube(&target[0], &target[1], pv[0], pv[1], pv[2]);
1903
1904         /* split line is always zero */
1905         if (target[0] >= 1.0f)
1906                 target[0] -= 1.0f;
1907 }
1908
1909 static int cylinder_project_exec(bContext *C, wmOperator *op)
1910 {
1911         Scene *scene = CTX_data_scene(C);
1912         View3D *v3d = CTX_wm_view3d(C);
1913
1914         ViewLayer *view_layer = CTX_data_view_layer(C);
1915         uint objects_len = 0;
1916         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
1917         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1918                 Object *obedit = objects[ob_index];
1919                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
1920                 BMFace *efa;
1921                 BMLoop *l;
1922                 BMIter iter, liter;
1923                 MLoopUV *luv;
1924
1925                 if (em->bm->totfacesel == 0) {
1926                         continue;
1927                 }
1928
1929                 /* add uvs if they don't exist yet */
1930                 if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1931                         continue;
1932                 }
1933
1934                 const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV);
1935                 float center[3], rotmat[4][4];
1936
1937                 uv_map_transform(C, op, rotmat);
1938                 uv_map_transform_center(scene, v3d, obedit, em, center, NULL);
1939
1940                 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1941                         if (!BM_elem_flag_test(efa, BM_ELEM_SELECT))
1942                                 continue;
1943
1944                         BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1945                                 luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
1946
1947                                 uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
1948                         }
1949
1950                         uv_map_mirror(em, efa);
1951                 }
1952
1953                 uv_map_clip_correct(scene, obedit, op);
1954
1955                 DEG_id_tag_update(obedit->data, 0);
1956                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
1957         }
1958         MEM_freeN(objects);
1959
1960         return OPERATOR_FINISHED;
1961 }
1962
1963 void UV_OT_cylinder_project(wmOperatorType *ot)
1964 {
1965         /* identifiers */
1966         ot->name = "Cylinder Projection";
1967         ot->idname = "UV_OT_cylinder_project";
1968         ot->description = "Project the UV vertices of the mesh over the curved wall of a cylinder";
1969
1970         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1971
1972         /* api callbacks */
1973         ot->exec = cylinder_project_exec;
1974         ot->poll = ED_operator_uvmap;
1975
1976         /* properties */
1977         uv_transform_properties(ot, 1);
1978         uv_map_clip_correct_properties(ot);
1979 }
1980
1981 /******************* Cube Project operator ****************/
1982
1983 void ED_uvedit_unwrap_cube_project(BMesh *bm, float cube_size, bool use_select, const float center[3])
1984 {
1985         BMFace *efa;
1986         BMLoop *l;
1987         BMIter iter, liter;
1988         MLoopUV *luv;
1989         float loc[3];
1990         int cox, coy;
1991
1992         int cd_loop_uv_offset;
1993
1994         cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
1995
1996         if (center) {
1997                 copy_v3_v3(loc, center);
1998         }
1999         else {
2000                 zero_v3(loc);
2001         }
2002
2003         /* choose x,y,z axis for projection depending on the largest normal
2004          * component, but clusters all together around the center of map. */
2005
2006         BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
2007                 /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
2008                 if (use_select && !BM_elem_flag_test(efa, BM_ELEM_SELECT))
2009                         continue;
2010
2011                 axis_dominant_v3(&cox, &coy, efa->no);
2012
2013                 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
2014                         luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
2015                         luv->uv[0] = 0.5f + 0.5f * cube_size * (l->v->co[cox] - loc[cox]);
2016                         luv->uv[1] = 0.5f + 0.5f * cube_size * (l->v->co[coy] - loc[coy]);
2017                 }
2018         }
2019 }
2020
2021 static int cube_project_exec(bContext *C, wmOperator *op)
2022 {
2023         Scene *scene = CTX_data_scene(C);
2024         View3D *v3d = CTX_wm_view3d(C);
2025
2026         PropertyRNA *prop_cube_size = RNA_struct_find_property(op->ptr, "cube_size");
2027         const float cube_size_init = RNA_property_float_get(op->ptr, prop_cube_size);
2028
2029         ViewLayer *view_layer = CTX_data_view_layer(C);
2030         uint objects_len = 0;
2031         Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
2032         for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
2033                 Object *obedit = objects[ob_index];
2034                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
2035
2036                 if (em->bm->totfacesel == 0) {
2037                         continue;
2038                 }
2039
2040                 /* add uvs if they don't exist yet */
2041                 if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
2042                         continue;
2043                 }
2044
2045                 float bounds[2][3];
2046                 float (*bounds_buf)[3] = NULL;
2047
2048                 if (!RNA_property_is_set(op->ptr, prop_cube_size)) {
2049                         bounds_buf = bounds;
2050                 }
2051
2052                 float center[3];
2053                 uv_map_transform_center(scene, v3d, obedit, em, center, bounds_buf);
2054
2055                 /* calculate based on bounds */
2056                 float cube_size = cube_size_init;
2057                 if (bounds_buf) {
2058                         float dims[3];
2059                         sub_v3_v3v3(dims, bounds[1], bounds[0]);
2060                         cube_size = max_fff(UNPACK3(dims));
2061                         cube_size = cube_size ? 2.0f / cube_size : 1.0f;
2062                         if (ob_index == 0) {
2063                                 /* This doesn't fit well with, multiple objects. */
2064                                 RNA_property_float_set(op->ptr, prop_cube_size, cube_size);
2065                         }
2066                 }
2067
2068                 ED_uvedit_unwrap_cube_project(em->bm, cube_size, true, center);
2069
2070                 uv_map_clip_correct(scene, obedit, op);
2071
2072                 DEG_id_tag_update(obedit->data, 0);
2073                 WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
2074         }
2075         MEM_freeN(objects);
2076
2077         return OPERATOR_FINISHED;
2078 }
2079
2080 void UV_OT_cube_project(wmOperatorType *ot)
2081 {
2082         /* identifiers */
2083         ot->name = "Cube Projection";
2084         ot->idname = "UV_OT_cube_project";
2085         ot->description = "Project the UV vertices of the mesh over the six faces of a cube";
2086
2087         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2088
2089         /* api callbacks */
2090         ot->exec = cube_project_exec;
2091         ot->poll = ED_operator_uvmap;
2092
2093         /* properties */
2094         RNA_def_float(ot->srna, "cube_size", 1.0f, 0.0f, FLT_MAX, "Cube Size", "Size of the cube to project on", 0.001f, 100.0f);
2095         uv_map_clip_correct_properties(ot);
2096 }