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