3377fdad9db5d69e9918e5400826320650be5fac
[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_meshdata_types.h"
41 #include "DNA_object_types.h"
42 #include "DNA_scene_types.h"
43 #include "DNA_modifier_types.h"
44
45 #include "BLI_utildefines.h"
46 #include "BLI_math.h"
47 #include "BLI_edgehash.h"
48 #include "BLI_editVert.h"
49 #include "BLI_uvproject.h"
50 #include "BLI_utildefines.h"
51 #include "BLI_rand.h"
52 #include "BLI_string.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_depsgraph.h"
59 #include "BKE_image.h"
60 #include "BKE_main.h"
61 #include "BKE_mesh.h"
62 #include "BKE_report.h"
63 #include "BKE_tessmesh.h"
64
65 #include "BLI_math.h"
66 #include "BLI_edgehash.h"
67 #include "BLI_editVert.h"
68 #include "BLI_scanfill.h"
69 #include "BLI_array.h"
70 #include "BLI_uvproject.h"
71
72 #include "PIL_time.h"
73
74 #include "ED_image.h"
75 #include "ED_mesh.h"
76 #include "ED_screen.h"
77 #include "ED_uvedit.h"
78 #include "ED_view3d.h"
79
80 #include "RNA_access.h"
81 #include "RNA_define.h"
82
83
84 #include "WM_api.h"
85 #include "WM_types.h"
86
87 #include "uvedit_intern.h"
88 #include "uvedit_parametrizer.h"
89
90 static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
91 {
92         Main *bmain= CTX_data_main(C);
93         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
94         BMFace *efa;
95         BMIter iter;
96         Image *ima;
97         bScreen *sc;
98         ScrArea *sa;
99         SpaceLink *slink;
100         SpaceImage *sima;
101
102         if(ED_uvedit_test(obedit)) {
103                 return 1;
104         }
105
106         if(em && em->bm->totface && !CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) {
107                 BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY);
108                 BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV);
109         }
110
111         if(!ED_uvedit_test(obedit)) {
112                 return 0;
113         }
114
115         ima= CTX_data_edit_image(C);
116
117         if(!ima) {
118                 /* no image in context in the 3d view, we find first image window .. */
119                 sc= CTX_wm_screen(C);
120
121                 for(sa=sc->areabase.first; sa; sa=sa->next) {
122                         slink= sa->spacedata.first;
123                         if(slink->spacetype == SPACE_IMAGE) {
124                                 sima= (SpaceImage*)slink;
125
126                                 ima= sima->image;
127                                 if(ima) {
128                                         if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
129                                                 ima= NULL;
130                                         else
131                                                 break;
132                                 }
133                         }
134                 }
135         }
136         
137         if(ima)
138                 ED_uvedit_assign_image(bmain, scene, obedit, ima, NULL);
139         
140         /* select new UV's */
141         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
142                 uvedit_face_select(scene, em, efa);
143         }
144
145         return 1;
146 }
147
148 /****************** Parametrizer Conversion ***************/
149
150 static int uvedit_have_selection(Scene *scene, BMEditMesh *em, short implicit)
151 {
152         BMFace *efa;
153         BMLoop *l;
154         BMIter iter, liter;
155         MLoopUV *luv;
156         
157         /* verify if we have any selected uv's before unwrapping,
158            so we can cancel the operator early */
159         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
160                 if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
161                         if(BM_TestHFlag(efa, BM_HIDDEN))
162                                 continue;
163                 }
164                 else if(BM_TestHFlag(efa, BM_HIDDEN) || !BM_TestHFlag(efa, BM_SELECT))
165                         continue;
166         
167                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
168                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
169                         if (!luv)
170                                 return 1;
171                         
172                         if (uvedit_uv_selected(em, scene, l))
173                                 break;
174                 }
175                 
176                 if (implicit && !l)
177                         continue;
178                 
179                 return 1;
180         }
181
182         return 0;
183 }
184
185 static ParamHandle *construct_param_handle(Scene *scene, BMEditMesh *em, 
186                                     short implicit, short fill, short sel, 
187                                     short correct_aspect)
188 {
189         ParamHandle *handle;
190         BMFace *efa;
191         BMLoop *l;
192         BMEdge *eed;
193         BMIter iter, liter;
194         MTexPoly *tf;
195         
196         handle = param_construct_begin();
197
198         if(correct_aspect) {
199                 efa = BM_get_actFace(em->bm, 1);
200
201                 if(efa) {
202                         float aspx, aspy;
203                         tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
204
205                         ED_image_uv_aspect(tf->tpage, &aspx, &aspy);
206                 
207                         if(aspx!=aspy)
208                                 param_aspect_ratio(handle, aspx, aspy);
209                 }
210         }
211         
212         /* we need the vert indices */
213         BM_ElemIndex_Ensure(em->bm, BM_VERT);
214         
215         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
216                 EditVert *v, *lastv, *firstv;
217                 EditFace *sefa;
218                 ParamKey key, vkeys[4];
219                 ParamBool pin[4], select[4];
220                 BMLoop *ls[3];
221                 MLoopUV *luvs[3];
222                 float *co[4];
223                 float *uv[4];
224                 int lsel;
225
226                 if((BM_TestHFlag(efa, BM_HIDDEN)) || (sel && BM_TestHFlag(efa, BM_SELECT)==0))
227                         continue;
228
229                 /* tf= (MTexPoly *)CustomData_em_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
230                 lsel = 0;
231
232                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
233                         if (uvedit_uv_selected(em, scene, l)) {
234                                 lsel = 1;
235                                 break;
236                         }
237                 }
238
239                 if (implicit && !lsel)
240                         continue;
241
242                 key = (ParamKey)efa;
243
244                 /*scanfill time!*/
245                 BLI_begin_edgefill();
246                 
247                 firstv = lastv = NULL;
248                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
249                         int i;
250                         
251                         v = BLI_addfillvert(l->v->co);
252                         
253                         /*add small random offset*/
254                         for (i=0; i<3; i++) {
255                                 v->co[i] += (BLI_drand()-0.5f)*FLT_EPSILON*50;
256                         }
257                         
258                         v->tmp.p = l;
259
260                         if (lastv) {
261                                 BLI_addfilledge(lastv, v);
262                         }
263
264                         lastv = v;
265                         if (!firstv) 
266                                 firstv = v;
267                 }
268
269                 BLI_addfilledge(firstv, v);
270                 
271                 /*mode 2 enables faster handling of tri/quads*/
272                 BLI_edgefill(2);
273                 for (sefa = fillfacebase.first; sefa; sefa=sefa->next) {
274                         ls[0] = sefa->v1->tmp.p;
275                         ls[1] = sefa->v2->tmp.p;
276                         ls[2] = sefa->v3->tmp.p;
277                         
278                         luvs[0] = CustomData_bmesh_get(&em->bm->ldata, ls[0]->head.data, CD_MLOOPUV);
279                         luvs[1] = CustomData_bmesh_get(&em->bm->ldata, ls[1]->head.data, CD_MLOOPUV);
280                         luvs[2] = CustomData_bmesh_get(&em->bm->ldata, ls[2]->head.data, CD_MLOOPUV);
281
282                         vkeys[0] = (ParamKey)BM_GetIndex(ls[0]->v);
283                         vkeys[1] = (ParamKey)BM_GetIndex(ls[1]->v);
284                         vkeys[2] = (ParamKey)BM_GetIndex(ls[2]->v);
285
286                         co[0] = ls[0]->v->co;
287                         co[1] = ls[1]->v->co;
288                         co[2] = ls[2]->v->co;
289
290                         uv[0] = luvs[0]->uv;
291                         uv[1] = luvs[1]->uv;
292                         uv[2] = luvs[2]->uv;
293
294                         pin[0] = (luvs[0]->flag & MLOOPUV_PINNED) != 0;
295                         pin[1] = (luvs[1]->flag & MLOOPUV_PINNED) != 0;
296                         pin[2] = (luvs[2]->flag & MLOOPUV_PINNED) != 0;
297
298                         select[0] = uvedit_uv_selected(em, scene, ls[0]) != 0;
299                         select[1] = uvedit_uv_selected(em, scene, ls[1]) != 0;
300                         select[2] = uvedit_uv_selected(em, scene, ls[2]) != 0;
301
302                         if (!p_face_exists(handle,vkeys,0,1,2))
303                                         param_face_add(handle, key, 3, vkeys, co, uv, pin, select);
304                 }
305
306                 BLI_end_edgefill();
307         }
308
309         if(!implicit) {
310                 BM_ITER(eed, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
311                         if(BM_TestHFlag(eed, BM_SEAM)) {
312                                 ParamKey vkeys[2];
313                                 vkeys[0] = (ParamKey)BM_GetIndex(eed->v1);
314                                 vkeys[1] = (ParamKey)BM_GetIndex(eed->v2);
315                                 param_edge_set_seam(handle, vkeys);
316                         }
317                 }
318         }
319
320         param_construct_end(handle, fill, implicit);
321
322         return handle;
323 }
324
325 #if 0 /* BMESH_TODO */
326 static void texface_from_original_index(EditFace *editFace, MTFace *texFace, int index, float **uv, ParamBool *pin, ParamBool *select, Scene *scene)
327 {
328         int i, nverts = (editFace->v4)? 4: 3;
329
330         *uv = NULL;
331         *pin = 0;
332         *select = 1;
333
334         if(index == ORIGINDEX_NONE)
335                 return;
336
337         for(i = 0; i < nverts; i++) {
338                 if((*(&editFace->v1 + i))->tmp.t == index) {
339                         *uv = texFace->uv[i];
340                         *pin = ((texFace->unwrap & TF_PIN_MASK(i)) != 0);
341                         *select = (uvedit_uv_selected(scene, editFace, texFace, i) != 0);
342                 }
343         }
344 }
345
346 /* unwrap handle initialization for subsurf aware-unwrapper. The many modifications required to make the original function(see above)
347  * work justified the existence of a new function. */
348 static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *editMesh, short fill, short sel, short correct_aspect)
349 {
350         ParamHandle *handle;
351         /* index pointers */
352         MFace *face;
353         MEdge *edge;
354         EditVert *editVert;
355         MTFace *texface;
356         EditFace *editFace, **editFaceTmp;
357         EditEdge *editEdge, **editEdgeTmp;
358         int i;
359
360         /* modifier initialization data, will  control what type of subdivision will happen*/
361         SubsurfModifierData smd = {{0}};
362         /* Used to hold subsurfed Mesh */
363         DerivedMesh *derivedMesh, *initialDerived;
364         /* holds original indices for subsurfed mesh */
365         int *origVertIndices, *origFaceIndices, *origEdgeIndices;
366         /* Holds vertices of subsurfed mesh */
367         MVert *subsurfedVerts;
368         MEdge *subsurfedEdges;
369         MFace *subsurfedFaces;
370         MTFace *subsurfedTexfaces;
371         /* number of vertices and faces for subsurfed mesh*/
372         int numOfEdges, numOfFaces;
373
374         /* holds a map to editfaces for every subsurfed MFace. These will be used to get hidden/ selected flags etc. */
375         EditFace **faceMap;
376         /* Mini container to hold all EditFaces so that they may be indexed easily and fast. */
377         EditFace **editFaceArray;
378         /* similar to the above, we need a way to map edges to their original ones */
379         EditEdge **edgeMap;
380         EditEdge **editEdgeArray;
381
382         handle = param_construct_begin();
383
384         if(correct_aspect) {
385                 EditFace *eface = EM_get_actFace(editMesh, 1);
386
387                 if(eface) {
388                         float aspx, aspy;
389                         texface= CustomData_em_get(&editMesh->fdata, eface->data, CD_MTFACE);
390
391                         ED_image_uv_aspect(texface->tpage, &aspx, &aspy);
392                 
393                         if(aspx!=aspy)
394                                 param_aspect_ratio(handle, aspx, aspy);
395                 }
396         }
397
398         /* number of subdivisions to perform */
399         smd.levels = scene->toolsettings->uv_subsurf_level;
400         smd.subdivType = ME_CC_SUBSURF;
401                 
402         initialDerived = CDDM_from_editmesh(editMesh, NULL);
403         derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd,
404                 0, NULL, 0, 0, 1);
405
406         initialDerived->release(initialDerived);
407
408         /* get the derived data */
409         subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
410         subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
411         subsurfedFaces = derivedMesh->getFaceArray(derivedMesh);
412
413         origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
414         origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
415         origFaceIndices = derivedMesh->getFaceDataArray(derivedMesh, CD_ORIGINDEX);
416
417         subsurfedTexfaces = derivedMesh->getFaceDataArray(derivedMesh, CD_MTFACE);
418
419         numOfEdges = derivedMesh->getNumEdges(derivedMesh);
420         numOfFaces = derivedMesh->getNumFaces(derivedMesh);
421
422         faceMap = MEM_mallocN(numOfFaces*sizeof(EditFace *), "unwrap_edit_face_map");
423         editFaceArray = MEM_mallocN(editMesh->totface*sizeof(EditFace *), "unwrap_editFaceArray");
424
425         /* fill edit face array with edit faces */
426         for(editFace = editMesh->faces.first, editFaceTmp = editFaceArray; editFace; editFace= editFace->next, editFaceTmp++)
427                 *editFaceTmp = editFace;
428
429         /* map subsurfed faces to original editFaces */
430         for(i = 0; i < numOfFaces; i++)
431                 faceMap[i] = editFaceArray[origFaceIndices[i]];
432
433         MEM_freeN(editFaceArray);
434
435         edgeMap = MEM_mallocN(numOfEdges*sizeof(EditEdge *), "unwrap_edit_edge_map");
436         editEdgeArray = MEM_mallocN(editMesh->totedge*sizeof(EditEdge *), "unwrap_editEdgeArray");
437
438         /* fill edit edge array with edit edges */
439         for(editEdge = editMesh->edges.first, editEdgeTmp = editEdgeArray; editEdge; editEdge= editEdge->next, editEdgeTmp++)
440                 *editEdgeTmp = editEdge;
441
442         /* map subsurfed edges to original editEdges */
443         for(i = 0; i < numOfEdges; i++) {
444                 /* not all edges correspond to an old edge */
445                 edgeMap[i] = (origEdgeIndices[i] != -1)?
446                         editEdgeArray[origEdgeIndices[i]] : NULL;
447         }
448
449         MEM_freeN(editEdgeArray);
450
451         /* we need the editvert indices too */
452         for(editVert = editMesh->verts.first, i=0; editVert; editVert = editVert->next, i++)
453                 editVert->tmp.t = i;
454
455         /* Prepare and feed faces to the solver */
456         for(i = 0; i < numOfFaces; i++) {
457                 ParamKey key, vkeys[4];
458                 ParamBool pin[4], select[4];
459                 float *co[4];
460                 float *uv[4];
461                 EditFace *origFace = faceMap[i];
462                 MTFace *origtexface = (MTFace *)CustomData_em_get(&editMesh->fdata, origFace->data, CD_MTFACE);
463                 
464                 face = subsurfedFaces+i;
465
466                 if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
467                         if(origFace->h)
468                                 continue;
469                 }
470                 else {
471                         if((origFace->h) || (sel && (origFace->f & SELECT)==0))
472                                 continue;
473                 }
474
475                 /* Now we feed the rest of the data from the subsurfed faces */
476                 texface= subsurfedTexfaces+i;
477
478                 /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
479                 key = (ParamKey)face;
480                 vkeys[0] = (ParamKey)face->v1;
481                 vkeys[1] = (ParamKey)face->v2;
482                 vkeys[2] = (ParamKey)face->v3;
483                 vkeys[3] = (ParamKey)face->v4;
484
485                 co[0] = subsurfedVerts[face->v1].co;
486                 co[1] = subsurfedVerts[face->v2].co;
487                 co[2] = subsurfedVerts[face->v3].co;
488                 co[3] = subsurfedVerts[face->v4].co;
489                 
490                 /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus
491                  * flushing the solution to the edit mesh. */
492                 texface_from_original_index(origFace, origtexface, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene);
493                 texface_from_original_index(origFace, origtexface, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene);
494                 texface_from_original_index(origFace, origtexface, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene);
495                 texface_from_original_index(origFace, origtexface, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene);
496
497                 param_face_add(handle, key, 4, vkeys, co, uv, pin, select);
498         }
499
500         /* these are calculated from original mesh too */
501         for(edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) {
502                 if((edgeMap[i] != NULL) && edgeMap[i]->seam) {
503                         ParamKey vkeys[2];
504                         vkeys[0] = (ParamKey)edge->v1;
505                         vkeys[1] = (ParamKey)edge->v2;
506                         param_edge_set_seam(handle, vkeys);
507                 }
508         }
509
510         param_construct_end(handle, fill, 0);
511
512         /* cleanup */
513         MEM_freeN(faceMap);
514         MEM_freeN(edgeMap);
515         derivedMesh->release(derivedMesh);
516
517         return handle;
518 }
519
520 #else
521
522 static ParamHandle *construct_param_handle_subsurfed(Scene *scene, BMEditMesh *editMesh, short fill, short sel, short correct_aspect)
523 {
524         (void)scene;
525         (void)editMesh;
526         (void)fill;
527         (void)sel;
528         (void)correct_aspect;
529         return NULL;
530 }
531
532 #endif /* BMESH_TODO */
533
534 /* ******************** Minimize Stretch operator **************** */
535
536 typedef struct MinStretch {
537         Scene *scene;
538         Object *obedit;
539         BMEditMesh *em;
540         ParamHandle *handle;
541         float blend;
542         double lasttime;
543         int i, iterations;
544         wmTimer *timer;
545 } MinStretch;
546
547 static int minimize_stretch_init(bContext *C, wmOperator *op)
548 {
549         Scene *scene= CTX_data_scene(C);
550         Object *obedit= CTX_data_edit_object(C);
551         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
552         MinStretch *ms;
553         int fill_holes= RNA_boolean_get(op->ptr, "fill_holes");
554         short implicit= 1;
555
556         if(!uvedit_have_selection(scene, em, implicit)) {
557                 return 0;
558         }
559
560         ms= MEM_callocN(sizeof(MinStretch), "MinStretch");
561         ms->scene= scene;
562         ms->obedit= obedit;
563         ms->em= em;
564         ms->blend= RNA_float_get(op->ptr, "blend");
565         ms->iterations= RNA_int_get(op->ptr, "iterations");
566         ms->i= 0;
567         ms->handle= construct_param_handle(scene, em, implicit, fill_holes, 1, 1);
568         ms->lasttime= PIL_check_seconds_timer();
569
570         param_stretch_begin(ms->handle);
571         if(ms->blend != 0.0f)
572                 param_stretch_blend(ms->handle, ms->blend);
573
574         op->customdata= ms;
575
576         return 1;
577 }
578
579 static void minimize_stretch_iteration(bContext *C, wmOperator *op, int interactive)
580 {
581         MinStretch *ms= op->customdata;
582         ScrArea *sa= CTX_wm_area(C);
583
584         param_stretch_blend(ms->handle, ms->blend);
585         param_stretch_iter(ms->handle);
586
587         ms->i++;
588         RNA_int_set(op->ptr, "iterations", ms->i);
589
590         if(interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
591                 char str[100];
592
593                 param_flush(ms->handle);
594
595                 if(sa) {
596                         BLI_snprintf(str, sizeof(str), "Minimize Stretch. Blend %.2f", ms->blend);
597                         ED_area_headerprint(sa, str);
598                 }
599
600                 ms->lasttime = PIL_check_seconds_timer();
601
602                 DAG_id_tag_update(ms->obedit->data, 0);
603                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ms->obedit->data);
604         }
605 }
606
607 static void minimize_stretch_exit(bContext *C, wmOperator *op, int cancel)
608 {
609         MinStretch *ms= op->customdata;
610         ScrArea *sa= CTX_wm_area(C);
611
612         if(sa)
613                 ED_area_headerprint(sa, NULL);
614         if(ms->timer)
615                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer);
616
617         if(cancel)
618                 param_flush_restore(ms->handle);
619         else
620                 param_flush(ms->handle);
621
622         param_stretch_end(ms->handle);
623         param_delete(ms->handle);
624
625         DAG_id_tag_update(ms->obedit->data, 0);
626         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ms->obedit->data);
627
628         MEM_freeN(ms);
629         op->customdata= NULL;
630 }
631
632 static int minimize_stretch_exec(bContext *C, wmOperator *op)
633 {
634         int i, iterations;
635
636         if(!minimize_stretch_init(C, op))
637                 return OPERATOR_CANCELLED;
638
639         iterations= RNA_int_get(op->ptr, "iterations");
640         for(i=0; i<iterations; i++)
641                 minimize_stretch_iteration(C, op, 0);
642         minimize_stretch_exit(C, op, 0);
643
644         return OPERATOR_FINISHED;
645 }
646
647 static int minimize_stretch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
648 {
649         MinStretch *ms;
650
651         if(!minimize_stretch_init(C, op))
652                 return OPERATOR_CANCELLED;
653
654         minimize_stretch_iteration(C, op, 1);
655
656         ms= op->customdata;
657         WM_event_add_modal_handler(C, op);
658         ms->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
659
660         return OPERATOR_RUNNING_MODAL;
661 }
662
663 static int minimize_stretch_modal(bContext *C, wmOperator *op, wmEvent *event)
664 {
665         MinStretch *ms= op->customdata;
666
667         switch(event->type) {
668                 case ESCKEY:
669                 case RIGHTMOUSE:
670                         minimize_stretch_exit(C, op, 1);
671                         return OPERATOR_CANCELLED;
672                 case RETKEY:
673                 case PADENTER:
674                 case LEFTMOUSE:
675                         minimize_stretch_exit(C, op, 0);
676                         return OPERATOR_FINISHED;
677                 case PADPLUSKEY:
678                 case WHEELUPMOUSE:
679                         if(ms->blend < 0.95f) {
680                                 ms->blend += 0.1f;
681                                 ms->lasttime= 0.0f;
682                                 RNA_float_set(op->ptr, "blend", ms->blend);
683                                 minimize_stretch_iteration(C, op, 1);
684                         }
685                         break;
686                 case PADMINUS:
687                 case WHEELDOWNMOUSE:
688                         if(ms->blend > 0.05f) {
689                                 ms->blend -= 0.1f;
690                                 ms->lasttime= 0.0f;
691                                 RNA_float_set(op->ptr, "blend", ms->blend);
692                                 minimize_stretch_iteration(C, op, 1);
693                         }
694                         break;
695                 case TIMER:
696                         if(ms->timer == event->customdata) {
697                                 double start= PIL_check_seconds_timer();
698
699                                 do {
700                                         minimize_stretch_iteration(C, op, 1);
701                                 } while(PIL_check_seconds_timer() - start < 0.01);
702                         }
703                         break;
704         }
705
706         if(ms->iterations && ms->i >= ms->iterations) {
707                 minimize_stretch_exit(C, op, 0);
708                 return OPERATOR_FINISHED;
709         }
710
711         return OPERATOR_RUNNING_MODAL;
712 }
713
714 static int minimize_stretch_cancel(bContext *C, wmOperator *op)
715 {
716         minimize_stretch_exit(C, op, 1);
717
718         return OPERATOR_CANCELLED;
719 }
720
721 void UV_OT_minimize_stretch(wmOperatorType *ot)
722 {
723         /* identifiers */
724         ot->name= "Minimize Stretch";
725         ot->idname= "UV_OT_minimize_stretch";
726         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_GRAB_POINTER|OPTYPE_BLOCKING;
727         ot->description="Reduce UV stretching by relaxing angles";
728         
729         /* api callbacks */
730         ot->exec= minimize_stretch_exec;
731         ot->invoke= minimize_stretch_invoke;
732         ot->modal= minimize_stretch_modal;
733         ot->cancel= minimize_stretch_cancel;
734         ot->poll= ED_operator_uvedit;
735
736         /* properties */
737         RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry");
738         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);
739         RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively", 0, 100);
740 }
741
742 /* ******************** Pack Islands operator **************** */
743
744 static int pack_islands_exec(bContext *C, wmOperator *op)
745 {
746         Scene *scene= CTX_data_scene(C);
747         Object *obedit= CTX_data_edit_object(C);
748         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
749         ParamHandle *handle;
750         short implicit= 1;
751
752         if(!uvedit_have_selection(scene, em, implicit)) {
753                 return OPERATOR_CANCELLED;
754         }
755
756         if(RNA_struct_property_is_set(op->ptr, "margin")) {
757                 scene->toolsettings->uvcalc_margin= RNA_float_get(op->ptr, "margin");
758         }
759         else {
760                 RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
761         }
762
763         handle = construct_param_handle(scene, em, implicit, 0, 1, 1);
764         param_pack(handle, scene->toolsettings->uvcalc_margin);
765         param_flush(handle);
766         param_delete(handle);
767         
768         DAG_id_tag_update(obedit->data, 0);
769         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
770
771         return OPERATOR_FINISHED;
772 }
773
774 void UV_OT_pack_islands(wmOperatorType *ot)
775 {
776         /* identifiers */
777         ot->name= "Pack Islands";
778         ot->idname= "UV_OT_pack_islands";
779         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
780         
781         /* api callbacks */
782         ot->exec= pack_islands_exec;
783         ot->poll= ED_operator_uvedit;
784
785         /* properties */
786         RNA_def_float_factor(ot->srna, "margin", 0.0f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
787 }
788
789 /* ******************** Average Islands Scale operator **************** */
790
791 static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
792 {
793         Scene *scene= CTX_data_scene(C);
794         Object *obedit= CTX_data_edit_object(C);
795         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
796         ParamHandle *handle;
797         short implicit= 1;
798
799         if(!uvedit_have_selection(scene, em, implicit)) {
800                 return OPERATOR_CANCELLED;
801         }
802
803         handle= construct_param_handle(scene, em, implicit, 0, 1, 1);
804         param_average(handle);
805         param_flush(handle);
806         param_delete(handle);
807         
808         DAG_id_tag_update(obedit->data, 0);
809         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
810
811         return OPERATOR_FINISHED;
812 }
813
814 void UV_OT_average_islands_scale(wmOperatorType *ot)
815 {
816         /* identifiers */
817         ot->name= "Average Islands Scale";
818         ot->idname= "UV_OT_average_islands_scale";
819         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
820         
821         /* api callbacks */
822         ot->exec= average_islands_scale_exec;
823         ot->poll= ED_operator_uvedit;
824 }
825
826 /**************** Live Unwrap *****************/
827
828 static ParamHandle *liveHandle = NULL;
829
830 void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
831 {
832         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
833         short abf = scene->toolsettings->unwrapper == 0;
834         short fillholes = scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
835         short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF;
836
837         if(!ED_uvedit_test(obedit)) {
838                 return;
839         }
840
841         if(use_subsurf)
842                 liveHandle = construct_param_handle_subsurfed(scene, em, fillholes, 0, 1);
843         else
844                 liveHandle = construct_param_handle(scene, em, 0, fillholes, 0, 1);
845
846         param_lscm_begin(liveHandle, PARAM_TRUE, abf);
847 }
848
849 void ED_uvedit_live_unwrap_re_solve(void)
850 {
851         if(liveHandle) {
852                 param_lscm_solve(liveHandle);
853                 param_flush(liveHandle);
854         }
855 }
856         
857 void ED_uvedit_live_unwrap_end(short cancel)
858 {
859         if(liveHandle) {
860                 param_lscm_end(liveHandle);
861                 if(cancel)
862                         param_flush_restore(liveHandle);
863                 param_delete(liveHandle);
864                 liveHandle = NULL;
865         }
866 }
867
868 /*************** UV Map Common Transforms *****************/
869
870 #define VIEW_ON_EQUATOR 0
871 #define VIEW_ON_POLES   1
872 #define ALIGN_TO_OBJECT 2
873
874 #define POLAR_ZX        0
875 #define POLAR_ZY        1
876
877 static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, 
878                                     Object *ob, BMEditMesh *em)
879 {
880         BMFace *efa;
881         BMLoop *l;
882         BMIter iter, liter;
883         float min[3], max[3], *cursx;
884         int around= (v3d)? v3d->around: V3D_CENTER;
885
886         /* only operates on the edit object - this is all that's needed now */
887
888         switch(around)  {
889                 case V3D_CENTER: /* bounding box center */
890                         min[0]= min[1]= min[2]= 1e20f;
891                         max[0]= max[1]= max[2]= -1e20f; 
892                         
893                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL)  {
894                                 if(BM_TestHFlag(efa, BM_SELECT)) {
895                                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
896                                                 DO_MINMAX(l->v->co, min, max);
897                                         }
898                                 }
899                         }
900                         mid_v3_v3v3(result, min, max);
901                         break;
902
903                 case V3D_CURSOR: /*cursor center*/ 
904                         cursx= give_cursor(scene, v3d);
905                         /* shift to objects world */
906                         result[0]= cursx[0]-ob->obmat[3][0];
907                         result[1]= cursx[1]-ob->obmat[3][1];
908                         result[2]= cursx[2]-ob->obmat[3][2];
909                         break;
910
911                 case V3D_LOCAL: /*object center*/
912                 case V3D_CENTROID: /* multiple objects centers, only one object here*/
913                 default:
914                         result[0]= result[1]= result[2]= 0.0;
915                         break;
916         }
917 }
918
919 static void uv_map_rotation_matrix(float result[][4], RegionView3D *rv3d, Object *ob,
920                                    float upangledeg, float sideangledeg, float radius)
921 {
922         float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
923         float sideangle= 0.0f, upangle= 0.0f;
924         int k;
925
926         /* get rotation of the current view matrix */
927         if(rv3d)
928                 copy_m4_m4(viewmatrix, rv3d->viewmat);
929         else
930                 unit_m4(viewmatrix);
931
932         /* but shifting */
933         for(k=0; k<4; k++)
934                 viewmatrix[3][k] =0.0f;
935
936         /* get rotation of the current object matrix */
937         copy_m4_m4(rotobj,ob->obmat);
938
939         /* but shifting */
940         for(k=0; k<4; k++)
941                 rotobj[3][k] =0.0f;
942
943         zero_m4(rotup);
944         zero_m4(rotside);
945
946         /* compensate front/side.. against opengl x,y,z world definition */
947         /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */
948         /* i wanted to keep the reason here, so we're rotating*/
949         sideangle= (float)M_PI*(sideangledeg + 180.0f)/180.0f;
950         rotside[0][0]= (float)cos(sideangle);
951         rotside[0][1]= -(float)sin(sideangle);
952         rotside[1][0]= (float)sin(sideangle);
953         rotside[1][1]= (float)cos(sideangle);
954         rotside[2][2]= 1.0f;
955
956         upangle= (float)M_PI*upangledeg/180.0f;
957         rotup[1][1]= (float)cos(upangle)/radius;
958         rotup[1][2]= -(float)sin(upangle)/radius;
959         rotup[2][1]= (float)sin(upangle)/radius;
960         rotup[2][2]= (float)cos(upangle)/radius;
961         rotup[0][0]= (float)1.0f/radius;
962
963         /* calculate transforms*/
964         mul_serie_m4(result, rotup, rotside, viewmatrix, rotobj, NULL, NULL, NULL, NULL);
965 }
966
967 static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float rotmat[4][4])
968 {
969         /* context checks are messy here, making it work in both 3d view and uv editor */
970         Scene *scene= CTX_data_scene(C);
971         Object *obedit= CTX_data_edit_object(C);
972         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
973         View3D *v3d= CTX_wm_view3d(C);
974         RegionView3D *rv3d= CTX_wm_region_view3d(C);
975         /* common operator properties */
976         int align= RNA_enum_get(op->ptr, "align");
977         int direction= RNA_enum_get(op->ptr, "direction");
978         float radius= RNA_struct_find_property(op->ptr, "radius")? RNA_float_get(op->ptr, "radius"): 1.0f;
979         float upangledeg, sideangledeg;
980
981         uv_map_transform_center(scene, v3d, center, obedit, em);
982
983         if(direction == VIEW_ON_EQUATOR) {
984                 upangledeg= 90.0f;
985                 sideangledeg= 0.0f;
986         }
987         else {
988                 upangledeg= 0.0f;
989                 if(align == POLAR_ZY) sideangledeg= 0.0f;
990                 else sideangledeg= 90.0f;
991         }
992
993         /* be compatible to the "old" sphere/cylinder mode */
994         if(direction == ALIGN_TO_OBJECT)
995                 unit_m4(rotmat);
996         else 
997                 uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius);
998
999 }
1000
1001 static void uv_transform_properties(wmOperatorType *ot, int radius)
1002 {
1003         static EnumPropertyItem direction_items[]= {
1004                 {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"},
1005                 {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"},
1006                 {ALIGN_TO_OBJECT, "ALIGN_TO_OBJECT", 0, "Align to Object", "Align according to object transform"},
1007                 {0, NULL, 0, NULL, NULL}
1008         };
1009         static EnumPropertyItem align_items[]= {
1010                 {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"},
1011                 {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"},
1012                 {0, NULL, 0, NULL, NULL}
1013         };
1014
1015         RNA_def_enum(ot->srna, "direction", direction_items, VIEW_ON_EQUATOR, "Direction",
1016                      "Direction of the sphere or cylinder");
1017         RNA_def_enum(ot->srna, "align", align_items, VIEW_ON_EQUATOR, "Align",
1018                      "How to determine rotation around the pole");
1019         if(radius)
1020                 RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius",
1021                               "Radius of the sphere or cylinder", 0.0001f, 100.0f);
1022 }
1023
1024 static void correct_uv_aspect(BMEditMesh *em)
1025 {
1026         BMFace *efa= BM_get_actFace(em->bm, 1);
1027         BMLoop *l;
1028         BMIter iter, liter;
1029         MTexPoly *tf;
1030         MLoopUV *luv;
1031         float scale, aspx= 1.0f, aspy=1.0f;
1032         
1033         if(efa) {
1034                 tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1035                 ED_image_uv_aspect(tf->tpage, &aspx, &aspy);
1036         }
1037         
1038         if(aspx == aspy)
1039                 return;
1040                 
1041         if(aspx > aspy) {
1042                 scale= aspy/aspx;
1043
1044                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1045                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1046                         if (!BM_TestHFlag(efa, BM_SELECT) || BM_TestHFlag(efa, BM_HIDDEN))
1047                                 continue;
1048                         
1049                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1050                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1051                                 luv->uv[0] = ((luv->uv[0]-0.5)*scale)+0.5;
1052                         }
1053                 }
1054         }
1055         else {
1056                 scale= aspx/aspy;
1057
1058                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1059                         tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1060                         if (!BM_TestHFlag(efa, BM_SELECT)||BM_TestHFlag(efa, BM_HIDDEN))
1061                                 continue;
1062                         
1063                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1064                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1065                                 luv->uv[1] = ((luv->uv[1]-0.5)*scale)+0.5;
1066                         }
1067                 }
1068         }
1069 }
1070
1071 /******************** Map Clip & Correct ******************/
1072
1073 static void uv_map_clip_correct_properties(wmOperatorType *ot)
1074 {
1075         RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect",
1076                         "Map UVs taking image aspect ratio into account");
1077         RNA_def_boolean(ot->srna, "clip_to_bounds", 0, "Clip to Bounds",
1078                         "Clip UV coordinates to bounds after unwrapping");
1079         RNA_def_boolean(ot->srna, "scale_to_bounds", 0, "Scale to Bounds",
1080                         "Scale UV coordinates to bounds after unwrapping");
1081 }
1082
1083 static void uv_map_clip_correct(BMEditMesh *em, wmOperator *op)
1084 {
1085         BMFace *efa;
1086         BMLoop *l;
1087         BMIter iter, liter;
1088         MLoopUV *luv;
1089         float dx, dy, min[2], max[2];
1090         int correct_aspect= RNA_boolean_get(op->ptr, "correct_aspect");
1091         int clip_to_bounds= RNA_boolean_get(op->ptr, "clip_to_bounds");
1092         int scale_to_bounds= RNA_boolean_get(op->ptr, "scale_to_bounds");
1093
1094         /* correct for image aspect ratio */
1095         if(correct_aspect)
1096                 correct_uv_aspect(em);
1097
1098         if(scale_to_bounds) {
1099                 INIT_MINMAX2(min, max);
1100                 
1101                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1102                         if (!BM_TestHFlag(efa, BM_SELECT))
1103                                 continue;
1104
1105                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1106                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1107                                 DO_MINMAX2(luv->uv, min, max);
1108                         }
1109                 }
1110                 
1111                 /* rescale UV to be in 1/1 */
1112                 dx= (max[0]-min[0]);
1113                 dy= (max[1]-min[1]);
1114
1115                 if(dx > 0.0f)
1116                         dx= 1.0f/dx;
1117                 if(dy > 0.0f)
1118                         dy= 1.0f/dy;
1119
1120                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1121                         if (!BM_TestHFlag(efa, BM_SELECT))
1122                                 continue;
1123
1124                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1125                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1126                                 
1127                                 luv->uv[0] = (luv->uv[0]-min[0])*dx;
1128                                 luv->uv[1] = (luv->uv[1]-min[1])*dy;
1129                         }
1130                 }
1131         }
1132         else if(clip_to_bounds) {
1133                 /* clipping and wrapping */
1134                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1135                         if (!BM_TestHFlag(efa, BM_SELECT))
1136                                 continue;
1137
1138                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1139                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1140                                 CLAMP(luv->uv[0], 0.0f, 1.0f);
1141                                 CLAMP(luv->uv[1], 0.0f, 1.0f);
1142                         }
1143                 }
1144         }
1145 }
1146
1147 /* ******************** Unwrap operator **************** */
1148
1149 /* assumes UV Map is checked, doesn't run update funcs */
1150 void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
1151 {
1152         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1153         ParamHandle *handle;
1154
1155         const short fill_holes= scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
1156         const short correct_aspect= !(scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT);
1157         const short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF;
1158
1159         if(use_subsurf)
1160                 handle = construct_param_handle_subsurfed(scene, em, fill_holes, sel, correct_aspect);
1161         else
1162                 handle= construct_param_handle(scene, em, 0, fill_holes, sel, correct_aspect);
1163
1164         param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
1165         param_lscm_solve(handle);
1166         param_lscm_end(handle);
1167
1168         param_pack(handle, scene->toolsettings->uvcalc_margin);
1169
1170         param_flush(handle);
1171
1172         param_delete(handle);
1173 }
1174
1175 static int unwrap_exec(bContext *C, wmOperator *op)
1176 {
1177         Scene *scene= CTX_data_scene(C);
1178         Object *obedit= CTX_data_edit_object(C);
1179         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1180         int method = RNA_enum_get(op->ptr, "method");
1181         int fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
1182         int correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
1183         int use_subsurf = RNA_boolean_get(op->ptr, "use_subsurf_data");
1184         int subsurf_level = RNA_int_get(op->ptr, "uv_subsurf_level");
1185         float obsize[3], unitsize[3] = {1.0f, 1.0f, 1.0f};
1186         short implicit= 0;
1187
1188         if(!uvedit_have_selection(scene, em, implicit)) {
1189                 return OPERATOR_CANCELLED;
1190         }
1191         
1192         /* add uvs if they don't exist yet */
1193         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1194                 return OPERATOR_CANCELLED;
1195         }
1196
1197         mat4_to_size(obsize, obedit->obmat);
1198         if(!compare_v3v3(obsize, unitsize, 1e-4f))
1199                 BKE_report(op->reports, RPT_INFO, "Object scale is not 1.0. Unwrap will operate on a non-scaled version of the mesh.");
1200
1201         /* remember last method for live unwrap */
1202         scene->toolsettings->unwrapper = method;
1203         
1204         scene->toolsettings->uv_subsurf_level = subsurf_level;
1205
1206         if(fill_holes)          scene->toolsettings->uvcalc_flag |=  UVCALC_FILLHOLES;
1207         else                            scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES;
1208
1209         if(correct_aspect)      scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT;
1210         else                            scene->toolsettings->uvcalc_flag |=  UVCALC_NO_ASPECT_CORRECT;
1211
1212         if(use_subsurf)         scene->toolsettings->uvcalc_flag |= UVCALC_USESUBSURF;
1213         else                            scene->toolsettings->uvcalc_flag &= ~UVCALC_USESUBSURF;
1214
1215         /* execute unwrap */
1216         ED_unwrap_lscm(scene, obedit, TRUE);
1217
1218         DAG_id_tag_update(obedit->data, 0);
1219         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1220
1221         return OPERATOR_FINISHED;
1222 }
1223
1224 void UV_OT_unwrap(wmOperatorType *ot)
1225 {
1226         static EnumPropertyItem method_items[] = {
1227                 {0, "ANGLE_BASED", 0, "Angle Based", ""},
1228                 {1, "CONFORMAL", 0, "Conformal", ""},
1229                 {0, NULL, 0, NULL, NULL}};
1230
1231         /* identifiers */
1232         ot->name= "Unwrap";
1233         ot->description= "Unwrap the mesh of the object being edited";
1234         ot->idname= "UV_OT_unwrap";
1235         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1236         
1237         /* api callbacks */
1238         ot->exec= unwrap_exec;
1239         ot->poll= ED_operator_uvmap;
1240
1241         /* properties */
1242         RNA_def_enum(ot->srna, "method", method_items, 0, "Method",
1243                      "Unwrapping method (Angle Based usually gives better results than Conformal, while being somewhat slower)");
1244         RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes",
1245                         "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry");
1246         RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect",
1247                         "Map UVs taking image aspect ratio into account");
1248         RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Data", "Map UV's taking vertex position after subsurf into account");
1249         RNA_def_int(ot->srna, "uv_subsurf_level", 1, 1, 6, "SubSurf Target", "Number of times to subdivide before calculating UV's", 1, 6);
1250 }
1251
1252 /**************** Project From View operator **************/
1253 static int uv_from_view_exec(bContext *C, wmOperator *op)
1254 {
1255         Scene *scene= CTX_data_scene(C);
1256         Object *obedit= CTX_data_edit_object(C);
1257         Camera *camera= NULL;
1258         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1259         ARegion *ar = CTX_wm_region(C);
1260         View3D *v3d= CTX_wm_view3d(C);
1261         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1262         BMFace *efa;
1263         BMLoop *l;
1264         BMIter iter, liter;
1265         MLoopUV *luv;
1266         float rotmat[4][4];
1267
1268         /* add uvs if they don't exist yet */
1269         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1270                 return OPERATOR_CANCELLED;
1271         }
1272
1273         /* establish the camera object, so we can default to view mapping if anything is wrong with it */
1274         if ((rv3d->persp==RV3D_CAMOB) && (v3d->camera) && (v3d->camera->type==OB_CAMERA)) {
1275                 camera= v3d->camera->data;
1276         }
1277
1278         if(RNA_boolean_get(op->ptr, "orthographic")) {
1279                 uv_map_rotation_matrix(rotmat, rv3d, obedit, 90.0f, 0.0f, 1.0f);
1280                 
1281                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1282                         if (!BM_TestHFlag(efa, BM_SELECT))
1283                                 continue;
1284
1285                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1286                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1287                                 project_from_view_ortho(luv->uv, l->v->co, rotmat);
1288                         }
1289                 }
1290         }
1291         else if (camera) {
1292                 struct UvCameraInfo *uci= project_camera_info(v3d->camera, obedit->obmat, scene->r.xsch, scene->r.ysch);
1293                 
1294                 if(uci) {
1295                         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1296                                 if (!BM_TestHFlag(efa, BM_SELECT))
1297                                         continue;
1298
1299                                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1300                                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1301                                         project_from_camera(luv->uv, l->v->co, uci);
1302                                 }
1303                         }
1304                         
1305                         MEM_freeN(uci);
1306                 }
1307         }
1308         else {
1309                 copy_m4_m4(rotmat, obedit->obmat);
1310
1311                 BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1312                         if (!BM_TestHFlag(efa, BM_SELECT))
1313                                 continue;
1314
1315                         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1316                                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1317                                 project_from_view(luv->uv, l->v->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
1318                         }
1319                 }
1320         }
1321
1322         uv_map_clip_correct(em, op);
1323
1324         DAG_id_tag_update(obedit->data, 0);
1325         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1326
1327         return OPERATOR_FINISHED;
1328 }
1329
1330 static int uv_from_view_poll(bContext *C)
1331 {
1332         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1333
1334         if(!ED_operator_uvmap(C))
1335                 return 0;
1336
1337         return (rv3d != NULL);
1338 }
1339
1340 void UV_OT_from_view(wmOperatorType *ot)
1341 {
1342         /* identifiers */
1343         ot->name= "Project From View";
1344         ot->idname= "UV_OT_project_from_view";
1345         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1346         
1347         /* api callbacks */
1348         ot->exec= uv_from_view_exec;
1349         ot->poll= uv_from_view_poll;
1350
1351         /* properties */
1352         RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", "Use orthographic projection");
1353         uv_map_clip_correct_properties(ot);
1354 }
1355
1356 /********************** Reset operator ********************/
1357
1358 static int reset_exec(bContext *C, wmOperator *UNUSED(op))
1359 {
1360         Scene *scene= CTX_data_scene(C);
1361         Object *obedit= CTX_data_edit_object(C);
1362         Mesh *me = (Mesh*)obedit->data;
1363
1364         /* add uvs if they don't exist yet */
1365         if (!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1366                 return OPERATOR_CANCELLED;
1367         }
1368
1369         if (!ED_mesh_uv_loop_reset(C, me)) {
1370                 return OPERATOR_CANCELLED;
1371         }
1372
1373         DAG_id_tag_update(obedit->data, 0);
1374         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1375         
1376         return OPERATOR_FINISHED;
1377 }
1378
1379 void UV_OT_reset(wmOperatorType *ot)
1380 {
1381         /* identifiers */
1382         ot->name= "Reset";
1383         ot->idname= "UV_OT_reset";
1384         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1385         
1386         /* api callbacks */
1387         ot->exec= reset_exec;
1388         ot->poll= ED_operator_uvmap;
1389 }
1390
1391 /****************** Sphere Project operator ***************/
1392
1393 static void uv_sphere_project(float target[2], float source[3], float center[3], float rotmat[4][4])
1394 {
1395         float pv[3];
1396
1397         sub_v3_v3v3(pv, source, center);
1398         mul_m4_v3(rotmat, pv);
1399
1400         map_to_sphere( &target[0], &target[1],pv[0], pv[1], pv[2]);
1401
1402         /* split line is always zero */
1403         if(target[0] >= 1.0f)
1404                 target[0] -= 1.0f;  
1405 }
1406
1407 static void uv_map_mirror(BMEditMesh *em, BMFace *efa, MTexPoly *UNUSED(tf))
1408 {
1409         BMLoop *l;
1410         BMIter liter;
1411         MLoopUV *luv;
1412         BLI_array_declare(uvs);
1413         float **uvs = NULL;
1414         float dx;
1415         int i, mi;
1416
1417         i = 0;
1418         BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1419                 luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1420                 BLI_array_growone(uvs);
1421
1422                 uvs[i] = luv->uv;
1423                 i++;
1424         }
1425
1426         mi = 0;
1427         for(i=1; i<efa->len; i++)
1428                 if(uvs[i][0] > uvs[mi][0])
1429                         mi = i;
1430
1431         for(i=0; i<efa->len; i++) {
1432                 if(i != mi) {
1433                         dx = uvs[mi][0] - uvs[i][0];
1434                         if(dx > 0.5f) uvs[i][0] += 1.0f;
1435                 } 
1436         } 
1437
1438         BLI_array_free(uvs);
1439 }
1440
1441 static int sphere_project_exec(bContext *C, wmOperator *op)
1442 {
1443         Scene *scene= CTX_data_scene(C);
1444         Object *obedit= CTX_data_edit_object(C);
1445         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1446         BMFace *efa;
1447         BMLoop *l;
1448         BMIter iter, liter;
1449         MTexPoly *tf;
1450         MLoopUV *luv;
1451         float center[3], rotmat[4][4];
1452
1453         /* add uvs if they don't exist yet */
1454         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1455                 return OPERATOR_CANCELLED;
1456         }
1457
1458         uv_map_transform(C, op, center, rotmat);
1459
1460         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1461                 if (!BM_TestHFlag(efa, BM_SELECT))
1462                         continue;
1463
1464                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1465                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1466
1467                         uv_sphere_project(luv->uv, l->v->co, center, rotmat);
1468                 }
1469
1470                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1471                 uv_map_mirror(em, efa, tf);
1472         }
1473
1474         uv_map_clip_correct(em, op);
1475
1476         DAG_id_tag_update(obedit->data, 0);
1477         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1478
1479         return OPERATOR_FINISHED;
1480 }
1481
1482 void UV_OT_sphere_project(wmOperatorType *ot)
1483 {
1484         /* identifiers */
1485         ot->name= "Sphere Projection";
1486         ot->idname= "UV_OT_sphere_project";
1487         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1488         
1489         /* api callbacks */
1490         ot->exec= sphere_project_exec;
1491         ot->poll= ED_operator_uvmap;
1492
1493         /* properties */
1494         uv_transform_properties(ot, 0);
1495         uv_map_clip_correct_properties(ot);
1496 }
1497
1498 /***************** Cylinder Project operator **************/
1499
1500 static void uv_cylinder_project(float target[2], float source[3], float center[3], float rotmat[4][4])
1501 {
1502         float pv[3];
1503
1504         sub_v3_v3v3(pv, source, center);
1505         mul_m4_v3(rotmat, pv);
1506
1507         map_to_tube( &target[0], &target[1],pv[0], pv[1], pv[2]);
1508
1509         /* split line is always zero */
1510         if(target[0] >= 1.0f)
1511                 target[0] -= 1.0f;  
1512 }
1513
1514 static int cylinder_project_exec(bContext *C, wmOperator *op)
1515 {
1516         Scene *scene= CTX_data_scene(C);
1517         Object *obedit= CTX_data_edit_object(C);
1518         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1519         BMFace *efa;
1520         BMLoop *l;
1521         BMIter iter, liter;
1522         MTexPoly *tf;
1523         MLoopUV *luv;
1524         float center[3], rotmat[4][4];
1525
1526         /* add uvs if they don't exist yet */
1527         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1528                 return OPERATOR_CANCELLED;
1529         }
1530
1531         uv_map_transform(C, op, center, rotmat);
1532
1533         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1534                 tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
1535                 if (!BM_TestHFlag(efa, BM_SELECT))
1536                         continue;
1537                 
1538                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1539                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1540
1541                         uv_cylinder_project(luv->uv, l->v->co, center, rotmat);
1542                 }
1543
1544                 uv_map_mirror(em, efa, tf);
1545         }
1546
1547         uv_map_clip_correct(em, op);
1548
1549         DAG_id_tag_update(obedit->data, 0);
1550         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1551
1552         return OPERATOR_FINISHED;
1553 }
1554
1555 void UV_OT_cylinder_project(wmOperatorType *ot)
1556 {
1557         /* identifiers */
1558         ot->name= "Cylinder Projection";
1559         ot->idname= "UV_OT_cylinder_project";
1560         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1561         
1562         /* api callbacks */
1563         ot->exec= cylinder_project_exec;
1564         ot->poll= ED_operator_uvmap;
1565
1566         /* properties */
1567         uv_transform_properties(ot, 1);
1568         uv_map_clip_correct_properties(ot);
1569 }
1570
1571 /******************* Cube Project operator ****************/
1572
1573 static int cube_project_exec(bContext *C, wmOperator *op)
1574 {
1575         Scene *scene= CTX_data_scene(C);
1576         Object *obedit= CTX_data_edit_object(C);
1577         BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
1578         BMFace *efa;
1579         BMLoop *l;
1580         BMIter iter, liter;
1581         /* MTexPoly *tf; */ /* UNUSED */
1582         MLoopUV *luv;
1583         float cube_size, *loc, dx, dy;
1584         int cox, coy;
1585
1586         /* add uvs if they don't exist yet */
1587         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
1588                 return OPERATOR_CANCELLED;
1589         }
1590
1591         loc= obedit->obmat[3];
1592         cube_size= RNA_float_get(op->ptr, "cube_size");
1593
1594         /* choose x,y,z axis for projection depending on the largest normal
1595          * component, but clusters all together around the center of map. */
1596
1597         BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
1598                 int first=1;
1599
1600                 /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
1601                 if (!BM_TestHFlag(efa, BM_SELECT))
1602                         continue;
1603
1604                 axis_dominant_v3(&cox, &coy, efa->no);
1605
1606                 dx = dy = 0;
1607                 BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
1608                         luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
1609
1610                         luv->uv[0] = 0.5f+0.5f*cube_size*(loc[cox] + l->v->co[cox]);
1611                         luv->uv[1] = 0.5f+0.5f*cube_size*(loc[coy] + l->v->co[coy]);
1612                         
1613                         if (first) {
1614                                 dx = floor(luv->uv[0]);
1615                                 dy = floor(luv->uv[1]);
1616                                 first = 0;
1617                         }
1618                         
1619
1620                         luv->uv[0] -= dx;
1621                         luv->uv[1] -= dy;
1622                 }
1623         }
1624
1625         uv_map_clip_correct(em, op);
1626
1627         DAG_id_tag_update(obedit->data, 0);
1628         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1629
1630         return OPERATOR_FINISHED;
1631 }
1632
1633 void UV_OT_cube_project(wmOperatorType *ot)
1634 {
1635         /* identifiers */
1636         ot->name= "Cube Projection";
1637         ot->idname= "UV_OT_cube_project";
1638         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1639         
1640         /* api callbacks */
1641         ot->exec= cube_project_exec;
1642         ot->poll= ED_operator_uvmap;
1643
1644         /* properties */
1645         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);
1646         uv_map_clip_correct_properties(ot);
1647 }