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