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