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