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