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