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