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