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