Blender V2.61 - r43446

uvedit_unwrap_ops.c

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