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