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