Blender  V2.59
uvedit_unwrap_ops.c
Go to the documentation of this file.
00001 /*
00002  * $Id: uvedit_unwrap_ops.c 37670 2011-06-20 17:28:25Z blendix $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include <string.h>
00036 #include <stdlib.h>
00037 #include <math.h>
00038 
00039 #include "MEM_guardedalloc.h"
00040 
00041 #include "DNA_camera_types.h"
00042 #include "DNA_meshdata_types.h"
00043 #include "DNA_object_types.h"
00044 #include "DNA_scene_types.h"
00045 
00046 #include "BLI_math.h"
00047 #include "BLI_edgehash.h"
00048 #include "BLI_editVert.h"
00049 #include "BLI_uvproject.h"
00050 #include "BLI_utildefines.h"
00051 
00052 #include "BKE_context.h"
00053 #include "BKE_customdata.h"
00054 #include "BKE_depsgraph.h"
00055 #include "BKE_image.h"
00056 #include "BKE_mesh.h"
00057 
00058 #include "PIL_time.h"
00059 
00060 #include "ED_image.h"
00061 #include "ED_mesh.h"
00062 #include "ED_screen.h"
00063 #include "ED_uvedit.h"
00064 #include "ED_view3d.h"
00065 
00066 #include "RNA_access.h"
00067 #include "RNA_define.h"
00068 
00069 
00070 #include "WM_api.h"
00071 #include "WM_types.h"
00072 
00073 #include "uvedit_intern.h"
00074 #include "uvedit_parametrizer.h"
00075 
00076 static int ED_uvedit_ensure_uvs(bContext *C, Scene *scene, Object *obedit)
00077 {
00078         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00079         EditFace *efa;
00080         MTFace *tf;
00081         Image *ima;
00082         bScreen *sc;
00083         ScrArea *sa;
00084         SpaceLink *slink;
00085         SpaceImage *sima;
00086 
00087         if(ED_uvedit_test(obedit)) {
00088                 BKE_mesh_end_editmesh(obedit->data, em);
00089                 return 1;
00090         }
00091 
00092         if(em && em->faces.first)
00093                 EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL);
00094         
00095         if(!ED_uvedit_test(obedit)) {
00096                 BKE_mesh_end_editmesh(obedit->data, em);
00097                 return 0;
00098         }
00099 
00100         ima= CTX_data_edit_image(C);
00101 
00102         if(!ima) {
00103                 /* no image in context in the 3d view, we find first image window .. */
00104                 sc= CTX_wm_screen(C);
00105 
00106                 for(sa=sc->areabase.first; sa; sa=sa->next) {
00107                         slink= sa->spacedata.first;
00108                         if(slink->spacetype == SPACE_IMAGE) {
00109                                 sima= (SpaceImage*)slink;
00110 
00111                                 ima= sima->image;
00112                                 if(ima) {
00113                                         if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
00114                                                 ima= NULL;
00115                                         else
00116                                                 break;
00117                                 }
00118                         }
00119                 }
00120         }
00121         
00122         if(ima)
00123                 ED_uvedit_assign_image(scene, obedit, ima, NULL);
00124         
00125         /* select new UV's */
00126         for(efa=em->faces.first; efa; efa=efa->next) {
00127                 tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00128                 uvedit_face_select(scene, efa, tf);
00129         }
00130 
00131         BKE_mesh_end_editmesh(obedit->data, em);
00132         return 1;
00133 }
00134 
00135 /****************** Parametrizer Conversion ***************/
00136 
00137 static int uvedit_have_selection(Scene *scene, EditMesh *em, short implicit)
00138 {
00139         EditFace *efa;
00140         MTFace *tf;
00141 
00142         /* verify if we have any selected uv's before unwrapping,
00143            so we can cancel the operator early */
00144         for(efa= em->faces.first; efa; efa= efa->next) {
00145                 if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
00146                         if(efa->h)
00147                                 continue;
00148                 }
00149                 else if((efa->h) || ((efa->f & SELECT)==0))
00150                         continue;
00151 
00152                 tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00153 
00154                 if(!tf)
00155                         return 1; /* default selected if doesn't exists */
00156                 
00157                 if(implicit &&
00158                         !(      uvedit_uv_selected(scene, efa, tf, 0) ||
00159                                 uvedit_uv_selected(scene, efa, tf, 1) ||
00160                                 uvedit_uv_selected(scene, efa, tf, 2) ||
00161                                 (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) )
00162                 ) {
00163                         continue;
00164                 }
00165 
00166                 return 1;
00167         }
00168 
00169         return 0;
00170 }
00171 
00172 static ParamHandle *construct_param_handle(Scene *scene, EditMesh *em, short implicit, short fill, short sel, short correct_aspect)
00173 {
00174         ParamHandle *handle;
00175         EditFace *efa;
00176         EditEdge *eed;
00177         EditVert *ev;
00178         MTFace *tf;
00179         int a;
00180         
00181         handle = param_construct_begin();
00182 
00183         if(correct_aspect) {
00184                 efa = EM_get_actFace(em, 1);
00185 
00186                 if(efa) {
00187                         float aspx, aspy;
00188                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00189 
00190                         ED_image_uv_aspect(tf->tpage, &aspx, &aspy);
00191                 
00192                         if(aspx!=aspy)
00193                                 param_aspect_ratio(handle, aspx, aspy);
00194                 }
00195         }
00196         
00197         /* we need the vert indices */
00198         for(ev= em->verts.first, a=0; ev; ev= ev->next, a++)
00199                 ev->tmp.l = a;
00200         
00201         for(efa= em->faces.first; efa; efa= efa->next) {
00202                 ParamKey key, vkeys[4];
00203                 ParamBool pin[4], select[4];
00204                 float *co[4];
00205                 float *uv[4];
00206                 int nverts;
00207                 
00208                 if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
00209                         if(efa->h)
00210                                 continue;
00211                 }
00212                 else if((efa->h) || (sel && (efa->f & SELECT)==0))
00213                         continue;
00214 
00215                 tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00216                 
00217                 if(implicit &&
00218                         !(      uvedit_uv_selected(scene, efa, tf, 0) ||
00219                                 uvedit_uv_selected(scene, efa, tf, 1) ||
00220                                 uvedit_uv_selected(scene, efa, tf, 2) ||
00221                                 (efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) )
00222                 ) {
00223                         continue;
00224                 }
00225 
00226                 key = (ParamKey)efa;
00227                 vkeys[0] = (ParamKey)efa->v1->tmp.l;
00228                 vkeys[1] = (ParamKey)efa->v2->tmp.l;
00229                 vkeys[2] = (ParamKey)efa->v3->tmp.l;
00230 
00231                 co[0] = efa->v1->co;
00232                 co[1] = efa->v2->co;
00233                 co[2] = efa->v3->co;
00234 
00235                 uv[0] = tf->uv[0];
00236                 uv[1] = tf->uv[1];
00237                 uv[2] = tf->uv[2];
00238 
00239                 pin[0] = ((tf->unwrap & TF_PIN1) != 0);
00240                 pin[1] = ((tf->unwrap & TF_PIN2) != 0);
00241                 pin[2] = ((tf->unwrap & TF_PIN3) != 0);
00242 
00243                 select[0] = ((uvedit_uv_selected(scene, efa, tf, 0)) != 0);
00244                 select[1] = ((uvedit_uv_selected(scene, efa, tf, 1)) != 0);
00245                 select[2] = ((uvedit_uv_selected(scene, efa, tf, 2)) != 0);
00246 
00247                 if(efa->v4) {
00248                         vkeys[3] = (ParamKey)efa->v4->tmp.l;
00249                         co[3] = efa->v4->co;
00250                         uv[3] = tf->uv[3];
00251                         pin[3] = ((tf->unwrap & TF_PIN4) != 0);
00252                         select[3] = (uvedit_uv_selected(scene, efa, tf, 3) != 0);
00253                         nverts = 4;
00254                 }
00255                 else
00256                         nverts = 3;
00257 
00258                 param_face_add(handle, key, nverts, vkeys, co, uv, pin, select);
00259         }
00260 
00261         if(!implicit) {
00262                 for(eed= em->edges.first; eed; eed= eed->next) {
00263                         if(eed->seam) {
00264                                 ParamKey vkeys[2];
00265                                 vkeys[0] = (ParamKey)eed->v1->tmp.l;
00266                                 vkeys[1] = (ParamKey)eed->v2->tmp.l;
00267                                 param_edge_set_seam(handle, vkeys);
00268                         }
00269                 }
00270         }
00271 
00272         param_construct_end(handle, fill, implicit);
00273 
00274         return handle;
00275 }
00276 
00277 /* ******************** Minimize Stretch operator **************** */
00278 
00279 typedef struct MinStretch {
00280         Scene *scene;
00281         Object *obedit;
00282         EditMesh *em;
00283         ParamHandle *handle;
00284         float blend;
00285         double lasttime;
00286         int i, iterations;
00287         wmTimer *timer;
00288 } MinStretch;
00289 
00290 static int minimize_stretch_init(bContext *C, wmOperator *op)
00291 {
00292         Scene *scene= CTX_data_scene(C);
00293         Object *obedit= CTX_data_edit_object(C);
00294         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00295         MinStretch *ms;
00296         int fill_holes= RNA_boolean_get(op->ptr, "fill_holes");
00297         short implicit= 1;
00298 
00299         if(!uvedit_have_selection(scene, em, implicit)) {
00300                 BKE_mesh_end_editmesh(obedit->data, em);
00301                 return 0;
00302         }
00303 
00304         ms= MEM_callocN(sizeof(MinStretch), "MinStretch");
00305         ms->scene= scene;
00306         ms->obedit= obedit;
00307         ms->em= em;
00308         ms->blend= RNA_float_get(op->ptr, "blend");
00309         ms->iterations= RNA_int_get(op->ptr, "iterations");
00310         ms->i= 0;
00311         ms->handle= construct_param_handle(scene, em, implicit, fill_holes, 1, 1);
00312         ms->lasttime= PIL_check_seconds_timer();
00313 
00314         param_stretch_begin(ms->handle);
00315         if(ms->blend != 0.0f)
00316                 param_stretch_blend(ms->handle, ms->blend);
00317 
00318         op->customdata= ms;
00319 
00320         return 1;
00321 }
00322 
00323 static void minimize_stretch_iteration(bContext *C, wmOperator *op, int interactive)
00324 {
00325         MinStretch *ms= op->customdata;
00326         ScrArea *sa= CTX_wm_area(C);
00327 
00328         param_stretch_blend(ms->handle, ms->blend);
00329         param_stretch_iter(ms->handle);
00330 
00331         ms->i++;
00332         RNA_int_set(op->ptr, "iterations", ms->i);
00333 
00334         if(interactive && (PIL_check_seconds_timer() - ms->lasttime > 0.5)) {
00335                 char str[100];
00336 
00337                 param_flush(ms->handle);
00338 
00339                 if(sa) {
00340                         sprintf(str, "Minimize Stretch. Blend %.2f.", ms->blend);
00341                         ED_area_headerprint(sa, str);
00342                 }
00343 
00344                 ms->lasttime = PIL_check_seconds_timer();
00345 
00346                 DAG_id_tag_update(ms->obedit->data, 0);
00347                 WM_event_add_notifier(C, NC_GEOM|ND_DATA, ms->obedit->data);
00348         }
00349 }
00350 
00351 static void minimize_stretch_exit(bContext *C, wmOperator *op, int cancel)
00352 {
00353         MinStretch *ms= op->customdata;
00354         ScrArea *sa= CTX_wm_area(C);
00355 
00356         if(sa)
00357                 ED_area_headerprint(sa, NULL);
00358         if(ms->timer)
00359                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ms->timer);
00360 
00361         if(cancel)
00362                 param_flush_restore(ms->handle);
00363         else
00364                 param_flush(ms->handle);
00365 
00366         param_stretch_end(ms->handle);
00367         param_delete(ms->handle);
00368 
00369         DAG_id_tag_update(ms->obedit->data, 0);
00370         WM_event_add_notifier(C, NC_GEOM|ND_DATA, ms->obedit->data);
00371 
00372         MEM_freeN(ms);
00373         op->customdata= NULL;
00374 }
00375 
00376 static int minimize_stretch_exec(bContext *C, wmOperator *op)
00377 {
00378         int i, iterations;
00379 
00380         if(!minimize_stretch_init(C, op))
00381                 return OPERATOR_CANCELLED;
00382 
00383         iterations= RNA_int_get(op->ptr, "iterations");
00384         for(i=0; i<iterations; i++)
00385                 minimize_stretch_iteration(C, op, 0);
00386         minimize_stretch_exit(C, op, 0);
00387 
00388         return OPERATOR_FINISHED;
00389 }
00390 
00391 static int minimize_stretch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
00392 {
00393         MinStretch *ms;
00394 
00395         if(!minimize_stretch_init(C, op))
00396                 return OPERATOR_CANCELLED;
00397 
00398         minimize_stretch_iteration(C, op, 1);
00399 
00400         ms= op->customdata;
00401         WM_event_add_modal_handler(C, op);
00402         ms->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
00403 
00404         return OPERATOR_RUNNING_MODAL;
00405 }
00406 
00407 static int minimize_stretch_modal(bContext *C, wmOperator *op, wmEvent *event)
00408 {
00409         MinStretch *ms= op->customdata;
00410 
00411         switch(event->type) {
00412                 case ESCKEY:
00413                 case RIGHTMOUSE:
00414                         minimize_stretch_exit(C, op, 1);
00415                         return OPERATOR_CANCELLED;
00416                 case RETKEY:
00417                 case PADENTER:
00418                 case LEFTMOUSE:
00419                         minimize_stretch_exit(C, op, 0);
00420                         return OPERATOR_FINISHED;
00421                 case PADPLUSKEY:
00422                 case WHEELUPMOUSE:
00423                         if(ms->blend < 0.95f) {
00424                                 ms->blend += 0.1f;
00425                                 ms->lasttime= 0.0f;
00426                                 RNA_float_set(op->ptr, "blend", ms->blend);
00427                                 minimize_stretch_iteration(C, op, 1);
00428                         }
00429                         break;
00430                 case PADMINUS:
00431                 case WHEELDOWNMOUSE:
00432                         if(ms->blend > 0.05f) {
00433                                 ms->blend -= 0.1f;
00434                                 ms->lasttime= 0.0f;
00435                                 RNA_float_set(op->ptr, "blend", ms->blend);
00436                                 minimize_stretch_iteration(C, op, 1);
00437                         }
00438                         break;
00439                 case TIMER:
00440                         if(ms->timer == event->customdata) {
00441                                 double start= PIL_check_seconds_timer();
00442 
00443                                 do {
00444                                         minimize_stretch_iteration(C, op, 1);
00445                                 } while(PIL_check_seconds_timer() - start < 0.01);
00446                         }
00447                         break;
00448         }
00449 
00450         if(ms->iterations && ms->i >= ms->iterations) {
00451                 minimize_stretch_exit(C, op, 0);
00452                 return OPERATOR_FINISHED;
00453         }
00454 
00455         return OPERATOR_RUNNING_MODAL;
00456 }
00457 
00458 static int minimize_stretch_cancel(bContext *C, wmOperator *op)
00459 {
00460         minimize_stretch_exit(C, op, 1);
00461 
00462         return OPERATOR_CANCELLED;
00463 }
00464 
00465 void UV_OT_minimize_stretch(wmOperatorType *ot)
00466 {
00467         /* identifiers */
00468         ot->name= "Minimize Stretch";
00469         ot->idname= "UV_OT_minimize_stretch";
00470         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00471         ot->description="Reduce UV stretching by relaxing angles";
00472         
00473         /* api callbacks */
00474         ot->exec= minimize_stretch_exec;
00475         ot->invoke= minimize_stretch_invoke;
00476         ot->modal= minimize_stretch_modal;
00477         ot->cancel= minimize_stretch_cancel;
00478         ot->poll= ED_operator_uvedit;
00479 
00480         /* properties */
00481         RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry.");
00482         RNA_def_float_factor(ot->srna, "blend", 0.0f, 0.0f, 1.0f, "Blend", "Blend factor between stretch minimized and original.", 0.0f, 1.0f);
00483         RNA_def_int(ot->srna, "iterations", 0, 0, INT_MAX, "Iterations", "Number of iterations to run, 0 is unlimited when run interactively.", 0, 100);
00484 }
00485 
00486 /* ******************** Pack Islands operator **************** */
00487 
00488 static int pack_islands_exec(bContext *C, wmOperator *op)
00489 {
00490         Scene *scene= CTX_data_scene(C);
00491         Object *obedit= CTX_data_edit_object(C);
00492         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00493         ParamHandle *handle;
00494         short implicit= 1;
00495 
00496         if(!uvedit_have_selection(scene, em, implicit)) {
00497                 BKE_mesh_end_editmesh(obedit->data, em);
00498                 return OPERATOR_CANCELLED;
00499         }
00500 
00501         if(RNA_property_is_set(op->ptr, "margin")) {
00502                 scene->toolsettings->uvcalc_margin= RNA_float_get(op->ptr, "margin");
00503         }
00504         else {
00505                 RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin);
00506         }
00507 
00508         handle = construct_param_handle(scene, em, implicit, 0, 1, 1);
00509         param_pack(handle, scene->toolsettings->uvcalc_margin);
00510         param_flush(handle);
00511         param_delete(handle);
00512         
00513         DAG_id_tag_update(obedit->data, 0);
00514         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
00515 
00516         BKE_mesh_end_editmesh(obedit->data, em);
00517         return OPERATOR_FINISHED;
00518 }
00519 
00520 void UV_OT_pack_islands(wmOperatorType *ot)
00521 {
00522         /* identifiers */
00523         ot->name= "Pack Islands";
00524         ot->idname= "UV_OT_pack_islands";
00525         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00526         
00527         /* api callbacks */
00528         ot->exec= pack_islands_exec;
00529         ot->poll= ED_operator_uvedit;
00530 
00531         /* properties */
00532         RNA_def_float_factor(ot->srna, "margin", 0.0f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f);
00533 }
00534 
00535 /* ******************** Average Islands Scale operator **************** */
00536 
00537 static int average_islands_scale_exec(bContext *C, wmOperator *UNUSED(op))
00538 {
00539         Scene *scene= CTX_data_scene(C);
00540         Object *obedit= CTX_data_edit_object(C);
00541         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00542         ParamHandle *handle;
00543         short implicit= 1;
00544 
00545         if(!uvedit_have_selection(scene, em, implicit)) {
00546                 BKE_mesh_end_editmesh(obedit->data, em);
00547                 return OPERATOR_CANCELLED;
00548         }
00549 
00550         handle= construct_param_handle(scene, em, implicit, 0, 1, 1);
00551         param_average(handle);
00552         param_flush(handle);
00553         param_delete(handle);
00554         
00555         DAG_id_tag_update(obedit->data, 0);
00556         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
00557 
00558         BKE_mesh_end_editmesh(obedit->data, em);
00559         return OPERATOR_FINISHED;
00560 }
00561 
00562 void UV_OT_average_islands_scale(wmOperatorType *ot)
00563 {
00564         /* identifiers */
00565         ot->name= "Average Islands Scale";
00566         ot->idname= "UV_OT_average_islands_scale";
00567         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00568         
00569         /* api callbacks */
00570         ot->exec= average_islands_scale_exec;
00571         ot->poll= ED_operator_uvedit;
00572 }
00573 
00574 /**************** Live Unwrap *****************/
00575 
00576 static ParamHandle *liveHandle = NULL;
00577 
00578 void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
00579 {
00580         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00581         short abf = scene->toolsettings->unwrapper == 0;
00582         short fillholes = scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
00583 
00584         if(!ED_uvedit_test(obedit)) {
00585                 BKE_mesh_end_editmesh(obedit->data, em);
00586                 return;
00587         }
00588 
00589         liveHandle = construct_param_handle(scene, em, 0, fillholes, 1, 1);
00590 
00591         param_lscm_begin(liveHandle, PARAM_TRUE, abf);
00592         BKE_mesh_end_editmesh(obedit->data, em);
00593 }
00594 
00595 void ED_uvedit_live_unwrap_re_solve(void)
00596 {
00597         if(liveHandle) {
00598                 param_lscm_solve(liveHandle);
00599                 param_flush(liveHandle);
00600         }
00601 }
00602         
00603 void ED_uvedit_live_unwrap_end(short cancel)
00604 {
00605         if(liveHandle) {
00606                 param_lscm_end(liveHandle);
00607                 if(cancel)
00608                         param_flush_restore(liveHandle);
00609                 param_delete(liveHandle);
00610                 liveHandle = NULL;
00611         }
00612 }
00613 
00614 /*************** UV Map Common Transforms *****************/
00615 
00616 #define VIEW_ON_EQUATOR 0
00617 #define VIEW_ON_POLES   1
00618 #define ALIGN_TO_OBJECT 2
00619 
00620 #define POLAR_ZX        0
00621 #define POLAR_ZY        1
00622 
00623 static void uv_map_transform_center(Scene *scene, View3D *v3d, float *result, Object *ob, EditMesh *em)
00624 {
00625         EditFace *efa;
00626         float min[3], max[3], *cursx;
00627         int around= (v3d)? v3d->around: V3D_CENTER;
00628 
00629         /* only operates on the edit object - this is all that's needed now */
00630 
00631         switch(around)  {
00632                 case V3D_CENTER: /* bounding box center */
00633                         min[0]= min[1]= min[2]= 1e20f;
00634                         max[0]= max[1]= max[2]= -1e20f; 
00635 
00636                         for(efa= em->faces.first; efa; efa= efa->next) {
00637                                 if(efa->f & SELECT) {
00638                                         DO_MINMAX(efa->v1->co, min, max);
00639                                         DO_MINMAX(efa->v2->co, min, max);
00640                                         DO_MINMAX(efa->v3->co, min, max);
00641                                         if(efa->v4) DO_MINMAX(efa->v4->co, min, max);
00642                                 }
00643                         }
00644                         mid_v3_v3v3(result, min, max);
00645                         break;
00646 
00647                 case V3D_CURSOR: /*cursor center*/ 
00648                         cursx= give_cursor(scene, v3d);
00649                         /* shift to objects world */
00650                         result[0]= cursx[0]-ob->obmat[3][0];
00651                         result[1]= cursx[1]-ob->obmat[3][1];
00652                         result[2]= cursx[2]-ob->obmat[3][2];
00653                         break;
00654 
00655                 case V3D_LOCAL: /*object center*/
00656                 case V3D_CENTROID: /* multiple objects centers, only one object here*/
00657                 default:
00658                         result[0]= result[1]= result[2]= 0.0;
00659                         break;
00660         }
00661 }
00662 
00663 static void uv_map_rotation_matrix(float result[][4], RegionView3D *rv3d, Object *ob, float upangledeg, float sideangledeg, float radius)
00664 {
00665         float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
00666         float sideangle= 0.0f, upangle= 0.0f;
00667         int k;
00668 
00669         /* get rotation of the current view matrix */
00670         if(rv3d)
00671                 copy_m4_m4(viewmatrix, rv3d->viewmat);
00672         else
00673                 unit_m4(viewmatrix);
00674 
00675         /* but shifting */
00676         for(k=0; k<4; k++)
00677                 viewmatrix[3][k] =0.0f;
00678 
00679         /* get rotation of the current object matrix */
00680         copy_m4_m4(rotobj,ob->obmat);
00681 
00682         /* but shifting */
00683         for(k=0; k<4; k++)
00684                 rotobj[3][k] =0.0f;
00685 
00686         zero_m4(rotup);
00687         zero_m4(rotside);
00688 
00689         /* compensate front/side.. against opengl x,y,z world definition */
00690         /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */
00691         /* i wanted to keep the reason here, so we're rotating*/
00692         sideangle= (float)M_PI*(sideangledeg + 180.0f)/180.0f;
00693         rotside[0][0]= (float)cos(sideangle);
00694         rotside[0][1]= -(float)sin(sideangle);
00695         rotside[1][0]= (float)sin(sideangle);
00696         rotside[1][1]= (float)cos(sideangle);
00697         rotside[2][2]= 1.0f;
00698 
00699         upangle= (float)M_PI*upangledeg/180.0f;
00700         rotup[1][1]= (float)cos(upangle)/radius;
00701         rotup[1][2]= -(float)sin(upangle)/radius;
00702         rotup[2][1]= (float)sin(upangle)/radius;
00703         rotup[2][2]= (float)cos(upangle)/radius;
00704         rotup[0][0]= (float)1.0f/radius;
00705 
00706         /* calculate transforms*/
00707         mul_serie_m4(result, rotup, rotside, viewmatrix, rotobj, NULL, NULL, NULL, NULL);
00708 }
00709 
00710 static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float rotmat[4][4])
00711 {
00712         /* context checks are messy here, making it work in both 3d view and uv editor */
00713         Scene *scene= CTX_data_scene(C);
00714         Object *obedit= CTX_data_edit_object(C);
00715         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00716         View3D *v3d= CTX_wm_view3d(C);
00717         RegionView3D *rv3d= CTX_wm_region_view3d(C);
00718         /* common operator properties */
00719         int align= RNA_enum_get(op->ptr, "align");
00720         int direction= RNA_enum_get(op->ptr, "direction");
00721         float radius= RNA_struct_find_property(op->ptr, "radius")? RNA_float_get(op->ptr, "radius"): 1.0f;
00722         float upangledeg, sideangledeg;
00723 
00724         uv_map_transform_center(scene, v3d, center, obedit, em);
00725 
00726         if(direction == VIEW_ON_EQUATOR) {
00727                 upangledeg= 90.0f;
00728                 sideangledeg= 0.0f;
00729         }
00730         else {
00731                 upangledeg= 0.0f;
00732                 if(align == POLAR_ZY) sideangledeg= 0.0f;
00733                 else sideangledeg= 90.0f;
00734         }
00735 
00736         /* be compatible to the "old" sphere/cylinder mode */
00737         if(direction == ALIGN_TO_OBJECT)
00738                 unit_m4(rotmat);
00739         else 
00740                 uv_map_rotation_matrix(rotmat, rv3d, obedit, upangledeg, sideangledeg, radius);
00741 
00742         BKE_mesh_end_editmesh(obedit->data, em);
00743 }
00744 
00745 static void uv_transform_properties(wmOperatorType *ot, int radius)
00746 {
00747         static EnumPropertyItem direction_items[]= {
00748                 {VIEW_ON_EQUATOR, "VIEW_ON_EQUATOR", 0, "View on Equator", "3D view is on the equator"},
00749                 {VIEW_ON_POLES, "VIEW_ON_POLES", 0, "View on Poles", "3D view is on the poles"},
00750                 {ALIGN_TO_OBJECT, "ALIGN_TO_OBJECT", 0, "Align to Object", "Align according to object transform"},
00751                 {0, NULL, 0, NULL, NULL}
00752         };
00753         static EnumPropertyItem align_items[]= {
00754                 {POLAR_ZX, "POLAR_ZX", 0, "Polar ZX", "Polar 0 is X"},
00755                 {POLAR_ZY, "POLAR_ZY", 0, "Polar ZY", "Polar 0 is Y"},
00756                 {0, NULL, 0, NULL, NULL}
00757         };
00758 
00759         RNA_def_enum(ot->srna, "direction", direction_items, VIEW_ON_EQUATOR, "Direction", "Direction of the sphere or cylinder.");
00760         RNA_def_enum(ot->srna, "align", align_items, VIEW_ON_EQUATOR, "Align", "How to determine rotation around the pole.");
00761         if(radius)
00762                 RNA_def_float(ot->srna, "radius", 1.0f, 0.0f, FLT_MAX, "Radius", "Radius of the sphere or cylinder.", 0.0001f, 100.0f);
00763 }
00764 
00765 static void correct_uv_aspect(EditMesh *em)
00766 {
00767         EditFace *efa= EM_get_actFace(em, 1);
00768         MTFace *tf;
00769         float scale, aspx= 1.0f, aspy=1.0f;
00770         
00771         if(efa) {
00772                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00773                 ED_image_uv_aspect(tf->tpage, &aspx, &aspy);
00774         }
00775         
00776         if(aspx == aspy)
00777                 return;
00778                 
00779         if(aspx > aspy) {
00780                 scale= aspy/aspx;
00781 
00782                 for(efa= em->faces.first; efa; efa= efa->next) {
00783                         if(efa->f & SELECT) {
00784                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00785 
00786                                 tf->uv[0][0]= ((tf->uv[0][0]-0.5f)*scale)+0.5f;
00787                                 tf->uv[1][0]= ((tf->uv[1][0]-0.5f)*scale)+0.5f;
00788                                 tf->uv[2][0]= ((tf->uv[2][0]-0.5f)*scale)+0.5f;
00789                                 if(efa->v4)
00790                                         tf->uv[3][0]= ((tf->uv[3][0]-0.5f)*scale)+0.5f;
00791                         }
00792                 }
00793         }
00794         else {
00795                 scale= aspx/aspy;
00796 
00797                 for(efa= em->faces.first; efa; efa= efa->next) {
00798                         if(efa->f & SELECT) {
00799                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00800 
00801                                 tf->uv[0][1]= ((tf->uv[0][1]-0.5f)*scale)+0.5f;
00802                                 tf->uv[1][1]= ((tf->uv[1][1]-0.5f)*scale)+0.5f;
00803                                 tf->uv[2][1]= ((tf->uv[2][1]-0.5f)*scale)+0.5f;
00804                                 if(efa->v4)
00805                                         tf->uv[3][1]= ((tf->uv[3][1]-0.5f)*scale)+0.5f;
00806                         }
00807                 }
00808         }
00809 }
00810 
00811 /******************** Map Clip & Correct ******************/
00812 
00813 static void uv_map_clip_correct_properties(wmOperatorType *ot)
00814 {
00815         RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", "Map UV's taking image aspect ratio into account.");
00816         RNA_def_boolean(ot->srna, "clip_to_bounds", 0, "Clip to Bounds", "Clip UV coordinates to bounds after unwrapping.");
00817         RNA_def_boolean(ot->srna, "scale_to_bounds", 0, "Scale to Bounds", "Scale UV coordinates to bounds after unwrapping.");
00818 }
00819 
00820 static void uv_map_clip_correct(EditMesh *em, wmOperator *op)
00821 {
00822         EditFace *efa;
00823         MTFace *tf;
00824         float dx, dy, min[2], max[2];
00825         int b, nverts;
00826         int correct_aspect= RNA_boolean_get(op->ptr, "correct_aspect");
00827         int clip_to_bounds= RNA_boolean_get(op->ptr, "clip_to_bounds");
00828         int scale_to_bounds= RNA_boolean_get(op->ptr, "scale_to_bounds");
00829 
00830         /* correct for image aspect ratio */
00831         if(correct_aspect)
00832                 correct_uv_aspect(em);
00833 
00834         if(scale_to_bounds) {
00835                 INIT_MINMAX2(min, max);
00836                 
00837                 for(efa= em->faces.first; efa; efa= efa->next) {
00838                         if(efa->f & SELECT) {
00839                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00840 
00841                                 DO_MINMAX2(tf->uv[0], min, max);
00842                                 DO_MINMAX2(tf->uv[1], min, max);
00843                                 DO_MINMAX2(tf->uv[2], min, max);
00844 
00845                                 if(efa->v4)
00846                                         DO_MINMAX2(tf->uv[3], min, max);
00847                         }
00848                 }
00849                 
00850                 /* rescale UV to be in 1/1 */
00851                 dx= (max[0]-min[0]);
00852                 dy= (max[1]-min[1]);
00853 
00854                 if(dx > 0.0f)
00855                         dx= 1.0f/dx;
00856                 if(dy > 0.0f)
00857                         dy= 1.0f/dy;
00858 
00859                 for(efa= em->faces.first; efa; efa= efa->next) {
00860                         if(efa->f & SELECT) {
00861                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00862 
00863                                 nverts= (efa->v4)? 4: 3;
00864 
00865                                 for(b=0; b<nverts; b++) {
00866                                         tf->uv[b][0]= (tf->uv[b][0]-min[0])*dx;
00867                                         tf->uv[b][1]= (tf->uv[b][1]-min[1])*dy;
00868                                 }
00869                         }
00870                 }
00871         }
00872         else if(clip_to_bounds) {
00873                 /* clipping and wrapping */
00874                 for(efa= em->faces.first; efa; efa= efa->next) {
00875                         if(efa->f & SELECT) {
00876                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00877                         
00878                                 nverts= (efa->v4)? 4: 3;
00879 
00880                                 for(b=0; b<nverts; b++) {
00881                                         CLAMP(tf->uv[b][0], 0.0f, 1.0f);
00882                                         CLAMP(tf->uv[b][1], 0.0f, 1.0f);
00883                                 }
00884                         }
00885                 }
00886         }
00887 }
00888 
00889 /* ******************** Unwrap operator **************** */
00890 
00891 /* assumes UV layer is checked, doesn't run update funcs */
00892 void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
00893 {
00894         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00895         ParamHandle *handle;
00896 
00897         const short fill_holes= scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
00898         const short correct_aspect= !(scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT);
00899         short implicit= 0;
00900 
00901         handle= construct_param_handle(scene, em, implicit, fill_holes, sel, correct_aspect);
00902 
00903         param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
00904         param_lscm_solve(handle);
00905         param_lscm_end(handle);
00906 
00907         param_pack(handle, scene->toolsettings->uvcalc_margin);
00908 
00909         param_flush(handle);
00910 
00911         param_delete(handle);
00912 
00913         BKE_mesh_end_editmesh(obedit->data, em);
00914 }
00915 
00916 static int unwrap_exec(bContext *C, wmOperator *op)
00917 {
00918         Scene *scene= CTX_data_scene(C);
00919         Object *obedit= CTX_data_edit_object(C);
00920         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00921         int method = RNA_enum_get(op->ptr, "method");
00922         int fill_holes = RNA_boolean_get(op->ptr, "fill_holes");
00923         int correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect");
00924         short implicit= 0;
00925 
00926         if(!uvedit_have_selection(scene, em, implicit)) {
00927                 BKE_mesh_end_editmesh(obedit->data, em);
00928                 return 0;
00929         }
00930 
00931         BKE_mesh_end_editmesh(obedit->data, em);
00932         
00933         /* add uvs if they don't exist yet */
00934         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
00935                 return OPERATOR_CANCELLED;
00936         }
00937 
00938         /* remember last method for live unwrap */
00939         scene->toolsettings->unwrapper = method;
00940 
00941         if(fill_holes)          scene->toolsettings->uvcalc_flag |=  UVCALC_FILLHOLES;
00942         else                            scene->toolsettings->uvcalc_flag &= ~UVCALC_FILLHOLES;
00943 
00944         if(correct_aspect)      scene->toolsettings->uvcalc_flag &= ~UVCALC_NO_ASPECT_CORRECT;
00945         else                            scene->toolsettings->uvcalc_flag |=  UVCALC_NO_ASPECT_CORRECT;
00946 
00947         /* execute unwrap */
00948         ED_unwrap_lscm(scene, obedit, TRUE);
00949 
00950         DAG_id_tag_update(obedit->data, 0);
00951         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
00952 
00953         return OPERATOR_FINISHED;
00954 }
00955 
00956 void UV_OT_unwrap(wmOperatorType *ot)
00957 {
00958         static EnumPropertyItem method_items[] = {
00959                 {0, "ANGLE_BASED", 0, "Angle Based", ""},
00960                 {1, "CONFORMAL", 0, "Conformal", ""},
00961                 {0, NULL, 0, NULL, NULL}};
00962 
00963         /* identifiers */
00964         ot->name= "Unwrap";
00965         ot->description= "Unwrap the mesh of the object being edited";
00966         ot->idname= "UV_OT_unwrap";
00967         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00968         
00969         /* api callbacks */
00970         ot->exec= unwrap_exec;
00971         ot->poll= ED_operator_uvmap;
00972 
00973         /* properties */
00974         RNA_def_enum(ot->srna, "method", method_items, 0, "Method", "Unwrapping method. Angle Based usually gives better results than Conformal, while being somewhat slower.");
00975         RNA_def_boolean(ot->srna, "fill_holes", 1, "Fill Holes", "Virtual fill holes in mesh before unwrapping, to better avoid overlaps and preserve symmetry.");
00976         RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", "Map UV's taking image aspect ratio into account.");
00977 }
00978 
00979 /**************** Project From View operator **************/
00980 static int uv_from_view_exec(bContext *C, wmOperator *op)
00981 {
00982         Scene *scene= CTX_data_scene(C);
00983         Object *obedit= CTX_data_edit_object(C);
00984         Camera *camera= NULL;
00985         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00986         ARegion *ar= CTX_wm_region(C);
00987         View3D *v3d= CTX_wm_view3d(C);
00988         RegionView3D *rv3d= ar->regiondata;
00989         EditFace *efa;
00990         MTFace *tf;
00991         float rotmat[4][4];
00992 
00993         /* add uvs if they don't exist yet */
00994         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
00995                 BKE_mesh_end_editmesh(obedit->data, em);
00996                 return OPERATOR_CANCELLED;
00997         }
00998 
00999         /* establish the camera object, so we can default to view mapping if anything is wrong with it */
01000         if ((rv3d->persp==RV3D_CAMOB) && (v3d->camera) && (v3d->camera->type==OB_CAMERA)) {
01001                 camera= v3d->camera->data;
01002         }
01003 
01004         if(RNA_boolean_get(op->ptr, "orthographic")) {
01005                 uv_map_rotation_matrix(rotmat, ar->regiondata, obedit, 90.0f, 0.0f, 1.0f);
01006                 
01007                 for(efa= em->faces.first; efa; efa= efa->next) {
01008                         if(efa->f & SELECT) {
01009                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01010 
01011                                 project_from_view_ortho(tf->uv[0], efa->v1->co, rotmat);
01012                                 project_from_view_ortho(tf->uv[1], efa->v2->co, rotmat);
01013                                 project_from_view_ortho(tf->uv[2], efa->v3->co, rotmat);
01014                                 if(efa->v4)
01015                                         project_from_view_ortho(tf->uv[3], efa->v4->co, rotmat);
01016                         }
01017                 }
01018         }
01019         else if (camera) {
01020                 struct UvCameraInfo *uci= project_camera_info(v3d->camera, obedit->obmat, scene->r.xsch, scene->r.ysch);
01021                 
01022                 if(uci) {
01023                         for(efa= em->faces.first; efa; efa= efa->next) {
01024                                 if(efa->f & SELECT) {
01025                                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01026 
01027                                         project_from_camera(tf->uv[0], efa->v1->co, uci);
01028                                         project_from_camera(tf->uv[1], efa->v2->co, uci);
01029                                         project_from_camera(tf->uv[2], efa->v3->co, uci);
01030                                         if(efa->v4)
01031                                                 project_from_camera(tf->uv[3], efa->v4->co, uci);
01032                                 }
01033                         }
01034                         
01035                         MEM_freeN(uci);
01036                 }
01037         }
01038         else {
01039                 copy_m4_m4(rotmat, obedit->obmat);
01040 
01041                 for(efa= em->faces.first; efa; efa= efa->next) {
01042                         if(efa->f & SELECT) {
01043                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01044 
01045                                 project_from_view(tf->uv[0], efa->v1->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
01046                                 project_from_view(tf->uv[1], efa->v2->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
01047                                 project_from_view(tf->uv[2], efa->v3->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
01048                                 if(efa->v4)
01049                                         project_from_view(tf->uv[3], efa->v4->co, rv3d->persmat, rotmat, ar->winx, ar->winy);
01050                         }
01051                 }
01052         }
01053 
01054         uv_map_clip_correct(em, op);
01055 
01056         DAG_id_tag_update(obedit->data, 0);
01057         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
01058 
01059         BKE_mesh_end_editmesh(obedit->data, em);
01060         return OPERATOR_FINISHED;
01061 }
01062 
01063 static int uv_from_view_poll(bContext *C)
01064 {
01065         RegionView3D *rv3d= CTX_wm_region_view3d(C);
01066 
01067         if(!ED_operator_uvmap(C))
01068                 return 0;
01069 
01070         return (rv3d != NULL);
01071 }
01072 
01073 void UV_OT_from_view(wmOperatorType *ot)
01074 {
01075         /* identifiers */
01076         ot->name= "Project From View";
01077         ot->idname= "UV_OT_project_from_view";
01078         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01079         
01080         /* api callbacks */
01081         ot->exec= uv_from_view_exec;
01082         ot->poll= uv_from_view_poll;
01083 
01084         /* properties */
01085         RNA_def_boolean(ot->srna, "orthographic", 0, "Orthographic", "Use orthographic projection.");
01086         uv_map_clip_correct_properties(ot);
01087 }
01088 
01089 /********************** Reset operator ********************/
01090 
01091 static int reset_exec(bContext *C, wmOperator *UNUSED(op))
01092 {
01093         Scene *scene= CTX_data_scene(C);
01094         Object *obedit= CTX_data_edit_object(C);
01095         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01096         EditFace *efa;
01097         MTFace *tf;
01098 
01099         /* add uvs if they don't exist yet */
01100         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
01101                 BKE_mesh_end_editmesh(obedit->data, em);
01102                 return OPERATOR_CANCELLED;
01103         }
01104 
01105         for(efa= em->faces.first; efa; efa= efa->next) {
01106                 if(efa->f & SELECT) {
01107                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01108 
01109                         tf->uv[0][0]= 0.0f;
01110                         tf->uv[0][1]= 0.0f;
01111                         
01112                         tf->uv[1][0]= 1.0f;
01113                         tf->uv[1][1]= 0.0f;
01114                         
01115                         tf->uv[2][0]= 1.0f;
01116                         tf->uv[2][1]= 1.0f;
01117                         
01118                         tf->uv[3][0]= 0.0f;
01119                         tf->uv[3][1]= 1.0f;
01120                 }
01121         }
01122 
01123         DAG_id_tag_update(obedit->data, 0);
01124         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
01125 
01126         BKE_mesh_end_editmesh(obedit->data, em);
01127         return OPERATOR_FINISHED;
01128 }
01129 
01130 void UV_OT_reset(wmOperatorType *ot)
01131 {
01132         /* identifiers */
01133         ot->name= "Reset";
01134         ot->idname= "UV_OT_reset";
01135         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01136         
01137         /* api callbacks */
01138         ot->exec= reset_exec;
01139         ot->poll= ED_operator_uvmap;
01140 }
01141 
01142 /****************** Sphere Project operator ***************/
01143 
01144 static void uv_sphere_project(float target[2], float source[3], float center[3], float rotmat[4][4])
01145 {
01146         float pv[3];
01147 
01148         sub_v3_v3v3(pv, source, center);
01149         mul_m4_v3(rotmat, pv);
01150 
01151         map_to_sphere( &target[0], &target[1],pv[0], pv[1], pv[2]);
01152 
01153         /* split line is always zero */
01154         if(target[0] >= 1.0f)
01155                 target[0] -= 1.0f;  
01156 }
01157 
01158 static void uv_map_mirror(EditFace *efa, MTFace *tf)
01159 {
01160         float dx;
01161         int nverts, i, mi;
01162 
01163         nverts= (efa->v4)? 4: 3;
01164 
01165         mi = 0;
01166         for(i=1; i<nverts; i++)
01167                 if(tf->uv[i][0] > tf->uv[mi][0])
01168                         mi = i;
01169 
01170         for(i=0; i<nverts; i++) {
01171                 if(i != mi) {
01172                         dx = tf->uv[mi][0] - tf->uv[i][0];
01173                         if(dx > 0.5f) tf->uv[i][0] += 1.0f;
01174                 } 
01175         } 
01176 }
01177 
01178 static int sphere_project_exec(bContext *C, wmOperator *op)
01179 {
01180         Scene *scene= CTX_data_scene(C);
01181         Object *obedit= CTX_data_edit_object(C);
01182         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01183         EditFace *efa;
01184         MTFace *tf;
01185         float center[3], rotmat[4][4];
01186 
01187         /* add uvs if they don't exist yet */
01188         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
01189                 BKE_mesh_end_editmesh(obedit->data, em);
01190                 return OPERATOR_CANCELLED;
01191         }
01192 
01193         uv_map_transform(C, op, center, rotmat);
01194 
01195         for(efa= em->faces.first; efa; efa= efa->next) {
01196                 if(efa->f & SELECT) {
01197                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01198 
01199                         uv_sphere_project(tf->uv[0], efa->v1->co, center, rotmat);
01200                         uv_sphere_project(tf->uv[1], efa->v2->co, center, rotmat);
01201                         uv_sphere_project(tf->uv[2], efa->v3->co, center, rotmat);
01202                         if(efa->v4)
01203                                 uv_sphere_project(tf->uv[3], efa->v4->co, center, rotmat);
01204 
01205                         uv_map_mirror(efa, tf);
01206                 }
01207         }
01208 
01209         uv_map_clip_correct(em, op);
01210 
01211         DAG_id_tag_update(obedit->data, 0);
01212         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
01213 
01214         BKE_mesh_end_editmesh(obedit->data, em);
01215         return OPERATOR_FINISHED;
01216 }
01217 
01218 void UV_OT_sphere_project(wmOperatorType *ot)
01219 {
01220         /* identifiers */
01221         ot->name= "Sphere Projection";
01222         ot->idname= "UV_OT_sphere_project";
01223         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01224         
01225         /* api callbacks */
01226         ot->exec= sphere_project_exec;
01227         ot->poll= ED_operator_uvmap;
01228 
01229         /* properties */
01230         uv_transform_properties(ot, 0);
01231         uv_map_clip_correct_properties(ot);
01232 }
01233 
01234 /***************** Cylinder Project operator **************/
01235 
01236 static void uv_cylinder_project(float target[2], float source[3], float center[3], float rotmat[4][4])
01237 {
01238         float pv[3];
01239 
01240         sub_v3_v3v3(pv, source, center);
01241         mul_m4_v3(rotmat, pv);
01242 
01243         map_to_tube( &target[0], &target[1],pv[0], pv[1], pv[2]);
01244 
01245         /* split line is always zero */
01246         if(target[0] >= 1.0f)
01247                 target[0] -= 1.0f;  
01248 }
01249 
01250 static int cylinder_project_exec(bContext *C, wmOperator *op)
01251 {
01252         Scene *scene= CTX_data_scene(C);
01253         Object *obedit= CTX_data_edit_object(C);
01254         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01255         EditFace *efa;
01256         MTFace *tf;
01257         float center[3], rotmat[4][4];
01258 
01259         /* add uvs if they don't exist yet */
01260         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
01261                 BKE_mesh_end_editmesh(obedit->data, em);
01262                 return OPERATOR_CANCELLED;
01263         }
01264 
01265         uv_map_transform(C, op, center, rotmat);
01266 
01267         for(efa= em->faces.first; efa; efa= efa->next) {
01268                 if(efa->f & SELECT) {
01269                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01270 
01271                         uv_cylinder_project(tf->uv[0], efa->v1->co, center, rotmat);
01272                         uv_cylinder_project(tf->uv[1], efa->v2->co, center, rotmat);
01273                         uv_cylinder_project(tf->uv[2], efa->v3->co, center, rotmat);
01274                         if(efa->v4)
01275                                 uv_cylinder_project(tf->uv[3], efa->v4->co, center, rotmat);
01276 
01277                         uv_map_mirror(efa, tf);
01278                 }
01279         }
01280 
01281         uv_map_clip_correct(em, op);
01282 
01283         DAG_id_tag_update(obedit->data, 0);
01284         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
01285 
01286         BKE_mesh_end_editmesh(obedit->data, em);
01287         return OPERATOR_FINISHED;
01288 }
01289 
01290 void UV_OT_cylinder_project(wmOperatorType *ot)
01291 {
01292         /* identifiers */
01293         ot->name= "Cylinder Projection";
01294         ot->idname= "UV_OT_cylinder_project";
01295         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01296         
01297         /* api callbacks */
01298         ot->exec= cylinder_project_exec;
01299         ot->poll= ED_operator_uvmap;
01300 
01301         /* properties */
01302         uv_transform_properties(ot, 1);
01303         uv_map_clip_correct_properties(ot);
01304 }
01305 
01306 /******************* Cube Project operator ****************/
01307 
01308 static int cube_project_exec(bContext *C, wmOperator *op)
01309 {
01310         Scene *scene= CTX_data_scene(C);
01311         Object *obedit= CTX_data_edit_object(C);
01312         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01313         EditFace *efa;
01314         MTFace *tf;
01315         float no[3], cube_size, *loc, dx, dy;
01316         int cox, coy;
01317 
01318         /* add uvs if they don't exist yet */
01319         if(!ED_uvedit_ensure_uvs(C, scene, obedit)) {
01320                 BKE_mesh_end_editmesh(obedit->data, em);
01321                 return OPERATOR_CANCELLED;
01322         }
01323 
01324         loc= obedit->obmat[3];
01325         cube_size= RNA_float_get(op->ptr, "cube_size");
01326 
01327         /* choose x,y,z axis for projection depending on the largest normal
01328          * component, but clusters all together around the center of map. */
01329 
01330         for(efa= em->faces.first; efa; efa= efa->next) {
01331                 if(efa->f & SELECT) {
01332                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01333                         normal_tri_v3( no,efa->v1->co, efa->v2->co, efa->v3->co);
01334                         
01335                         no[0]= fabs(no[0]);
01336                         no[1]= fabs(no[1]);
01337                         no[2]= fabs(no[2]);
01338                         
01339                         cox=0; coy= 1;
01340                         if(no[2]>=no[0] && no[2]>=no[1]);
01341                         else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2;
01342                         else { cox= 1; coy= 2; }
01343                         
01344                         tf->uv[0][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v1->co[cox]);
01345                         tf->uv[0][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v1->co[coy]);
01346                         dx = floor(tf->uv[0][0]);
01347                         dy = floor(tf->uv[0][1]);
01348                         tf->uv[0][0] -= dx;
01349                         tf->uv[0][1] -= dy;
01350                         tf->uv[1][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v2->co[cox]);
01351                         tf->uv[1][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v2->co[coy]);
01352                         tf->uv[1][0] -= dx;
01353                         tf->uv[1][1] -= dy;
01354                         tf->uv[2][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v3->co[cox]);
01355                         tf->uv[2][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v3->co[coy]);
01356                         tf->uv[2][0] -= dx;
01357                         tf->uv[2][1] -= dy;
01358 
01359                         if(efa->v4) {
01360                                 tf->uv[3][0]= 0.5f+0.5f*cube_size*(loc[cox] + efa->v4->co[cox]);
01361                                 tf->uv[3][1]= 0.5f+0.5f*cube_size*(loc[coy] + efa->v4->co[coy]);
01362                                 tf->uv[3][0] -= dx;
01363                                 tf->uv[3][1] -= dy;
01364                         }
01365                 }
01366         }
01367 
01368         uv_map_clip_correct(em, op);
01369 
01370         DAG_id_tag_update(obedit->data, 0);
01371         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
01372 
01373         BKE_mesh_end_editmesh(obedit->data, em);
01374         return OPERATOR_FINISHED;
01375 }
01376 
01377 void UV_OT_cube_project(wmOperatorType *ot)
01378 {
01379         /* identifiers */
01380         ot->name= "Cube Projection";
01381         ot->idname= "UV_OT_cube_project";
01382         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01383         
01384         /* api callbacks */
01385         ot->exec= cube_project_exec;
01386         ot->poll= ED_operator_uvmap;
01387 
01388         /* properties */
01389         RNA_def_float(ot->srna, "cube_size", 1.0f, 0.0f, FLT_MAX, "Cube Size", "Size of the cube to project on.", 0.001f, 100.0f);
01390         uv_map_clip_correct_properties(ot);
01391 }