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