Blender V2.61 - r43446

uvedit_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 <stdlib.h>
00034 #include <string.h>
00035 #include <math.h>
00036 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "DNA_object_types.h"
00040 #include "DNA_material_types.h"
00041 #include "DNA_meshdata_types.h"
00042 #include "DNA_node_types.h"
00043 #include "DNA_scene_types.h"
00044 
00045 #include "BLI_math.h"
00046 #include "BLI_blenlib.h"
00047 #include "BLI_editVert.h"
00048 #include "BLI_utildefines.h"
00049 
00050 #include "BKE_context.h"
00051 #include "BKE_customdata.h"
00052 #include "BKE_depsgraph.h"
00053 #include "BKE_image.h"
00054 #include "BKE_library.h"
00055 #include "BKE_main.h"
00056 #include "BKE_material.h"
00057 #include "BKE_mesh.h"
00058 #include "BKE_node.h"
00059 #include "BKE_report.h"
00060 #include "BKE_scene.h"
00061 
00062 #include "ED_image.h"
00063 #include "ED_mesh.h"
00064 #include "ED_node.h"
00065 #include "ED_uvedit.h"
00066 #include "ED_object.h"
00067 #include "ED_screen.h"
00068 #include "ED_transform.h"
00069 
00070 #include "RNA_access.h"
00071 #include "RNA_define.h"
00072 
00073 #include "WM_api.h"
00074 #include "WM_types.h"
00075 
00076 #include "UI_view2d.h"
00077 
00078 #include "uvedit_intern.h"
00079 
00080 /************************* state testing ************************/
00081 
00082 int ED_uvedit_test(Object *obedit)
00083 {
00084     EditMesh *em;
00085     int ret;
00086 
00087     if(!obedit || obedit->type != OB_MESH)
00088         return 0;
00089 
00090     em = BKE_mesh_get_editmesh(obedit->data);
00091     ret = EM_texFaceCheck(em);
00092     BKE_mesh_end_editmesh(obedit->data, em);
00093     
00094     return ret;
00095 }
00096 
00097 /**************************** object active image *****************************/
00098 
00099 static int is_image_texture_node(bNode *node)
00100 {
00101     return ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT);
00102 }
00103 
00104 int ED_object_get_active_image(Object *ob, int mat_nr, Image **ima, ImageUser **iuser, bNode **node_r)
00105 {
00106     Material *ma= give_current_material(ob, mat_nr);
00107     bNode *node= (ma && ma->use_nodes)? nodeGetActiveTexture(ma->nodetree): NULL;
00108 
00109     if(node && is_image_texture_node(node)) {
00110         if(ima) *ima= (Image*)node->id;
00111         if(iuser) *iuser= NULL;
00112         if(node_r) *node_r= node;
00113         return TRUE;
00114     }
00115     
00116     if(ima) *ima= NULL;
00117     if(iuser) *iuser= NULL;
00118     if(node_r) *node_r= node;
00119 
00120     return FALSE;
00121 }
00122 
00123 void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *ima)
00124 {
00125     Material *ma= give_current_material(ob, mat_nr);
00126     bNode *node= (ma && ma->use_nodes)? nodeGetActiveTexture(ma->nodetree): NULL;
00127 
00128     if(node && is_image_texture_node(node)) {
00129         node->id= &ima->id;
00130         ED_node_generic_update(bmain, ma->nodetree, node);
00131     }
00132 }
00133 
00134 /************************* assign image ************************/
00135 
00136 void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *ima, Image *previma)
00137 {
00138     EditMesh *em;
00139     EditFace *efa;
00140     MTFace *tf;
00141     int update= 0;
00142     
00143     /* skip assigning these procedural images... */
00144     if(ima && (ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE))
00145         return;
00146 
00147     /* verify we have a mesh we can work with */
00148     if(!obedit || (obedit->type != OB_MESH))
00149         return;
00150 
00151     em= BKE_mesh_get_editmesh(((Mesh*)obedit->data));
00152     if(!em || !em->faces.first) {
00153         BKE_mesh_end_editmesh(obedit->data, em);
00154         return;
00155     }
00156 
00157     if(scene_use_new_shading_nodes(scene)) {
00158         /* new shading system, assign image in material */
00159         int sloppy= 1;
00160         EditFace *efa= EM_get_actFace(em, sloppy);
00161 
00162         if(efa)
00163             ED_object_assign_active_image(bmain, obedit, efa->mat_nr, ima);
00164     }
00165     else {
00166         /* old shading system, assign image to selected faces */
00167         
00168         /* ensure we have a uv map */
00169         if(!CustomData_has_layer(&em->fdata, CD_MTFACE)) {
00170             EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL);
00171             update= 1;
00172         }
00173 
00174         /* now assign to all visible faces */
00175         for(efa= em->faces.first; efa; efa= efa->next) {
00176             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00177 
00178             if(uvedit_face_visible(scene, previma, efa, tf)) {
00179                 if(ima) {
00180                     tf->tpage= ima;
00181                     
00182                     if(ima->id.us==0) id_us_plus(&ima->id);
00183                     else id_lib_extern(&ima->id);
00184                 }
00185                 else
00186                     tf->tpage= NULL;
00187 
00188                 update = 1;
00189             }
00190         }
00191 
00192         /* and update depdency graph */
00193         if(update)
00194             DAG_id_tag_update(obedit->data, 0);
00195     }
00196 
00197     BKE_mesh_end_editmesh(obedit->data, em);
00198 }
00199 
00200 /* dotile - 1, set the tile flag (from the space image)
00201  *          2, set the tile index for the faces. */
00202 static int uvedit_set_tile(Object *obedit, Image *ima, int curtile)
00203 {
00204     EditMesh *em;
00205     EditFace *efa;
00206     MTFace *tf;
00207     
00208     /* verify if we have something to do */
00209     if(!ima || !ED_uvedit_test(obedit))
00210         return 0;
00211 
00212     if((ima->tpageflag & IMA_TILES) == 0)
00213         return 0;
00214 
00215     /* skip assigning these procedural images... */
00216     if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
00217         return 0;
00218     
00219     em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00220 
00221     for(efa= em->faces.first; efa; efa= efa->next) {
00222         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00223 
00224         if(efa->h==0 && efa->f & SELECT)
00225             tf->tile= curtile; /* set tile index */
00226     }
00227 
00228     DAG_id_tag_update(obedit->data, 0);
00229     BKE_mesh_end_editmesh(obedit->data, em);
00230 
00231     return 1;
00232 }
00233 
00234 /*********************** space conversion *********************/
00235 
00236 static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
00237 {
00238     int width, height;
00239 
00240     if(sima) {
00241         ED_space_image_size(sima, &width, &height);
00242     }
00243     else {
00244         width= 256;
00245         height= 256;
00246     }
00247 
00248     dist[0]= pixeldist/width;
00249     dist[1]= pixeldist/height;
00250 }
00251 
00252 /*************** visibility and selection utilities **************/
00253 
00254 int uvedit_face_visible_nolocal(Scene *scene, EditFace *efa)
00255 {
00256     ToolSettings *ts= scene->toolsettings;
00257 
00258     if(ts->uv_flag & UV_SYNC_SELECTION)
00259         return (efa->h==0);
00260     else
00261         return (efa->h==0 && (efa->f & SELECT));
00262 }
00263 
00264 int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf)
00265 {
00266     ToolSettings *ts= scene->toolsettings;
00267 
00268     if(ts->uv_flag & UV_SHOW_SAME_IMAGE)
00269         return (tf->tpage==ima)? uvedit_face_visible_nolocal(scene, efa): 0;
00270     else
00271         return uvedit_face_visible_nolocal(scene, efa);
00272 }
00273 
00274 int uvedit_face_selected(Scene *scene, EditFace *efa, MTFace *tf)
00275 {
00276     ToolSettings *ts= scene->toolsettings;
00277 
00278     if(ts->uv_flag & UV_SYNC_SELECTION)
00279         return (efa->f & SELECT);
00280     else
00281         return (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4));
00282 }
00283 
00284 void uvedit_face_select(Scene *scene, EditFace *efa, MTFace *tf)
00285 {
00286     ToolSettings *ts= scene->toolsettings;
00287 
00288     if(ts->uv_flag & UV_SYNC_SELECTION)
00289         EM_select_face(efa, 1);
00290     else
00291         tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
00292 }
00293 
00294 void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf)
00295 {
00296     ToolSettings *ts= scene->toolsettings;
00297 
00298     if(ts->uv_flag & UV_SYNC_SELECTION)
00299         EM_select_face(efa, 0);
00300     else
00301         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
00302 }
00303 
00304 int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
00305 {
00306     ToolSettings *ts= scene->toolsettings;
00307     int nvert= (efa->v4)? 4: 3;
00308 
00309     if(ts->uv_flag & UV_SYNC_SELECTION) {
00310         if(ts->selectmode & SCE_SELECT_FACE)
00311             return (efa->f & SELECT);
00312         else if(ts->selectmode & SCE_SELECT_EDGE)
00313             return (*(&efa->e1 + i))->f & SELECT;
00314         else
00315             return (((efa->v1 + i)->f & SELECT) && ((efa->v1 + (i+1)%nvert)->f & SELECT));
00316     }
00317     else
00318         return (tf->flag & TF_SEL_MASK(i)) && (tf->flag & TF_SEL_MASK((i+1)%nvert));
00319 }
00320 
00321 void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
00322 {
00323     ToolSettings *ts= scene->toolsettings;
00324     int nvert= (efa->v4)? 4: 3;
00325 
00326     if(ts->uv_flag & UV_SYNC_SELECTION) {
00327         if(ts->selectmode & SCE_SELECT_FACE)
00328             EM_select_face(efa, 1);
00329         else if(ts->selectmode & SCE_SELECT_EDGE)
00330             EM_select_edge((*(&efa->e1 + i)), 1);
00331         else {
00332             (efa->v1 + i)->f |= SELECT;
00333             (efa->v1 + (i+1)%nvert)->f |= SELECT;
00334         }
00335     }
00336     else
00337         tf->flag |= TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert);
00338 }
00339 
00340 void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
00341 {
00342     ToolSettings *ts= scene->toolsettings;
00343     int nvert= (efa->v4)? 4: 3;
00344 
00345     if(ts->uv_flag & UV_SYNC_SELECTION) {
00346         if(ts->selectmode & SCE_SELECT_FACE)
00347             EM_select_face(efa, 0);
00348         else if(ts->selectmode & SCE_SELECT_EDGE)
00349             EM_select_edge((*(&efa->e1 + i)), 0);
00350         else {
00351             (efa->v1 + i)->f &= ~SELECT;
00352             (efa->v1 + (i+1)%nvert)->f &= ~SELECT;
00353         }
00354     }
00355     else
00356         tf->flag &= ~(TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert));
00357 }
00358 
00359 int uvedit_uv_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
00360 {
00361     ToolSettings *ts= scene->toolsettings;
00362 
00363     if(ts->uv_flag & UV_SYNC_SELECTION) {
00364         if(ts->selectmode & SCE_SELECT_FACE)
00365             return (efa->f & SELECT);
00366         else
00367             return (*(&efa->v1 + i))->f & SELECT;
00368     }
00369     else
00370         return tf->flag & TF_SEL_MASK(i);
00371 }
00372 
00373 void uvedit_uv_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
00374 {
00375     ToolSettings *ts= scene->toolsettings;
00376 
00377     if(ts->uv_flag & UV_SYNC_SELECTION) {
00378         if(ts->selectmode & SCE_SELECT_FACE)
00379             EM_select_face(efa, 1);
00380         else
00381             (*(&efa->v1 + i))->f |= SELECT;
00382     }
00383     else
00384         tf->flag |= TF_SEL_MASK(i);
00385 }
00386 
00387 void uvedit_uv_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
00388 {
00389     ToolSettings *ts= scene->toolsettings;
00390 
00391     if(ts->uv_flag & UV_SYNC_SELECTION) {
00392         if(ts->selectmode & SCE_SELECT_FACE)
00393             EM_select_face(efa, 0);
00394         else
00395             (*(&efa->v1 + i))->f &= ~SELECT;
00396     }
00397     else
00398         tf->flag &= ~TF_SEL_MASK(i);
00399 }
00400 
00401 /*********************** live unwrap utilities ***********************/
00402 
00403 static void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
00404 {
00405     if(sima && (sima->flag & SI_LIVE_UNWRAP)) {
00406         ED_uvedit_live_unwrap_begin(scene, obedit);
00407         ED_uvedit_live_unwrap_re_solve();
00408         ED_uvedit_live_unwrap_end(0);
00409     }
00410 }
00411 
00412 /*********************** geometric utilities ***********************/
00413 
00414 void uv_center(float uv[][2], float cent[2], int quad)
00415 {
00416     if(quad) {
00417         cent[0] = (uv[0][0] + uv[1][0] + uv[2][0] + uv[3][0]) / 4.0f;
00418         cent[1] = (uv[0][1] + uv[1][1] + uv[2][1] + uv[3][1]) / 4.0f;
00419     }
00420     else {
00421         cent[0] = (uv[0][0] + uv[1][0] + uv[2][0]) / 3.0f;
00422         cent[1] = (uv[0][1] + uv[1][1] + uv[2][1]) / 3.0f;
00423     }
00424 }
00425 
00426 float uv_area(float uv[][2], int quad)
00427 {
00428     if(quad)
00429         return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); 
00430     else
00431         return area_tri_v2(uv[0], uv[1], uv[2]); 
00432 }
00433 
00434 void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy)
00435 {
00436     uv[0][0] = uv_orig[0][0]*aspx;
00437     uv[0][1] = uv_orig[0][1]*aspy;
00438     
00439     uv[1][0] = uv_orig[1][0]*aspx;
00440     uv[1][1] = uv_orig[1][1]*aspy;
00441     
00442     uv[2][0] = uv_orig[2][0]*aspx;
00443     uv[2][1] = uv_orig[2][1]*aspy;
00444     
00445     uv[3][0] = uv_orig[3][0]*aspx;
00446     uv[3][1] = uv_orig[3][1]*aspy;
00447 }
00448 
00449 int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
00450 {
00451     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00452     EditFace *efa;
00453     MTFace *tf;
00454     int sel;
00455 
00456     INIT_MINMAX2(min, max);
00457 
00458     sel= 0;
00459     for(efa= em->faces.first; efa; efa= efa->next) {
00460         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00461         if(uvedit_face_visible(scene, ima, efa, tf)) {
00462             if(uvedit_uv_selected(scene, efa, tf, 0))               { DO_MINMAX2(tf->uv[0], min, max); sel = 1; }
00463             if(uvedit_uv_selected(scene, efa, tf, 1))               { DO_MINMAX2(tf->uv[1], min, max); sel = 1; }
00464             if(uvedit_uv_selected(scene, efa, tf, 2))               { DO_MINMAX2(tf->uv[2], min, max); sel = 1; }
00465             if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3)))  { DO_MINMAX2(tf->uv[3], min, max); sel = 1; }
00466         }
00467     }
00468     
00469     BKE_mesh_end_editmesh(obedit->data, em);
00470     return sel;
00471 }
00472 
00473 static int ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[3])
00474 {
00475     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00476     EditFace *efa;
00477     MTFace *tf;
00478     unsigned int sel= 0;
00479 
00480     zero_v3(co);
00481 
00482     for(efa= em->faces.first; efa; efa= efa->next) {
00483         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00484         if(uvedit_face_visible(scene, ima, efa, tf)) {
00485             if(uvedit_uv_selected(scene, efa, tf, 0))               { add_v3_v3(co, tf->uv[0]); sel++; }
00486             if(uvedit_uv_selected(scene, efa, tf, 1))               { add_v3_v3(co, tf->uv[1]); sel++; }
00487             if(uvedit_uv_selected(scene, efa, tf, 2))               { add_v3_v3(co, tf->uv[2]); sel++; }
00488             if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3)))  { add_v3_v3(co, tf->uv[3]); sel++; }
00489         }
00490     }
00491 
00492     mul_v3_fl(co, 1.0f/(float)sel);
00493 
00494     BKE_mesh_end_editmesh(obedit->data, em);
00495     return (sel != 0);
00496 }
00497 
00498 static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, char mode)
00499 {
00500     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00501     float min[2], max[2];
00502     int change= 0;
00503     
00504     if(mode==V3D_CENTER) { /* bounding box */
00505         if(ED_uvedit_minmax(scene, ima, obedit, min, max)) {
00506             change = 1;
00507 
00508             cent[0]= (min[0]+max[0])/2.0f;
00509             cent[1]= (min[1]+max[1])/2.0f;
00510         }
00511     }
00512     else {
00513         if(ED_uvedit_median(scene, ima, obedit, cent)) {
00514             change = 1;
00515         }
00516 
00517     }
00518 
00519     if(change) {
00520         BKE_mesh_end_editmesh(obedit->data, em);
00521         return 1;
00522     }
00523 
00524     BKE_mesh_end_editmesh(obedit->data, em);
00525     return 0;
00526 }
00527 
00528 /************************** find nearest ****************************/
00529 
00530 typedef struct NearestHit {
00531     EditFace *efa;
00532     MTFace *tf;
00533 
00534     int vert, uv;
00535     int edge, vert2;
00536 } NearestHit;
00537 
00538 static void find_nearest_uv_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
00539 {
00540     MTFace *tf;
00541     EditFace *efa;
00542     EditVert *eve;
00543     float mindist, dist;
00544     int i, nverts;
00545 
00546     mindist= 1e10f;
00547     memset(hit, 0, sizeof(*hit));
00548 
00549     for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
00550         eve->tmp.l = i;
00551     
00552     for(efa= em->faces.first; efa; efa= efa->next) {
00553         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00554 
00555         if(uvedit_face_visible(scene, ima, efa, tf)) {
00556             nverts= efa->v4? 4: 3;
00557 
00558             for(i=0; i<nverts; i++) {
00559                 dist= dist_to_line_segment_v2(co, tf->uv[i], tf->uv[(i+1)%nverts]);
00560 
00561                 if(dist < mindist) {
00562                     hit->tf= tf;
00563                     hit->efa= efa;
00564                     hit->edge= i;
00565                     mindist= dist;
00566 
00567                     hit->vert= (*(&efa->v1 + i))->tmp.l;
00568                     hit->vert2= (*(&efa->v1 + ((i+1)%nverts)))->tmp.l;
00569                 }
00570             }
00571         }
00572     }
00573 }
00574 
00575 static void find_nearest_uv_face(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
00576 {
00577     MTFace *tf;
00578     EditFace *efa;
00579     float mindist, dist, cent[2];
00580     int i, nverts;
00581 
00582     mindist= 1e10f;
00583     memset(hit, 0, sizeof(*hit));
00584     
00585     for(efa= em->faces.first; efa; efa= efa->next) {
00586         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00587 
00588         if(uvedit_face_visible(scene, ima, efa, tf)) {
00589             nverts= efa->v4? 4: 3;
00590             cent[0]= cent[1]= 0.0f;
00591 
00592             for(i=0; i<nverts; i++) {
00593                 add_v2_v2(cent, tf->uv[i]);
00594             }
00595 
00596             cent[0] /= nverts;
00597             cent[1] /= nverts;
00598             dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
00599 
00600             if(dist < mindist) {
00601                 hit->tf= tf;
00602                 hit->efa= efa;
00603                 mindist= dist;
00604             }
00605         }
00606     }
00607 }
00608 
00609 static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float uv[2])
00610 {
00611     float m[3], v1[3], v2[3], c1, c2;
00612     int id1, id2;
00613 
00614     id1= (id+nverts-1)%nverts;
00615     id2= (id+nverts+1)%nverts;
00616 
00617     m[0]= co[0]-uv[0];
00618     m[1]= co[1]-uv[1];
00619     sub_v2_v2v2(v1, tf->uv[id1], tf->uv[id]);
00620     sub_v2_v2v2(v2, tf->uv[id2], tf->uv[id]);
00621 
00622     /* m and v2 on same side of v-v1? */
00623     c1= v1[0]*m[1] - v1[1]*m[0];
00624     c2= v1[0]*v2[1] - v1[1]*v2[0];
00625 
00626     if(c1*c2 < 0.0f)
00627         return 0;
00628 
00629     /* m and v1 on same side of v-v2? */
00630     c1= v2[0]*m[1] - v2[1]*m[0];
00631     c2= v2[0]*v1[1] - v2[1]*v1[0];
00632 
00633     return (c1*c2 >= 0.0f);
00634 }
00635 
00636 static void find_nearest_uv_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit)
00637 {
00638     EditFace *efa;
00639     EditVert *eve;
00640     MTFace *tf;
00641     float mindist, dist;
00642     int i, nverts;
00643 
00644     mindist= 1e10f;
00645     memset(hit, 0, sizeof(*hit));
00646     
00647     for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
00648         eve->tmp.l = i;
00649     
00650     for(efa= em->faces.first; efa; efa= efa->next) {
00651         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00652 
00653         if(uvedit_face_visible(scene, ima, efa, tf)) {
00654             nverts= efa->v4? 4: 3;
00655 
00656             for(i=0; i<nverts; i++) {
00657                 if(penalty && uvedit_uv_selected(scene, efa, tf, i))
00658                     dist= fabsf(co[0]-tf->uv[i][0])+penalty[0] + fabsf(co[1]-tf->uv[i][1]) + penalty[1];
00659                 else
00660                     dist= fabsf(co[0]-tf->uv[i][0]) + fabsf(co[1]-tf->uv[i][1]);
00661 
00662                 if(dist<=mindist) {
00663                     if(dist==mindist)
00664                         if(!nearest_uv_between(tf, nverts, i, co, tf->uv[i]))
00665                             continue;
00666 
00667                     mindist= dist;
00668 
00669                     hit->uv= i;
00670                     hit->tf= tf;
00671                     hit->efa= efa;
00672 
00673                     hit->vert= (*(&efa->v1 + i))->tmp.l;
00674                 }
00675             }
00676         }
00677     }
00678 }
00679 
00680 int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
00681 {
00682     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
00683     EditFace *efa;
00684     MTFace *tf;
00685     float mindist, dist;
00686     int i, nverts, found= 0;
00687 
00688     mindist= 1e10f;
00689     uv[0]= co[0];
00690     uv[1]= co[1];
00691     
00692     for(efa= em->faces.first; efa; efa= efa->next) {
00693         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00694 
00695         if(uvedit_face_visible(scene, ima, efa, tf)) {
00696             nverts= efa->v4? 4: 3;
00697 
00698             for(i=0; i<nverts; i++) {
00699                 if(uvedit_uv_selected(scene, efa, tf, i))
00700                     continue;
00701 
00702                 dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
00703 
00704                 if(dist<=mindist) {
00705                     mindist= dist;
00706 
00707                     uv[0]= tf->uv[i][0];
00708                     uv[1]= tf->uv[i][1];
00709                     found= 1;
00710                 }
00711             }
00712         }
00713     }
00714 
00715     BKE_mesh_end_editmesh(obedit->data, em);
00716     return found;
00717 }
00718 
00719 /*********************** loop select ***********************/
00720 
00721 static void uv_vertex_loop_flag(UvMapVert *first)
00722 {
00723     UvMapVert *iterv;
00724     int count= 0;
00725 
00726     for(iterv=first; iterv; iterv=iterv->next) {
00727         if(iterv->separate && iterv!=first)
00728             break;
00729 
00730         count++;
00731     }
00732     
00733     if(count < 5)
00734         first->flag= 1;
00735 }
00736 
00737 static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
00738 {
00739     UvMapVert *iterv, *first;
00740     
00741     first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l);
00742 
00743     for(iterv=first; iterv; iterv=iterv->next) {
00744         if(iterv->separate)
00745             first= iterv;
00746         if(iterv->f == efa->tmp.l)
00747             return first;
00748     }
00749     
00750     return NULL;
00751 }
00752 
00753 static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
00754 {
00755     UvMapVert *iterv1, *iterv2;
00756     EditFace *efa;
00757     int tot = 0;
00758 
00759     /* count number of faces this edge has */
00760     for(iterv1=first1; iterv1; iterv1=iterv1->next) {
00761         if(iterv1->separate && iterv1 != first1)
00762             break;
00763 
00764         for(iterv2=first2; iterv2; iterv2=iterv2->next) {
00765             if(iterv2->separate && iterv2 != first2)
00766                 break;
00767 
00768             if(iterv1->f == iterv2->f) {
00769                 /* if face already tagged, don't do this edge */
00770                 efa= EM_get_face_for_index(iterv1->f);
00771                 if(efa->f1)
00772                     return 0;
00773 
00774                 tot++;
00775                 break;
00776             }
00777         }
00778     }
00779 
00780     if(*totface == 0) /* start edge */
00781         *totface= tot;
00782     else if(tot != *totface) /* check for same number of faces as start edge */
00783         return 0;
00784 
00785     /* tag the faces */
00786     for(iterv1=first1; iterv1; iterv1=iterv1->next) {
00787         if(iterv1->separate && iterv1 != first1)
00788             break;
00789 
00790         for(iterv2=first2; iterv2; iterv2=iterv2->next) {
00791             if(iterv2->separate && iterv2 != first2)
00792                 break;
00793 
00794             if(iterv1->f == iterv2->f) {
00795                 efa= EM_get_face_for_index(iterv1->f);
00796                 efa->f1= 1;
00797                 break;
00798             }
00799         }
00800     }
00801 
00802     return 1;
00803 }
00804 
00805 static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *hit, float limit[2], int extend)
00806 {
00807     EditVert *eve;
00808     EditFace *efa;
00809     MTFace *tf;
00810     UvVertMap *vmap;
00811     UvMapVert *iterv1, *iterv2;
00812     int a, count, looking, nverts, starttotf, select;
00813 
00814     /* setup */
00815     EM_init_index_arrays(em, 0, 0, 1);
00816     vmap= EM_make_uv_vert_map(em, 0, 0, limit);
00817 
00818     for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
00819         eve->tmp.l = count;
00820 
00821     for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) {
00822         if(!extend) {
00823             tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00824             uvedit_face_deselect(scene, efa, tf);
00825         }
00826 
00827         efa->tmp.l= count;
00828         efa->f1= 0;
00829     }
00830     
00831     /* set flags for first face and verts */
00832     nverts= (hit->efa->v4)? 4: 3;
00833     iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
00834     iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
00835     uv_vertex_loop_flag(iterv1);
00836     uv_vertex_loop_flag(iterv2);
00837 
00838     starttotf= 0;
00839     uv_edge_tag_faces(iterv1, iterv2, &starttotf);
00840 
00841     /* sorry, first edge isnt even ok */
00842     if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
00843     else looking= 1;
00844 
00845     /* iterate */
00846     while(looking) {
00847         looking= 0;
00848 
00849         /* find correct valence edges which are not tagged yet, but connect to tagged one */
00850         for(efa= em->faces.first; efa; efa=efa->next) {
00851             tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00852 
00853             if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tf)) {
00854                 nverts= (efa->v4)? 4: 3;
00855                 for(a=0; a<nverts; a++) {
00856                     /* check face not hidden and not tagged */
00857                     iterv1= uv_vertex_map_get(vmap, efa, a);
00858                     iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
00859 
00860                     /* check if vertex is tagged and has right valence */
00861                     if(iterv1->flag || iterv2->flag) {
00862                         if(uv_edge_tag_faces(iterv1, iterv2, &starttotf)) {
00863                             looking= 1;
00864                             efa->f1= 1;
00865 
00866                             uv_vertex_loop_flag(iterv1);
00867                             uv_vertex_loop_flag(iterv2);
00868                             break;
00869                         }
00870                     }
00871                 }
00872             }
00873         }
00874     }
00875 
00876     /* do the actual select/deselect */
00877     nverts= (hit->efa->v4)? 4: 3;
00878     iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
00879     iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
00880     iterv1->flag= 1;
00881     iterv2->flag= 1;
00882 
00883     if(extend) {
00884         tf= CustomData_em_get(&em->fdata, hit->efa->data, CD_MTFACE);
00885 
00886         if(uvedit_uv_selected(scene, hit->efa, tf, hit->edge))
00887             select= 0;
00888         else
00889             select= 1;
00890     }
00891     else
00892         select= 1;
00893     
00894     for(efa= em->faces.first; efa; efa=efa->next) {
00895         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00896 
00897         nverts= (efa->v4)? 4: 3;
00898         for(a=0; a<nverts; a++) {
00899             iterv1= uv_vertex_map_get(vmap, efa, a);
00900 
00901             if(iterv1->flag) {
00902                 if(select) uvedit_uv_select(scene, efa, tf, a);
00903                 else uvedit_uv_deselect(scene, efa, tf, a);
00904             }
00905         }
00906     }
00907 
00908     /* cleanup */
00909     EM_free_uv_vert_map(vmap);
00910     EM_free_index_arrays();
00911 
00912     return (select)? 1: -1;
00913 }
00914 
00915 /*********************** linked select ***********************/
00916 
00917 static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2], NearestHit *hit, int extend)
00918 {
00919     EditFace *efa;
00920     MTFace *tf;
00921     UvVertMap *vmap;
00922     UvMapVert *vlist, *iterv, *startv;
00923     int i, nverts, stacksize= 0, *stack;
00924     unsigned int a;
00925     char *flag;
00926 
00927     EM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
00928     vmap= EM_make_uv_vert_map(em, 1, 0, limit);
00929     if(vmap == NULL)
00930         return;
00931 
00932     stack= MEM_mallocN(sizeof(*stack) * em->totface, "UvLinkStack");
00933     flag= MEM_callocN(sizeof(*flag) * em->totface, "UvLinkFlag");
00934 
00935     if(!hit) {
00936         for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
00937             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00938 
00939             if(uvedit_face_visible(scene, ima, efa, tf)) {
00940                 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
00941                 if(tf->flag & select_flag) {
00942                     stack[stacksize]= a;
00943                     stacksize++;
00944                     flag[a]= 1;
00945                 }
00946             }
00947         }
00948     }
00949     else {
00950         for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
00951             if(efa == hit->efa) {
00952                 stack[stacksize]= a;
00953                 stacksize++;
00954                 flag[a]= 1;
00955                 break;
00956             }
00957         }
00958     }
00959 
00960     while(stacksize > 0) {
00961         stacksize--;
00962         a= stack[stacksize];
00963 
00964         efa = EM_get_face_for_index(a);
00965 
00966         nverts= efa->v4? 4: 3;
00967 
00968         for(i=0; i<nverts; i++) {
00969             /* make_uv_vert_map_EM sets verts tmp.l to the indices */
00970             vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
00971             
00972             startv= vlist;
00973 
00974             for(iterv=vlist; iterv; iterv=iterv->next) {
00975                 if(iterv->separate)
00976                     startv= iterv;
00977                 if(iterv->f == a)
00978                     break;
00979             }
00980 
00981             for(iterv=startv; iterv; iterv=iterv->next) {
00982                 if((startv != iterv) && (iterv->separate))
00983                     break;
00984                 else if(!flag[iterv->f]) {
00985                     flag[iterv->f]= 1;
00986                     stack[stacksize]= iterv->f;
00987                     stacksize++;
00988                 }
00989             }
00990         }
00991     }
00992 
00993     if(!extend) {
00994         for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
00995             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
00996             if(flag[a])
00997                 tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
00998             else
00999                 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
01000         }
01001     }
01002     else {
01003         for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
01004             if(flag[a]) {
01005                 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
01006                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01007                 if((tf->flag & select_flag))
01008                     break;
01009             }
01010         }
01011 
01012         if(efa) {
01013             for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
01014                 if(flag[a]) {
01015                     tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01016                     tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
01017                 }
01018             }
01019         }
01020         else {
01021             for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
01022                 if(flag[a]) {
01023                     tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01024                     tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
01025                 }
01026             }
01027         }
01028     }
01029     
01030     MEM_freeN(stack);
01031     MEM_freeN(flag);
01032     EM_free_uv_vert_map(vmap);
01033     EM_free_index_arrays();
01034 }
01035 
01036 /* ******************** align operator **************** */
01037 
01038 static void weld_align_uv(bContext *C, int tool)
01039 {
01040     SpaceImage *sima;
01041     Scene *scene;
01042     Object *obedit;
01043     Image *ima;
01044     EditMesh *em;
01045     EditFace *efa;
01046     MTFace *tf;
01047     float cent[2], min[2], max[2];
01048     
01049     scene= CTX_data_scene(C);
01050     obedit= CTX_data_edit_object(C);
01051     em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01052     ima= CTX_data_edit_image(C);
01053     sima= CTX_wm_space_image(C);
01054 
01055     INIT_MINMAX2(min, max);
01056 
01057     if(tool == 'a') {
01058         for(efa= em->faces.first; efa; efa= efa->next) {
01059             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01060 
01061             if(uvedit_face_visible(scene, ima, efa, tf)) {
01062                 if(uvedit_uv_selected(scene, efa, tf, 0))
01063                     DO_MINMAX2(tf->uv[0], min, max)
01064                 if(uvedit_uv_selected(scene, efa, tf, 1))
01065                     DO_MINMAX2(tf->uv[1], min, max)
01066                 if(uvedit_uv_selected(scene, efa, tf, 2))
01067                     DO_MINMAX2(tf->uv[2], min, max)
01068                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
01069                     DO_MINMAX2(tf->uv[3], min, max)
01070             }
01071         }
01072 
01073         tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
01074     }
01075 
01076     uvedit_center(scene, ima, obedit, cent, 0);
01077 
01078     if(tool == 'x' || tool == 'w') {
01079         for(efa= em->faces.first; efa; efa= efa->next) {
01080             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01081             if(uvedit_face_visible(scene, ima, efa, tf)) {
01082                 if(uvedit_uv_selected(scene, efa, tf, 0))
01083                     tf->uv[0][0]= cent[0];
01084                 if(uvedit_uv_selected(scene, efa, tf, 1))
01085                     tf->uv[1][0]= cent[0];
01086                 if(uvedit_uv_selected(scene, efa, tf, 2))
01087                     tf->uv[2][0]= cent[0];
01088                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
01089                     tf->uv[3][0]= cent[0];
01090             }
01091         }
01092     }
01093 
01094     if(tool == 'y' || tool == 'w') {
01095         for(efa= em->faces.first; efa; efa= efa->next) {
01096             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01097             if(uvedit_face_visible(scene, ima, efa, tf)) {
01098                 if(uvedit_uv_selected(scene, efa, tf, 0))
01099                     tf->uv[0][1]= cent[1];
01100                 if(uvedit_uv_selected(scene, efa, tf, 1))
01101                     tf->uv[1][1]= cent[1];
01102                 if(uvedit_uv_selected(scene, efa, tf, 2))
01103                     tf->uv[2][1]= cent[1];
01104                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
01105                     tf->uv[3][1]= cent[1];
01106             }
01107         }
01108     }
01109 
01110     if(tool == 's' || tool == 't' || tool == 'u') {
01111          /* pass 1&2 variables */
01112         int i, j;
01113         int starttmpl= -1, connectedtostarttmpl= -1, startcorner;
01114         int endtmpl= -1,   connectedtoendtmpl= -1,   endcorner;
01115         MTFace *startface, *endface;
01116         int itmpl, jtmpl;
01117         EditVert *eve;
01118         int pass; /* first 2 passes find endpoints, 3rd pass moves middle points, 4th pass is fail-on-face-selected */
01119         EditFace *startefa, *endefa= NULL; /* endefa shouldnt need to be initialized but just incase */
01120 
01121          /* pass 3 variables */
01122         float startx, starty, firstm,  firstb,  midx,      midy;
01123         float endx,   endy,   secondm, secondb, midmovedx, midmovedy;
01124         float IsVertical_check= -1;
01125         float IsHorizontal_check= -1;
01126 
01127         for(i= 0, eve= em->verts.first; eve; eve= eve->next, i++) /* give each point a unique name */
01128             eve->tmp.l= i;
01129         for(pass= 1; pass <= 3; pass++) { /* do this for each endpoint */
01130             if(pass == 3){ /* calculate */
01131                 startx= startface->uv[startcorner][0];
01132                 starty= startface->uv[startcorner][1];
01133                 endx= endface->uv[endcorner][0];
01134                 endy= endface->uv[endcorner][1];
01135                 firstm= (endy-starty)/(endx-startx);
01136                 firstb= starty-(firstm*startx);
01137                 secondm= -1.0f/firstm;
01138                 if(startx == endx) IsVertical_check= startx;
01139                 if(starty == endy) IsHorizontal_check= starty;
01140             }
01141             for(efa= em->faces.first; efa; efa= efa->next) { /* for each face */
01142                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); /* get face */
01143                 if(uvedit_face_visible(scene, ima, efa, tf)) { /* if you can see it */
01144                     if(uvedit_face_selected(scene, efa, tf)) { /* if the face is selected, get out now! */
01145                         pass= 4;
01146                         break;
01147                     }
01148                     for(i= 0; (i < 3 || (i == 3 && efa->v4)); i++) { /* for each point of the face */
01149                         itmpl= (*(&efa->v1 + i))->tmp.l; /* get unique name for points */
01150                         if(pass == 3) { /* move */
01151                             if(uvedit_uv_selected(scene, efa, tf, i)) {
01152                                 if(!(itmpl == starttmpl || itmpl == endtmpl)) {
01153                                     if(IsVertical_check != -1) tf->uv[i][0]= IsVertical_check;
01154                                     if(IsHorizontal_check != -1) tf->uv[i][1]= IsHorizontal_check;
01155                                     if((IsVertical_check == -1) && (IsHorizontal_check == -1)) {
01156                                         midx= tf->uv[i][0];
01157                                         midy= tf->uv[i][1];
01158                                         if(tool == 's') {
01159                                             secondb= midy-(secondm*midx);
01160                                             midmovedx= (secondb-firstb)/(firstm-secondm);
01161                                             midmovedy= (secondm*midmovedx)+secondb;
01162                                             tf->uv[i][0]= midmovedx;
01163                                             tf->uv[i][1]= midmovedy;
01164                                         }
01165                                         else if(tool == 't') {
01166                                             tf->uv[i][0]= (midy-firstb)/firstm; /* midmovedx */
01167                                         }
01168                                         else if(tool == 'u') {
01169                                             tf->uv[i][1]= (firstm*midx)+firstb; /* midmovedy */
01170                                         }
01171                                     }
01172                                 }
01173                             }
01174                         }
01175                         else {
01176                             for(j= 0; (j < 3 || (j == 3 && efa->v4)); j++) { /* also for each point on the face */
01177                                 jtmpl= (*(&efa->v1 + j))->tmp.l;
01178                                 if(i != j && (!efa->v4 || ABS(i-j) !=  2)) { /* if the points are connected */
01179                                     /* quad   (0,1,2,3) 0,1 0,3 1,0 1,2 2,1 2,3 3,0 3,2
01180                                      * triangle (0,1,2) 0,1 0,2 1,0 1,2 2,0 2,1 */
01181                                     if(uvedit_uv_selected(scene, efa, tf, i) && uvedit_uv_selected(scene, efa, tf, j)) {
01182                                          /* if the edge is selected */
01183                                         if(pass == 1) { /* if finding first endpoint */
01184                                             if(starttmpl == -1) { /* if the first endpoint isn't found yet */
01185                                                 starttmpl= itmpl; /* set unique name for endpoint */
01186                                                 connectedtostarttmpl= jtmpl;
01187                                                  /* get point that endpoint is connected to */
01188                                                 startface= tf; /* get face it's on */
01189                                                 startcorner= i; /* what corner of the face? */
01190                                                 startefa= efa;
01191                                                 efa= em->faces.first;
01192                                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01193                                                 i= -1;
01194                                                 break;
01195                                             }
01196                                             if(starttmpl == itmpl && jtmpl != connectedtostarttmpl) {
01197                                                 starttmpl= -1; /* not an endpoint */
01198                                                 efa= startefa;
01199                                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01200                                                 i= startcorner;
01201                                                 break;
01202                                             }
01203                                         }
01204                                         else if(pass == 2) { /* if finding second endpoint */
01205                                             if(endtmpl == -1 && itmpl != starttmpl) {
01206                                                 endtmpl= itmpl;
01207                                                 connectedtoendtmpl= jtmpl;
01208                                                 endface= tf;
01209                                                 endcorner= i;
01210                                                 endefa= efa;
01211                                                 efa= em->faces.first;
01212                                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01213                                                 i= -1;
01214                                                 break;
01215                                             }
01216                                             if(endtmpl == itmpl && jtmpl != connectedtoendtmpl) {
01217                                                 endtmpl= -1;
01218                                                 efa= endefa;
01219                                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01220                                                 i= endcorner;
01221                                                 break;
01222                                             }
01223                                         }
01224                                     }
01225                                 }
01226                             }
01227                         }
01228                     }
01229                 }
01230             }
01231             if(pass == 2 && (starttmpl == -1 || endtmpl == -1)) {
01232                 /* if endpoints aren't found */
01233                 pass=4;
01234             }
01235         }
01236     }
01237 
01238     uvedit_live_unwrap_update(sima, scene, obedit);
01239     DAG_id_tag_update(obedit->data, 0);
01240     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
01241 
01242     BKE_mesh_end_editmesh(obedit->data, em);
01243 }
01244 
01245 static int align_exec(bContext *C, wmOperator *op)
01246 {
01247     weld_align_uv(C, RNA_enum_get(op->ptr, "axis"));
01248 
01249     return OPERATOR_FINISHED;
01250 }
01251 
01252 static void UV_OT_align(wmOperatorType *ot)
01253 {
01254     static EnumPropertyItem axis_items[] = {
01255         {'s', "ALIGN_S", 0, "Straighten", "Align UVs along the line defined by the endpoints"},
01256         {'t', "ALIGN_T", 0, "Straighten X", "Align UVs along the line defined by the endpoints along the X axis"},
01257         {'u', "ALIGN_U", 0, "Straighten Y", "Align UVs along the line defined by the endpoints along the Y axis"},
01258         {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"},
01259         {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
01260         {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
01261         {0, NULL, 0, NULL, NULL}};
01262 
01263     /* identifiers */
01264     ot->name= "Align";
01265     ot->description= "Align selected UV vertices to an axis";
01266     ot->idname= "UV_OT_align";
01267     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01268     
01269     /* api callbacks */
01270     ot->exec= align_exec;
01271     ot->poll= ED_operator_image_active; /* requires space image */;
01272 
01273     /* properties */
01274     RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on");
01275 }
01276 
01277 /* ******************** weld operator **************** */
01278 
01279 static int weld_exec(bContext *C, wmOperator *UNUSED(op))
01280 {
01281     weld_align_uv(C, 'w');
01282 
01283     return OPERATOR_FINISHED;
01284 }
01285 
01286 static void UV_OT_weld(wmOperatorType *ot)
01287 {
01288     /* identifiers */
01289     ot->name= "Weld";
01290     ot->description= "Weld selected UV vertices together";
01291     ot->idname= "UV_OT_weld";
01292     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01293     
01294     /* api callbacks */
01295     ot->exec= weld_exec;
01296     ot->poll= ED_operator_uvedit;
01297 }
01298 
01299 /* ******************** stitch operator **************** */
01300 
01301 /* just for averaging UVs */
01302 typedef struct UVVertAverage {
01303     float uv[2];
01304     int count;
01305 } UVVertAverage;
01306 
01307 static int stitch_exec(bContext *C, wmOperator *op)
01308 {
01309     SpaceImage *sima;
01310     Scene *scene;
01311     Object *obedit;
01312     EditMesh *em;
01313     EditFace *efa;
01314     EditVert *eve;
01315     Image *ima;
01316     MTFace *tf;
01317 
01318     scene= CTX_data_scene(C);
01319     obedit= CTX_data_edit_object(C);
01320     em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01321     ima= CTX_data_edit_image(C);
01322     sima= CTX_wm_space_image(C);
01323     
01324     if(RNA_boolean_get(op->ptr, "use_limit")) {
01325         UvVertMap *vmap;
01326         UvMapVert *vlist, *iterv;
01327         float newuv[2], limit[2];
01328         int a, vtot;
01329 
01330         limit[0]= RNA_float_get(op->ptr, "limit");
01331         limit[1]= limit[0];
01332 
01333         EM_init_index_arrays(em, 0, 0, 1);
01334         vmap= EM_make_uv_vert_map(em, 1, 0, limit);
01335 
01336         if(vmap == NULL) {
01337             BKE_mesh_end_editmesh(obedit->data, em);
01338             return OPERATOR_CANCELLED;
01339         }
01340 
01341         for(a=0, eve= em->verts.first; eve; a++, eve= eve->next) {
01342             vlist= EM_get_uv_map_vert(vmap, a);
01343 
01344             while(vlist) {
01345                 newuv[0]= 0; newuv[1]= 0;
01346                 vtot= 0;
01347 
01348                 for(iterv=vlist; iterv; iterv=iterv->next) {
01349                     if((iterv != vlist) && iterv->separate)
01350                         break;
01351 
01352                     efa = EM_get_face_for_index(iterv->f);
01353                     tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01354                     
01355                     if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
01356                         newuv[0] += tf->uv[iterv->tfindex][0];
01357                         newuv[1] += tf->uv[iterv->tfindex][1];
01358                         vtot++;
01359                     }
01360                 }
01361 
01362                 if(vtot > 1) {
01363                     newuv[0] /= vtot; newuv[1] /= vtot;
01364 
01365                     for(iterv=vlist; iterv; iterv=iterv->next) {
01366                         if((iterv != vlist) && iterv->separate)
01367                             break;
01368 
01369                         efa = EM_get_face_for_index(iterv->f);
01370                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01371 
01372                         if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
01373                             tf->uv[iterv->tfindex][0]= newuv[0];
01374                             tf->uv[iterv->tfindex][1]= newuv[1];
01375                         }
01376                     }
01377                 }
01378 
01379                 vlist= iterv;
01380             }
01381         }
01382 
01383         EM_free_uv_vert_map(vmap);
01384         EM_free_index_arrays();
01385     }
01386     else {
01387         UVVertAverage *uv_average, *uvav;
01388         int count;
01389 
01390         // index and count verts
01391         for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
01392             eve->tmp.l = count;
01393         
01394         uv_average= MEM_callocN(sizeof(UVVertAverage)*count, "Stitch");
01395         
01396         // gather uv averages per vert
01397         for(efa= em->faces.first; efa; efa= efa->next) {
01398             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01399 
01400             if(uvedit_face_visible(scene, ima, efa, tf)) {
01401                 if(uvedit_uv_selected(scene, efa, tf, 0)) {
01402                     uvav = uv_average + efa->v1->tmp.l;
01403                     uvav->count++;
01404                     uvav->uv[0] += tf->uv[0][0];
01405                     uvav->uv[1] += tf->uv[0][1];
01406                 }
01407 
01408                 if(uvedit_uv_selected(scene, efa, tf, 1)) {
01409                     uvav = uv_average + efa->v2->tmp.l;
01410                     uvav->count++;
01411                     uvav->uv[0] += tf->uv[1][0];
01412                     uvav->uv[1] += tf->uv[1][1];
01413                 }
01414 
01415                 if(uvedit_uv_selected(scene, efa, tf, 2)) {
01416                     uvav = uv_average + efa->v3->tmp.l;
01417                     uvav->count++;
01418                     uvav->uv[0] += tf->uv[2][0];
01419                     uvav->uv[1] += tf->uv[2][1];
01420                 }
01421 
01422                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
01423                     uvav = uv_average + efa->v4->tmp.l;
01424                     uvav->count++;
01425                     uvav->uv[0] += tf->uv[3][0];
01426                     uvav->uv[1] += tf->uv[3][1];
01427                 }
01428             }
01429         }
01430         
01431         // apply uv welding
01432         for(efa= em->faces.first; efa; efa= efa->next) {
01433             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01434 
01435             if(uvedit_face_visible(scene, ima, efa, tf)) {
01436                 if(uvedit_uv_selected(scene, efa, tf, 0)) {
01437                     uvav = uv_average + efa->v1->tmp.l;
01438                     tf->uv[0][0] = uvav->uv[0]/uvav->count;
01439                     tf->uv[0][1] = uvav->uv[1]/uvav->count;
01440                 }
01441 
01442                 if(uvedit_uv_selected(scene, efa, tf, 1)) {
01443                     uvav = uv_average + efa->v2->tmp.l;
01444                     tf->uv[1][0] = uvav->uv[0]/uvav->count;
01445                     tf->uv[1][1] = uvav->uv[1]/uvav->count;
01446                 }
01447 
01448                 if(uvedit_uv_selected(scene, efa, tf, 2)) {
01449                     uvav = uv_average + efa->v3->tmp.l;
01450                     tf->uv[2][0] = uvav->uv[0]/uvav->count;
01451                     tf->uv[2][1] = uvav->uv[1]/uvav->count;
01452                 }
01453 
01454                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
01455                     uvav = uv_average + efa->v4->tmp.l;
01456                     tf->uv[3][0] = uvav->uv[0]/uvav->count;
01457                     tf->uv[3][1] = uvav->uv[1]/uvav->count;
01458                 }
01459             }
01460         }
01461 
01462         MEM_freeN(uv_average);
01463     }
01464 
01465     uvedit_live_unwrap_update(sima, scene, obedit);
01466     DAG_id_tag_update(obedit->data, 0);
01467     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
01468 
01469     BKE_mesh_end_editmesh(obedit->data, em);
01470     return OPERATOR_FINISHED;
01471 }
01472 
01473 static void UV_OT_stitch(wmOperatorType *ot)
01474 {
01475     /* identifiers */
01476     ot->name= "Stitch";
01477     ot->description= "Stitch selected UV vertices by proximity";
01478     ot->idname= "UV_OT_stitch";
01479     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01480     
01481     /* api callbacks */
01482     ot->exec= stitch_exec;
01483     ot->poll= ED_operator_uvedit;
01484 
01485     /* properties */
01486     RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance");
01487     RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates", -FLT_MAX, FLT_MAX);
01488 }
01489 
01490 /* ******************** (de)select all operator **************** */
01491 
01492 static void select_all_perform(bContext *C, int action)
01493 {
01494     Scene *scene;
01495     ToolSettings *ts;
01496     Object *obedit;
01497     EditMesh *em;
01498     EditFace *efa;
01499     Image *ima;
01500     MTFace *tf;
01501     
01502     scene= CTX_data_scene(C);
01503     ts= CTX_data_tool_settings(C);
01504     obedit= CTX_data_edit_object(C);
01505     em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01506     ima= CTX_data_edit_image(C);
01507     
01508     if(ts->uv_flag & UV_SYNC_SELECTION) {
01509         switch (action) {
01510         case SEL_TOGGLE:
01511             EM_toggle_select_all(em);
01512             break;
01513         case SEL_SELECT:
01514             EM_select_all(em);
01515             break;
01516         case SEL_DESELECT:
01517             EM_deselect_all(em);
01518             break;
01519         case SEL_INVERT:
01520             EM_select_swap(em);
01521             break;
01522         }
01523     }
01524     else {
01525 
01526         if (action == SEL_TOGGLE) {
01527             action = SEL_SELECT;
01528             for(efa= em->faces.first; efa; efa= efa->next) {
01529                 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
01530                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01531 
01532                 if(uvedit_face_visible(scene, ima, efa, tf)) {
01533                     if(tf->flag & select_flag) {
01534                         action = SEL_DESELECT;
01535                         break;
01536                     }
01537                 }
01538             }
01539         }
01540     
01541         for(efa= em->faces.first; efa; efa= efa->next) {
01542             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01543 
01544             if(uvedit_face_visible(scene, ima, efa, tf)) {
01545                 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
01546 
01547                 switch (action) {
01548                 case SEL_SELECT:
01549                     tf->flag |= select_flag;
01550                     break;
01551                 case SEL_DESELECT:
01552                     tf->flag &= ~select_flag;
01553                     break;
01554                 case SEL_INVERT:
01555                     tf->flag ^= select_flag;
01556                     break;
01557                 }
01558             }
01559         }
01560     }
01561 }
01562 
01563 static int select_all_exec(bContext *C, wmOperator *op)
01564 {
01565     Object *obedit= CTX_data_edit_object(C);
01566     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01567     int action= RNA_enum_get(op->ptr, "action");
01568 
01569     select_all_perform(C, action);
01570 
01571     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
01572 
01573     BKE_mesh_end_editmesh(obedit->data, em);
01574     return OPERATOR_FINISHED;
01575 }
01576 
01577 static void UV_OT_select_all(wmOperatorType *ot)
01578 {
01579     /* identifiers */
01580     ot->name= "Select or Deselect All";
01581     ot->description= "Change selection of all UV vertices";
01582     ot->idname= "UV_OT_select_all";
01583     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01584     
01585     /* api callbacks */
01586     ot->exec= select_all_exec;
01587     ot->poll= ED_operator_uvedit;
01588 
01589     WM_operator_properties_select_all(ot);
01590 }
01591 
01592 /* ******************** mouse select operator **************** */
01593 
01594 static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky)
01595 {
01596     int i;
01597 
01598     /* this function test if some vertex needs to selected
01599      * in addition to the existing ones due to sticky select */
01600     if(sticky == SI_STICKY_DISABLE)
01601         return 0;
01602 
01603     for(i=0; i<4; i++) {
01604         if(hitv[i] == v) {
01605             if(sticky == SI_STICKY_LOC) {
01606                 if(fabsf(hituv[i][0]-uv[0]) < limit[0] && fabsf(hituv[i][1]-uv[1]) < limit[1])
01607                     return 1;
01608             }
01609             else if(sticky == SI_STICKY_VERTEX)
01610                 return 1;
01611         }
01612     }
01613 
01614     return 0;
01615 }
01616 
01617 static int mouse_select(bContext *C, float co[2], int extend, int loop)
01618 {
01619     SpaceImage *sima= CTX_wm_space_image(C);
01620     Scene *scene= CTX_data_scene(C);
01621     ToolSettings *ts= CTX_data_tool_settings(C);
01622     Object *obedit= CTX_data_edit_object(C);
01623     Image *ima= CTX_data_edit_image(C);
01624     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01625     EditFace *efa;
01626     MTFace *tf;
01627     NearestHit hit;
01628     int a, i, select = 1, selectmode, sticky, sync, hitv[4], nvert;
01629     int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel;  only use when selection sync is enabled */
01630     float limit[2], *hituv[4], penalty[2];
01631 
01632     /* notice 'limit' is the same no matter the zoom level, since this is like
01633      * remove doubles and could annoying if it joined points when zoomed out.
01634      * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and
01635      * shift-selecting can consider an adjacent point close enough to add to
01636      * the selection rather than de-selecting the closest. */
01637 
01638     uvedit_pixel_to_float(sima, limit, 0.05f);
01639     uvedit_pixel_to_float(sima, penalty, 5.0f / sima->zoom);
01640 
01641     /* retrieve operation mode */
01642     if(ts->uv_flag & UV_SYNC_SELECTION) {
01643         sync= 1;
01644 
01645         if(ts->selectmode & SCE_SELECT_FACE)
01646             selectmode= UV_SELECT_FACE;
01647         else if(ts->selectmode & SCE_SELECT_EDGE)
01648             selectmode= UV_SELECT_EDGE;
01649         else
01650             selectmode= UV_SELECT_VERTEX;
01651 
01652         sticky= SI_STICKY_DISABLE;
01653     }
01654     else {
01655         sync= 0;
01656         selectmode= ts->uv_selectmode;
01657         sticky= (sima)? sima->sticky: 1;
01658     }
01659 
01660     /* find nearest element */
01661     if(loop) {
01662         /* find edge */
01663         find_nearest_uv_edge(scene, ima, em, co, &hit);
01664         if(hit.efa == NULL) {
01665             BKE_mesh_end_editmesh(obedit->data, em);
01666             return OPERATOR_CANCELLED;
01667         }
01668     }
01669     else if(selectmode == UV_SELECT_VERTEX) {
01670         /* find vertex */
01671         find_nearest_uv_vert(scene, ima, em, co, penalty, &hit);
01672         if(hit.efa == NULL) {
01673             BKE_mesh_end_editmesh(obedit->data, em);
01674             return OPERATOR_CANCELLED;
01675         }
01676 
01677         /* mark 1 vertex as being hit */
01678         for(i=0; i<4; i++)
01679             hitv[i]= 0xFFFFFFFF;
01680 
01681         hitv[hit.uv]= hit.vert;
01682         hituv[hit.uv]= hit.tf->uv[hit.uv];
01683     }
01684     else if(selectmode == UV_SELECT_EDGE) {
01685         /* find edge */
01686         find_nearest_uv_edge(scene, ima, em, co, &hit);
01687         if(hit.efa == NULL) {
01688             BKE_mesh_end_editmesh(obedit->data, em);
01689             return OPERATOR_CANCELLED;
01690         }
01691 
01692         /* mark 2 edge vertices as being hit */
01693         for(i=0; i<4; i++)
01694             hitv[i]= 0xFFFFFFFF;
01695 
01696         nvert= (hit.efa->v4)? 4: 3;
01697 
01698         hitv[hit.edge]= hit.vert;
01699         hitv[(hit.edge+1)%nvert]= hit.vert2;
01700         hituv[hit.edge]= hit.tf->uv[hit.edge];
01701         hituv[(hit.edge+1)%nvert]= hit.tf->uv[(hit.edge+1)%nvert];
01702     }
01703     else if(selectmode == UV_SELECT_FACE) {
01704         /* find face */
01705         find_nearest_uv_face(scene, ima, em, co, &hit);
01706         if(hit.efa == NULL) {
01707             BKE_mesh_end_editmesh(obedit->data, em);
01708             return OPERATOR_CANCELLED;
01709         }
01710         
01711         /* make active */
01712         EM_set_actFace(em, hit.efa);
01713 
01714         /* mark all face vertices as being hit */
01715         for(i=0; i<4; i++)
01716             hituv[i]= hit.tf->uv[i];
01717 
01718         hitv[0]= hit.efa->v1->tmp.l;
01719         hitv[1]= hit.efa->v2->tmp.l;
01720         hitv[2]= hit.efa->v3->tmp.l;
01721         
01722         if(hit.efa->v4) hitv[3]= hit.efa->v4->tmp.l;
01723         else hitv[3]= 0xFFFFFFFF;
01724     }
01725     else if(selectmode == UV_SELECT_ISLAND) {
01726         find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
01727 
01728         if(hit.efa==NULL) {
01729             BKE_mesh_end_editmesh(obedit->data, em);
01730             return OPERATOR_CANCELLED;
01731         }
01732     }
01733     else {
01734         BKE_mesh_end_editmesh(obedit->data, em);
01735         return OPERATOR_CANCELLED;
01736     }
01737 
01738     /* do selection */
01739     if(loop) {
01740         flush= select_edgeloop(scene, ima, em, &hit, limit, extend);
01741     }
01742     else if(selectmode == UV_SELECT_ISLAND) {
01743         select_linked(scene, ima, em, limit, &hit, extend);
01744     }
01745     else if(extend) {
01746         if(selectmode == UV_SELECT_VERTEX) {
01747             /* (de)select uv vertex */
01748             if(uvedit_uv_selected(scene, hit.efa, hit.tf, hit.uv)) {
01749                 uvedit_uv_deselect(scene, hit.efa, hit.tf, hit.uv);
01750                 select= 0;
01751             }
01752             else {
01753                 uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
01754                 select= 1;
01755             }
01756             flush = 1;
01757         }
01758         else if(selectmode == UV_SELECT_EDGE) {
01759             /* (de)select edge */
01760             if(uvedit_edge_selected(scene, hit.efa, hit.tf, hit.edge)) {
01761                 uvedit_edge_deselect(scene, hit.efa, hit.tf, hit.edge);
01762                 select= 0;
01763             }
01764             else {
01765                 uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
01766                 select= 1;
01767             }
01768             flush = 1;
01769         }
01770         else if(selectmode == UV_SELECT_FACE) {
01771             /* (de)select face */
01772             if(uvedit_face_selected(scene, hit.efa, hit.tf)) {
01773                 uvedit_face_deselect(scene, hit.efa, hit.tf);
01774                 select= 0;
01775             }
01776             else {
01777                 uvedit_face_select(scene, hit.efa, hit.tf);
01778                 select= 1;
01779             }
01780             flush = -1;
01781         }
01782 
01783         /* (de)select sticky uv nodes */
01784         if(sticky != SI_STICKY_DISABLE) {
01785             EditVert *ev;
01786             
01787             for(a=0, ev=em->verts.first; ev; ev = ev->next, a++)
01788                 ev->tmp.l = a;
01789             
01790             /* deselect */
01791             if(select==0) {
01792                 for(efa= em->faces.first; efa; efa= efa->next) {
01793                     tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01794 
01795                     if(uvedit_face_visible(scene, ima, efa, tf)) {
01796                         if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
01797                             uvedit_uv_deselect(scene, efa, tf, 0);
01798                         if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
01799                             uvedit_uv_deselect(scene, efa, tf, 1);
01800                         if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
01801                             uvedit_uv_deselect(scene, efa, tf, 2);
01802                         if(efa->v4)
01803                             if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
01804                                 uvedit_uv_deselect(scene, efa, tf, 3);
01805                     }
01806                 }
01807                 flush = -1;
01808             }
01809             /* select */
01810             else {
01811                 for(efa= em->faces.first; efa; efa= efa->next) {
01812                     tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01813 
01814                     if(uvedit_face_visible(scene, ima, efa, tf)) {
01815                         if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
01816                             uvedit_uv_select(scene, efa, tf, 0);
01817                         if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
01818                             uvedit_uv_select(scene, efa, tf, 1);
01819                         if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
01820                             uvedit_uv_select(scene, efa, tf, 2);
01821                         if(efa->v4)
01822                             if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
01823                                 uvedit_uv_select(scene, efa, tf, 3);
01824                     }
01825                 }
01826                 
01827                 flush = 1;
01828             }           
01829         }
01830     }
01831     else {
01832         /* deselect all */
01833         for(efa= em->faces.first; efa; efa= efa->next) {
01834             tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01835             uvedit_face_deselect(scene, efa, tf);
01836         }
01837 
01838         if(selectmode == UV_SELECT_VERTEX) {
01839             /* select vertex */
01840             uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
01841             flush= 1;
01842         }
01843         else if(selectmode == UV_SELECT_EDGE) {
01844             /* select edge */
01845             uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
01846             flush= 1;
01847         }
01848         else if(selectmode == UV_SELECT_FACE) {
01849             /* select face */
01850             uvedit_face_select(scene, hit.efa, hit.tf);
01851         }
01852 
01853         /* select sticky uvs */
01854         if(sticky != SI_STICKY_DISABLE) {
01855             for(efa= em->faces.first; efa; efa= efa->next) {
01856                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
01857                 if(uvedit_face_visible(scene, ima, efa, tf)) {
01858                     if(sticky == SI_STICKY_DISABLE) continue;
01859 
01860                     if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
01861                         uvedit_uv_select(scene, efa, tf, 0);
01862                     if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
01863                         uvedit_uv_select(scene, efa, tf, 1);
01864                     if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
01865                         uvedit_uv_select(scene, efa, tf, 2);
01866                     if(efa->v4)
01867                         if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
01868                             uvedit_uv_select(scene, efa, tf, 3);
01869 
01870                     flush= 1;
01871                 }
01872             }
01873         }
01874     }
01875     
01876     if(sync) {
01877         /* flush for mesh selection */
01878         if(ts->selectmode != SCE_SELECT_FACE) {
01879             if(flush==1)        EM_select_flush(em);
01880             else if(flush==-1)  EM_deselect_flush(em);
01881         }
01882     }
01883     
01884     DAG_id_tag_update(obedit->data, 0);
01885     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
01886     
01887     BKE_mesh_end_editmesh(obedit->data, em);
01888     return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
01889 }
01890 
01891 static int select_exec(bContext *C, wmOperator *op)
01892 {
01893     float co[2];
01894     int extend, loop;
01895 
01896     RNA_float_get_array(op->ptr, "location", co);
01897     extend= RNA_boolean_get(op->ptr, "extend");
01898     loop= 0;
01899 
01900     return mouse_select(C, co, extend, loop);
01901 }
01902 
01903 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
01904 {
01905     ARegion *ar= CTX_wm_region(C);
01906     float co[2];
01907 
01908     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
01909     RNA_float_set_array(op->ptr, "location", co);
01910 
01911     return select_exec(C, op);
01912 }
01913 
01914 static void UV_OT_select(wmOperatorType *ot)
01915 {
01916     /* identifiers */
01917     ot->name= "Select";
01918     ot->description= "Select UV vertices";
01919     ot->idname= "UV_OT_select";
01920     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01921     
01922     /* api callbacks */
01923     ot->exec= select_exec;
01924     ot->invoke= select_invoke;
01925     ot->poll= ED_operator_image_active; /* requires space image */;
01926 
01927     /* properties */
01928     RNA_def_boolean(ot->srna, "extend", 0,
01929         "Extend", "Extend selection rather than clearing the existing selection");
01930     RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
01931         "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
01932 }
01933 
01934 /* ******************** loop select operator **************** */
01935 
01936 static int select_loop_exec(bContext *C, wmOperator *op)
01937 {
01938     float co[2];
01939     int extend, loop;
01940 
01941     RNA_float_get_array(op->ptr, "location", co);
01942     extend= RNA_boolean_get(op->ptr, "extend");
01943     loop= 1;
01944 
01945     return mouse_select(C, co, extend, loop);
01946 }
01947 
01948 static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
01949 {
01950     ARegion *ar= CTX_wm_region(C);
01951     float co[2];
01952 
01953     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
01954     RNA_float_set_array(op->ptr, "location", co);
01955 
01956     return select_loop_exec(C, op);
01957 }
01958 
01959 static void UV_OT_select_loop(wmOperatorType *ot)
01960 {
01961     /* identifiers */
01962     ot->name= "Loop Select";
01963     ot->description= "Select a loop of connected UV vertices";
01964     ot->idname= "UV_OT_select_loop";
01965     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01966     
01967     /* api callbacks */
01968     ot->exec= select_loop_exec;
01969     ot->invoke= select_loop_invoke;
01970     ot->poll= ED_operator_image_active; /* requires space image */;
01971 
01972     /* properties */
01973     RNA_def_boolean(ot->srna, "extend", 0,
01974         "Extend", "Extend selection rather than clearing the existing selection");
01975     RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
01976         "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
01977 }
01978 
01979 /* ******************** linked select operator **************** */
01980 
01981 static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, int pick)
01982 {
01983     SpaceImage *sima= CTX_wm_space_image(C);
01984     Scene *scene= CTX_data_scene(C);
01985     ToolSettings *ts= CTX_data_tool_settings(C);
01986     Object *obedit= CTX_data_edit_object(C);
01987     Image *ima= CTX_data_edit_image(C);
01988     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
01989     float limit[2];
01990     int extend;
01991 
01992     NearestHit hit, *hit_p= NULL;
01993 
01994     if(ts->uv_flag & UV_SYNC_SELECTION) {
01995         BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled");
01996         BKE_mesh_end_editmesh(obedit->data, em);
01997         return OPERATOR_CANCELLED;
01998     }
01999 
02000     extend= RNA_boolean_get(op->ptr, "extend");
02001     uvedit_pixel_to_float(sima, limit, 0.05f);
02002 
02003     if(pick) {
02004         float co[2];
02005 
02006         if(event) {
02007             /* invoke */
02008             ARegion *ar= CTX_wm_region(C);
02009 
02010             UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
02011             RNA_float_set_array(op->ptr, "location", co);
02012         }
02013         else {
02014             /* exec */
02015             RNA_float_get_array(op->ptr, "location", co);
02016         }
02017 
02018         find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
02019         hit_p= &hit;
02020     }
02021 
02022     select_linked(scene, ima, em, limit, hit_p, extend);
02023 
02024     DAG_id_tag_update(obedit->data, 0);
02025     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02026 
02027     BKE_mesh_end_editmesh(obedit->data, em);
02028     return OPERATOR_FINISHED;
02029 }
02030 
02031 static int select_linked_exec(bContext *C, wmOperator *op)
02032 {
02033     return select_linked_internal(C, op, NULL, 0);
02034 }
02035 
02036 static void UV_OT_select_linked(wmOperatorType *ot)
02037 {
02038     /* identifiers */
02039     ot->name= "Select Linked";
02040     ot->description= "Select all UV vertices linked to the active UV map";
02041     ot->idname= "UV_OT_select_linked";
02042     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02043     
02044     /* api callbacks */
02045     ot->exec= select_linked_exec;
02046     ot->poll= ED_operator_image_active; /* requires space image */
02047 
02048     /* properties */
02049     RNA_def_boolean(ot->srna, "extend", 0,
02050         "Extend", "Extend selection rather than clearing the existing selection");
02051 }
02052 
02053 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
02054 {
02055     return select_linked_internal(C, op, event, 1);
02056 }
02057 
02058 static int select_linked_pick_exec(bContext *C, wmOperator *op)
02059 {
02060     return select_linked_internal(C, op, NULL, 1);
02061 }
02062 
02063 static void UV_OT_select_linked_pick(wmOperatorType *ot)
02064 {
02065     /* identifiers */
02066     ot->name= "Select Linked Pick";
02067     ot->description= "Select all UV vertices linked under the mouse";
02068     ot->idname= "UV_OT_select_linked_pick";
02069     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02070 
02071     /* api callbacks */
02072     ot->invoke= select_linked_pick_invoke;
02073     ot->exec= select_linked_pick_exec;
02074     ot->poll= ED_operator_image_active; /* requires space image */;
02075 
02076     /* properties */
02077     RNA_def_boolean(ot->srna, "extend", 0,
02078         "Extend", "Extend selection rather than clearing the existing selection");
02079 
02080     RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
02081         "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
02082 }
02083 
02084 /* ******************** unlink selection operator **************** */
02085 
02086 static int unlink_selection_exec(bContext *C, wmOperator *op)
02087 {
02088     Scene *scene= CTX_data_scene(C);
02089     ToolSettings *ts= CTX_data_tool_settings(C);
02090     Object *obedit= CTX_data_edit_object(C);
02091     Image *ima= CTX_data_edit_image(C);
02092     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02093     EditFace *efa;
02094     MTFace *tf;
02095 
02096     if(ts->uv_flag & UV_SYNC_SELECTION) {
02097         BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled");
02098         BKE_mesh_end_editmesh(obedit->data, em);
02099         return OPERATOR_CANCELLED;
02100     }
02101     
02102     for(efa= em->faces.first; efa; efa= efa->next) {
02103         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02104 
02105         if(uvedit_face_visible(scene, ima, efa, tf)) {
02106             const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
02107             if(~tf->flag & select_flag)
02108                 tf->flag &= ~select_flag;
02109 
02110         }
02111     }
02112     
02113     DAG_id_tag_update(obedit->data, 0);
02114     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02115 
02116     BKE_mesh_end_editmesh(obedit->data, em);
02117     return OPERATOR_FINISHED;
02118 }
02119 
02120 static void UV_OT_unlink_selected(wmOperatorType *ot)
02121 {
02122     /* identifiers */
02123     ot->name= "Unlink Selection";
02124     ot->description= "Unlink selected UV vertices from active UV map";
02125     ot->idname= "UV_OT_unlink_selected";
02126     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02127     
02128     /* api callbacks */
02129     ot->exec= unlink_selection_exec;
02130     ot->poll= ED_operator_uvedit;
02131 }
02132 
02133 /* ******************** border select operator **************** */
02134 
02135 /* This function sets the selection on tagged faces, need because settings the
02136  * selection a face is done in a number of places but it also needs to respect
02137  * the sticky modes for the UV verts, so dealing with the sticky modes is best
02138  * done in a separate function.
02139  * 
02140  * De-selects faces that have been tagged on efa->tmp.l.  */
02141 
02142 static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select)
02143 {
02144     /* Selecting UV Faces with some modes requires us to change 
02145      * the selection in other faces (depending on the sticky mode).
02146      * 
02147      * This only needs to be done when the Mesh is not used for
02148      * selection (so for sticky modes, vertex or location based). */
02149     
02150     ToolSettings *ts= CTX_data_tool_settings(C);
02151     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02152     EditFace *efa;
02153     MTFace *tf;
02154     int nverts, i;
02155     
02156     if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_VERTEX) {
02157         /* Tag all verts as untouched, then touch the ones that have a face center
02158          * in the loop and select all MTFace UV's that use a touched vert. */
02159         EditVert *eve;
02160         
02161         for(eve= em->verts.first; eve; eve= eve->next)
02162             eve->tmp.l = 0;
02163         
02164         for(efa= em->faces.first; efa; efa= efa->next) {
02165             if(efa->tmp.l) {
02166                 if(efa->v4)
02167                     efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= efa->v4->tmp.l=1;
02168                 else
02169                     efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= 1;
02170             }
02171         }
02172 
02173         /* now select tagged verts */
02174         for(efa= em->faces.first; efa; efa= efa->next) {
02175             tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);       
02176             nverts= efa->v4? 4: 3;
02177             for(i=0; i<nverts; i++) {
02178                 if((*(&efa->v1 + i))->tmp.l) {
02179                     if(select)
02180                         uvedit_uv_select(scene, efa, tf, i);
02181                     else
02182                         uvedit_uv_deselect(scene, efa, tf, i);
02183                 }
02184             }
02185         }
02186     }
02187     else if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_LOC) {
02188         EditFace *efa_vlist;
02189         MTFace *tf_vlist;
02190         UvMapVert *start_vlist=NULL, *vlist_iter;
02191         struct UvVertMap *vmap;
02192         float limit[2];
02193         unsigned int efa_index;
02194         //EditVert *eve; /* removed vert counting for now */ 
02195         //int a;
02196         
02197         uvedit_pixel_to_float(sima, limit, 0.05);
02198         
02199         EM_init_index_arrays(em, 0, 0, 1);
02200         vmap= EM_make_uv_vert_map(em, 0, 0, limit);
02201         
02202         /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
02203         /*for(a=0, eve= em->verts.first; eve; a++, eve= eve->next)
02204             eve->tmp.l = a; */
02205         
02206         if(vmap == NULL) {
02207             BKE_mesh_end_editmesh(obedit->data, em);
02208             return;
02209         }
02210         
02211         for(efa_index=0, efa= em->faces.first; efa; efa_index++, efa= efa->next) {
02212             if(efa->tmp.l) {
02213                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02214                 nverts= efa->v4? 4: 3;
02215 
02216                 for(i=0; i<nverts; i++) {
02217                     if(select)
02218                         uvedit_uv_select(scene, efa, tf, i);
02219                     else
02220                         uvedit_uv_deselect(scene, efa, tf, i);
02221                     
02222                     vlist_iter= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
02223                     
02224                     while (vlist_iter) {
02225                         if(vlist_iter->separate)
02226                             start_vlist = vlist_iter;
02227                         
02228                         if(efa_index == vlist_iter->f)
02229                             break;
02230 
02231                         vlist_iter = vlist_iter->next;
02232                     }
02233                 
02234                     vlist_iter = start_vlist;
02235                     while (vlist_iter) {
02236                         
02237                         if(vlist_iter != start_vlist && vlist_iter->separate)
02238                             break;
02239                         
02240                         if(efa_index != vlist_iter->f) {
02241                             efa_vlist = EM_get_face_for_index(vlist_iter->f);
02242                             tf_vlist = CustomData_em_get(&em->fdata, efa_vlist->data, CD_MTFACE);
02243                             
02244                             if(select)
02245                                 uvedit_uv_select(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
02246                             else
02247                                 uvedit_uv_deselect(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
02248                         }
02249                         vlist_iter = vlist_iter->next;
02250                     }
02251                 }
02252             }
02253         }
02254         EM_free_index_arrays();
02255         EM_free_uv_vert_map(vmap);
02256         
02257     }
02258     else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
02259         for(efa= em->faces.first; efa; efa= efa->next) {
02260             if(efa->tmp.l) {
02261                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02262                 if(select)
02263                     uvedit_face_select(scene, efa, tf);
02264                 else
02265                     uvedit_face_deselect(scene, efa, tf);
02266             }
02267         }
02268     }
02269     BKE_mesh_end_editmesh(obedit->data, em);
02270 }
02271 
02272 static int border_select_exec(bContext *C, wmOperator *op)
02273 {
02274     SpaceImage *sima= CTX_wm_space_image(C);
02275     Scene *scene= CTX_data_scene(C);
02276     ToolSettings *ts= CTX_data_tool_settings(C);
02277     Object *obedit= CTX_data_edit_object(C);
02278     Image *ima= CTX_data_edit_image(C);
02279     ARegion *ar= CTX_wm_region(C);
02280     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02281     EditFace *efa;
02282     MTFace *tface;
02283     rcti rect;
02284     rctf rectf;
02285     int change, pinned, select, faces, extend;
02286 
02287     /* get rectangle from operator */
02288     rect.xmin= RNA_int_get(op->ptr, "xmin");
02289     rect.ymin= RNA_int_get(op->ptr, "ymin");
02290     rect.xmax= RNA_int_get(op->ptr, "xmax");
02291     rect.ymax= RNA_int_get(op->ptr, "ymax");
02292         
02293     UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
02294     UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
02295 
02296     /* figure out what to select/deselect */
02297     select= (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
02298     pinned= RNA_boolean_get(op->ptr, "pinned");
02299     extend= RNA_boolean_get(op->ptr, "extend");
02300 
02301     if(!extend)
02302         select_all_perform(C, SEL_DESELECT);
02303     
02304     if(ts->uv_flag & UV_SYNC_SELECTION)
02305         faces= (ts->selectmode == SCE_SELECT_FACE);
02306     else
02307         faces= (ts->uv_selectmode == UV_SELECT_FACE);
02308 
02309     /* do actual selection */
02310     if(faces && !pinned) {
02311         /* handle face selection mode */
02312         float cent[2];
02313 
02314         change= 0;
02315 
02316         for(efa= em->faces.first; efa; efa= efa->next) {
02317             /* assume not touched */
02318             efa->tmp.l = 0;
02319             tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02320             if(uvedit_face_visible(scene, ima, efa, tface)) {
02321                 uv_center(tface->uv, cent, efa->v4 != NULL);
02322                 if(BLI_in_rctf(&rectf, cent[0], cent[1])) {
02323                     efa->tmp.l = change = 1;
02324                 }
02325             }
02326         }
02327 
02328         /* (de)selects all tagged faces and deals with sticky modes */
02329         if(change)
02330             uv_faces_do_sticky(C, sima, scene, obedit, select);
02331     }
02332     else {
02333         /* other selection modes */
02334         change= 1;
02335 
02336         for(efa= em->faces.first; efa; efa= efa->next) {
02337             tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02338             if(uvedit_face_visible(scene, ima, efa, tface)) {
02339                 if(!pinned || (ts->uv_flag & UV_SYNC_SELECTION) ) {
02340                     /* UV_SYNC_SELECTION - can't do pinned selection */
02341                     if(BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
02342                         if(select)  uvedit_uv_select(scene, efa, tface, 0);
02343                         else        uvedit_uv_deselect(scene, efa, tface, 0);
02344                     }
02345                     if(BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
02346                         if(select)  uvedit_uv_select(scene, efa, tface, 1);
02347                         else        uvedit_uv_deselect(scene, efa, tface, 1);
02348                     }
02349                     if(BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
02350                         if(select)  uvedit_uv_select(scene, efa, tface, 2);
02351                         else        uvedit_uv_deselect(scene, efa, tface, 2);
02352                     }
02353                     if(efa->v4 && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
02354                         if(select)  uvedit_uv_select(scene, efa, tface, 3);
02355                         else        uvedit_uv_deselect(scene, efa, tface, 3);
02356                     }
02357                 }
02358                 else if(pinned) {
02359                     if((tface->unwrap & TF_PIN1) && 
02360                         BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
02361                         
02362                         if(select)  uvedit_uv_select(scene, efa, tface, 0);
02363                         else        uvedit_uv_deselect(scene, efa, tface, 0);
02364                     }
02365                     if((tface->unwrap & TF_PIN2) && 
02366                         BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
02367                         
02368                         if(select)  uvedit_uv_select(scene, efa, tface, 1);
02369                         else        uvedit_uv_deselect(scene, efa, tface, 1);
02370                     }
02371                     if((tface->unwrap & TF_PIN3) && 
02372                         BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
02373                         
02374                         if(select)  uvedit_uv_select(scene, efa, tface, 2);
02375                         else        uvedit_uv_deselect(scene, efa, tface, 2);
02376                     }
02377                     if((efa->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
02378                         if(select)  uvedit_uv_select(scene, efa, tface, 3);
02379                         else        uvedit_uv_deselect(scene, efa, tface, 3);
02380                     }
02381                 }
02382             }
02383         }
02384     }
02385 
02386     if(change) {
02387         /* make sure newly selected vert selection is updated*/
02388         if(ts->uv_flag & UV_SYNC_SELECTION) {
02389             if(ts->selectmode != SCE_SELECT_FACE) {
02390                 if(select)  EM_select_flush(em);
02391                 else        EM_deselect_flush(em);
02392             }
02393         }
02394 
02395         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02396         
02397         BKE_mesh_end_editmesh(obedit->data, em);
02398         return OPERATOR_FINISHED;
02399     }
02400     
02401     BKE_mesh_end_editmesh(obedit->data, em);
02402     return OPERATOR_CANCELLED;
02403 } 
02404 
02405 static void UV_OT_select_border(wmOperatorType *ot)
02406 {
02407     /* identifiers */
02408     ot->name= "Border Select";
02409     ot->description= "Select UV vertices using border selection";
02410     ot->idname= "UV_OT_select_border";
02411     
02412     /* api callbacks */
02413     ot->invoke= WM_border_select_invoke;
02414     ot->exec= border_select_exec;
02415     ot->modal= WM_border_select_modal;
02416     ot->poll= ED_operator_image_active; /* requires space image */;
02417     ot->cancel= WM_border_select_cancel;
02418     
02419     /* flags */
02420     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02421     
02422     /* properties */
02423     RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only");
02424 
02425     WM_operator_properties_gesture_border(ot, TRUE);
02426 }
02427 
02428 /* ******************** circle select operator **************** */
02429 
02430 static void select_uv_inside_ellipse(Scene *scene, int select, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, int select_index)
02431 {
02432     /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
02433     float x, y, r2, *uv;
02434     
02435     uv= tface->uv[index];
02436 
02437     x= (uv[0] - offset[0])*ell[0];
02438     y= (uv[1] - offset[1])*ell[1];
02439 
02440     r2 = x*x + y*y;
02441     if(r2 < 1.0f) {
02442         if(select)  uvedit_uv_select(scene, efa, tface, select_index);
02443         else uvedit_uv_deselect(scene, efa, tface, select_index);
02444     }
02445 }
02446 
02447 static int circle_select_exec(bContext *C, wmOperator *op)
02448 {
02449     SpaceImage *sima= CTX_wm_space_image(C);
02450     Scene *scene= CTX_data_scene(C);
02451     Object *obedit= CTX_data_edit_object(C);
02452     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02453     ARegion *ar= CTX_wm_region(C);
02454     EditFace *efa;
02455     MTFace *tface;
02456     int x, y, radius, width, height, select;
02457     float zoomx, zoomy, offset[2], ellipse[2];
02458     int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
02459 
02460     /* get operator properties */
02461     select= (gesture_mode == GESTURE_MODAL_SELECT);
02462     x= RNA_int_get(op->ptr, "x");
02463     y= RNA_int_get(op->ptr, "y");
02464     radius= RNA_int_get(op->ptr, "radius");
02465 
02466     /* compute ellipse size and location, not a circle since we deal
02467      * with non square image. ellipse is normalized, r = 1.0. */
02468     ED_space_image_size(sima, &width, &height);
02469     ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
02470 
02471     ellipse[0]= width*zoomx/radius;
02472     ellipse[1]= height*zoomy/radius;
02473 
02474     UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
02475     
02476     /* do selection */
02477     for(efa= em->faces.first; efa; efa= efa->next) {
02478         tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02479         select_uv_inside_ellipse(scene, select, efa, tface, 0, offset, ellipse, 0);
02480         select_uv_inside_ellipse(scene, select, efa, tface, 1, offset, ellipse, 1);
02481         select_uv_inside_ellipse(scene, select, efa, tface, 2, offset, ellipse, 2);
02482         if(efa->v4)
02483             select_uv_inside_ellipse(scene, select, efa, tface, 3, offset, ellipse, 3);
02484     }
02485 
02486     if(select) EM_select_flush(em);
02487     else EM_deselect_flush(em);
02488 
02489     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02490 
02491     BKE_mesh_end_editmesh(obedit->data, em);
02492     return OPERATOR_FINISHED;
02493 }
02494 
02495 static void UV_OT_circle_select(wmOperatorType *ot)
02496 {
02497     /* identifiers */
02498     ot->name= "Circle Select";
02499     ot->description= "Select UV vertices using circle selection";
02500     ot->idname= "UV_OT_circle_select";
02501     
02502     /* api callbacks */
02503     ot->invoke= WM_gesture_circle_invoke;
02504     ot->modal= WM_gesture_circle_modal;
02505     ot->exec= circle_select_exec;
02506     ot->poll= ED_operator_image_active; /* requires space image */;
02507     ot->cancel= WM_gesture_circle_cancel;
02508     
02509     /* flags */
02510     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02511     
02512     /* properties */
02513     RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
02514     RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
02515     RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
02516     RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
02517 }
02518 
02519 /* ******************** snap cursor operator **************** */
02520 
02521 static void snap_uv_to_pixel(float *uvco, float w, float h)
02522 {
02523     uvco[0] = ((float)((int)((uvco[0]*w) + 0.5f)))/w;
02524     uvco[1] = ((float)((int)((uvco[1]*h) + 0.5f)))/h;
02525 }
02526 
02527 static void snap_cursor_to_pixels(SpaceImage *sima)
02528 {
02529     int width= 0, height= 0;
02530 
02531     ED_space_image_size(sima, &width, &height);
02532     snap_uv_to_pixel(sima->cursor, width, height);
02533 }
02534 
02535 static int snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
02536 {
02537     return uvedit_center(scene, ima, obedit, sima->cursor, sima->around);
02538 }
02539 
02540 static int snap_cursor_exec(bContext *C, wmOperator *op)
02541 {
02542     SpaceImage *sima= CTX_wm_space_image(C);
02543     Scene *scene= CTX_data_scene(C);
02544     Object *obedit= CTX_data_edit_object(C);
02545     Image *ima= CTX_data_edit_image(C);
02546     int change= 0;
02547 
02548     switch(RNA_enum_get(op->ptr, "target")) {
02549         case 0:
02550             snap_cursor_to_pixels(sima);
02551             change= 1;
02552             break;
02553         case 1:
02554             change= snap_cursor_to_selection(scene, ima, obedit, sima);
02555             break;
02556     }
02557 
02558     if(!change)
02559         return OPERATOR_CANCELLED;
02560     
02561     WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, sima);
02562 
02563     return OPERATOR_FINISHED;
02564 }
02565 
02566 static void UV_OT_snap_cursor(wmOperatorType *ot)
02567 {
02568     static EnumPropertyItem target_items[] = {
02569         {0, "PIXELS", 0, "Pixels", ""},
02570         {1, "SELECTED", 0, "Selected", ""},
02571         {0, NULL, 0, NULL, NULL}};
02572 
02573     /* identifiers */
02574     ot->name= "Snap Cursor";
02575     ot->description= "Snap cursor to target type";
02576     ot->idname= "UV_OT_snap_cursor";
02577     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02578     
02579     /* api callbacks */
02580     ot->exec= snap_cursor_exec;
02581     ot->poll= ED_operator_image_active; /* requires space image */;
02582 
02583     /* properties */
02584     RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
02585 }
02586 
02587 /* ******************** snap selection operator **************** */
02588 
02589 static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
02590 {
02591     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02592     EditFace *efa;
02593     MTFace *tface;
02594     short change= 0;
02595 
02596     for(efa= em->faces.first; efa; efa= efa->next) {
02597         tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02598         if(uvedit_face_visible(scene, ima, efa, tface)) {
02599             if(uvedit_uv_selected(scene, efa, tface, 0))        copy_v2_v2(tface->uv[0], sima->cursor);
02600             if(uvedit_uv_selected(scene, efa, tface, 1))        copy_v2_v2(tface->uv[1], sima->cursor);
02601             if(uvedit_uv_selected(scene, efa, tface, 2))        copy_v2_v2(tface->uv[2], sima->cursor);
02602             if(efa->v4)
02603                 if(uvedit_uv_selected(scene, efa, tface, 3))    copy_v2_v2(tface->uv[3], sima->cursor);
02604 
02605             change= 1;
02606         }
02607     }
02608 
02609     BKE_mesh_end_editmesh(obedit->data, em);
02610     return change;
02611 }
02612 
02613 static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
02614 {
02615     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02616     EditFace *efa;
02617     EditVert *eve;
02618     MTFace *tface;
02619     short change = 0;
02620     int count = 0;
02621     float *coords;
02622     short *usercount, users;
02623     
02624     /* set all verts to -1 : an unused index*/
02625     for(eve= em->verts.first; eve; eve= eve->next)
02626         eve->tmp.l=-1;
02627     
02628     /* index every vert that has a selected UV using it, but only once so as to
02629      * get unique indices and to count how much to malloc */
02630     for(efa= em->faces.first; efa; efa= efa->next) {
02631         tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02632 
02633         if(uvedit_face_visible(scene, ima, efa, tface)) {
02634             if(uvedit_uv_selected(scene, efa, tface, 0) && efa->v1->tmp.l==-1)      efa->v1->tmp.l= count++;
02635             if(uvedit_uv_selected(scene, efa, tface, 1) && efa->v2->tmp.l==-1)      efa->v2->tmp.l= count++;
02636             if(uvedit_uv_selected(scene, efa, tface, 2) && efa->v3->tmp.l==-1)      efa->v3->tmp.l= count++;
02637             if(efa->v4)
02638                 if(uvedit_uv_selected(scene, efa, tface, 3) && efa->v4->tmp.l==-1)  efa->v4->tmp.l= count++;
02639 
02640             change = 1;
02641             
02642             /* optional speedup */
02643             efa->tmp.p = tface;
02644         }
02645         else
02646             efa->tmp.p = NULL;
02647     }
02648     
02649     coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
02650     usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
02651     
02652     /* add all UV coords from visible, unselected UV coords as well as counting them to average later */
02653     for(efa= em->faces.first; efa; efa= efa->next) {
02654         if((tface=(MTFace *)efa->tmp.p)) {
02655             /* is this an unselected UV we can snap to? */
02656             if(efa->v1->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 0))) {
02657                 coords[efa->v1->tmp.l*2] +=     tface->uv[0][0];
02658                 coords[(efa->v1->tmp.l*2)+1] += tface->uv[0][1];
02659                 usercount[efa->v1->tmp.l]++;
02660                 change = 1;
02661             }
02662             if(efa->v2->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 1))) {
02663                 coords[efa->v2->tmp.l*2] +=     tface->uv[1][0];
02664                 coords[(efa->v2->tmp.l*2)+1] += tface->uv[1][1];
02665                 usercount[efa->v2->tmp.l]++;
02666                 change = 1;
02667             }
02668             if(efa->v3->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 2))) {
02669                 coords[efa->v3->tmp.l*2] +=     tface->uv[2][0];
02670                 coords[(efa->v3->tmp.l*2)+1] += tface->uv[2][1];
02671                 usercount[efa->v3->tmp.l]++;
02672                 change = 1;
02673             }
02674             
02675             if(efa->v4) {
02676                 if(efa->v4->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 3))) {
02677                     coords[efa->v4->tmp.l*2] +=     tface->uv[3][0];
02678                     coords[(efa->v4->tmp.l*2)+1] += tface->uv[3][1];
02679                     usercount[efa->v4->tmp.l]++;
02680                     change = 1;
02681                 }
02682             }
02683         }
02684     }
02685     
02686     /* no other verts selected, bail out */
02687     if(!change) {
02688         MEM_freeN(coords);
02689         MEM_freeN(usercount);
02690         BKE_mesh_end_editmesh(obedit->data, em);
02691         return change;
02692     }
02693     
02694     /* copy the averaged unselected UVs back to the selected UVs */
02695     for(efa= em->faces.first; efa; efa= efa->next) {
02696         if((tface=(MTFace *)efa->tmp.p)) {
02697             
02698             if( uvedit_uv_selected(scene, efa, tface, 0) &&
02699                     efa->v1->tmp.l >= 0 &&
02700                     (users = usercount[efa->v1->tmp.l])
02701             ) {
02702                 tface->uv[0][0] = coords[efa->v1->tmp.l*2]      / users;
02703                 tface->uv[0][1] = coords[(efa->v1->tmp.l*2)+1]  / users;
02704             }
02705 
02706             if( uvedit_uv_selected(scene, efa, tface, 1) &&
02707                     efa->v2->tmp.l >= 0 &&
02708                     (users = usercount[efa->v2->tmp.l])
02709             ) {
02710                 tface->uv[1][0] = coords[efa->v2->tmp.l*2]      / users;
02711                 tface->uv[1][1] = coords[(efa->v2->tmp.l*2)+1]  / users;
02712             }
02713             
02714             if( uvedit_uv_selected(scene, efa, tface, 2) &&
02715                     efa->v3->tmp.l >= 0 &&
02716                     (users = usercount[efa->v3->tmp.l])
02717             ) {
02718                 tface->uv[2][0] = coords[efa->v3->tmp.l*2]      / users;
02719                 tface->uv[2][1] = coords[(efa->v3->tmp.l*2)+1]  / users;
02720             }
02721             
02722             if(efa->v4) {
02723                 if( uvedit_uv_selected(scene, efa, tface, 3) &&
02724                         efa->v4->tmp.l >= 0 &&
02725                         (users = usercount[efa->v4->tmp.l])
02726                 ) {
02727                     tface->uv[3][0] = coords[efa->v4->tmp.l*2]      / users;
02728                     tface->uv[3][1] = coords[(efa->v4->tmp.l*2)+1]  / users;
02729                 }
02730             }
02731         }
02732     }
02733     
02734     MEM_freeN(coords);
02735     MEM_freeN(usercount);
02736 
02737     BKE_mesh_end_editmesh(obedit->data, em);
02738     return change;
02739 }
02740 
02741 static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
02742 {
02743     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02744     Image *ima;
02745     EditFace *efa;
02746     MTFace *tface;
02747     int width= 0, height= 0;
02748     float w, h;
02749     short change = 0;
02750 
02751     if(!sima)
02752         return 0;
02753     
02754     ima= sima->image;
02755     
02756     ED_space_image_size(sima, &width, &height);
02757     w = (float)width;
02758     h = (float)height;
02759     
02760     for(efa= em->faces.first; efa; efa= efa->next) {
02761         tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02762         if(uvedit_face_visible(scene, ima, efa, tface)) {
02763             if(uvedit_uv_selected(scene, efa, tface, 0)) snap_uv_to_pixel(tface->uv[0], w, h);
02764             if(uvedit_uv_selected(scene, efa, tface, 1)) snap_uv_to_pixel(tface->uv[1], w, h);
02765             if(uvedit_uv_selected(scene, efa, tface, 2)) snap_uv_to_pixel(tface->uv[2], w, h);
02766             if(efa->v4)
02767                 if(uvedit_uv_selected(scene, efa, tface, 3)) snap_uv_to_pixel(tface->uv[3], w, h);
02768 
02769             change = 1;
02770         }
02771     }
02772 
02773     BKE_mesh_end_editmesh(obedit->data, em);
02774     return change;
02775 }
02776 
02777 static int snap_selection_exec(bContext *C, wmOperator *op)
02778 {
02779     SpaceImage *sima= CTX_wm_space_image(C);
02780     Scene *scene= CTX_data_scene(C);
02781     Object *obedit= CTX_data_edit_object(C);
02782     Image *ima= CTX_data_edit_image(C);
02783     int change= 0;
02784 
02785     switch(RNA_enum_get(op->ptr, "target")) {
02786         case 0:
02787             change= snap_uvs_to_pixels(sima, scene, obedit);
02788             break;
02789         case 1:
02790             change= snap_uvs_to_cursor(scene, ima, obedit, sima);
02791             break;
02792         case 2:
02793             change= snap_uvs_to_adjacent_unselected(scene, ima, obedit);
02794             break;
02795     }
02796 
02797     if(!change)
02798         return OPERATOR_CANCELLED;
02799 
02800     uvedit_live_unwrap_update(sima, scene, obedit);
02801     DAG_id_tag_update(obedit->data, 0);
02802     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
02803 
02804     return OPERATOR_FINISHED;
02805 }
02806 
02807 static void UV_OT_snap_selected(wmOperatorType *ot)
02808 {
02809     static EnumPropertyItem target_items[] = {
02810         {0, "PIXELS", 0, "Pixels", ""},
02811         {1, "CURSOR", 0, "Cursor", ""},
02812         {2, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
02813         {0, NULL, 0, NULL, NULL}};
02814 
02815     /* identifiers */
02816     ot->name= "Snap Selection";
02817     ot->description= "Snap selected UV vertices to target type";
02818     ot->idname= "UV_OT_snap_selected";
02819     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02820     
02821     /* api callbacks */
02822     ot->exec= snap_selection_exec;
02823     ot->poll= ED_operator_image_active; /* requires space image */;
02824 
02825     /* properties */
02826     RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UVs to");
02827 }
02828 
02829 /* ******************** pin operator **************** */
02830 
02831 static int pin_exec(bContext *C, wmOperator *op)
02832 {
02833     Scene *scene= CTX_data_scene(C);
02834     Object *obedit= CTX_data_edit_object(C);
02835     Image *ima= CTX_data_edit_image(C);
02836     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02837     EditFace *efa;
02838     MTFace *tface;
02839     int clear= RNA_boolean_get(op->ptr, "clear");
02840     
02841     for(efa= em->faces.first; efa; efa= efa->next) {
02842         tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02843 
02844         if(uvedit_face_visible(scene, ima, efa, tface)) {
02845             if(!clear) {
02846                 if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap |= TF_PIN1;
02847                 if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap |= TF_PIN2;
02848                 if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap |= TF_PIN3;
02849                 if(efa->v4)
02850                     if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap |= TF_PIN4;
02851             }
02852             else {
02853                 if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap &= ~TF_PIN1;
02854                 if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap &= ~TF_PIN2;
02855                 if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap &= ~TF_PIN3;
02856                 if(efa->v4)
02857                     if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap &= ~TF_PIN4;
02858             }
02859         }
02860     }
02861     
02862     WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
02863 
02864     BKE_mesh_end_editmesh(obedit->data, em);
02865     return OPERATOR_FINISHED;
02866 }
02867 
02868 static void UV_OT_pin(wmOperatorType *ot)
02869 {
02870     /* identifiers */
02871     ot->name= "Pin";
02872     ot->description= "Set/clear selected UV vertices as anchored between multiple unwrap operations";
02873     ot->idname= "UV_OT_pin";
02874     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02875     
02876     /* api callbacks */
02877     ot->exec= pin_exec;
02878     ot->poll= ED_operator_uvedit;
02879 
02880     /* properties */
02881     RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it");
02882 }
02883 
02884 /******************* select pinned operator ***************/
02885 
02886 static int select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
02887 {
02888     Scene *scene= CTX_data_scene(C);
02889     Object *obedit= CTX_data_edit_object(C);
02890     Image *ima= CTX_data_edit_image(C);
02891     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02892     EditFace *efa;
02893     MTFace *tface;
02894     
02895     for(efa= em->faces.first; efa; efa= efa->next) {
02896         tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02897 
02898         if(uvedit_face_visible(scene, ima, efa, tface)) {
02899             if(tface->unwrap & TF_PIN1) uvedit_uv_select(scene, efa, tface, 0);
02900             if(tface->unwrap & TF_PIN2) uvedit_uv_select(scene, efa, tface, 1);
02901             if(tface->unwrap & TF_PIN3) uvedit_uv_select(scene, efa, tface, 2);
02902             if(efa->v4) {
02903                 if(tface->unwrap & TF_PIN4) uvedit_uv_select(scene, efa, tface, 3);
02904             }
02905         }
02906     }
02907     
02908     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02909 
02910     BKE_mesh_end_editmesh(obedit->data, em);
02911     return OPERATOR_FINISHED;
02912 }
02913 
02914 static void UV_OT_select_pinned(wmOperatorType *ot)
02915 {
02916     /* identifiers */
02917     ot->name= "Selected Pinned";
02918     ot->description= "Select all pinned UV vertices";
02919     ot->idname= "UV_OT_select_pinned";
02920     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02921     
02922     /* api callbacks */
02923     ot->exec= select_pinned_exec;
02924     ot->poll= ED_operator_uvedit;
02925 }
02926 
02927 /********************** hide operator *********************/
02928 
02929 static int hide_exec(bContext *C, wmOperator *op)
02930 {
02931     SpaceImage *sima= CTX_wm_space_image(C);
02932     ToolSettings *ts= CTX_data_tool_settings(C);
02933     Object *obedit= CTX_data_edit_object(C);
02934     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
02935     EditFace *efa;
02936     MTFace *tf;
02937     int swap= RNA_boolean_get(op->ptr, "unselected");
02938     int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
02939 
02940     if(ts->uv_flag & UV_SYNC_SELECTION) {
02941         EM_hide_mesh(em, swap);
02942         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
02943 
02944         BKE_mesh_end_editmesh(obedit->data, em);
02945         return OPERATOR_FINISHED;
02946     }
02947     
02948     if(swap) {
02949         for(efa= em->faces.first; efa; efa= efa->next) {
02950             if(efa->f & SELECT) {
02951                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02952                 if(facemode) {
02953                     /* Pretend face mode */
02954                     if((    (efa->v4==NULL && 
02955                             (   tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==            (TF_SEL1|TF_SEL2|TF_SEL3) )          ||
02956                             (   tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) ==    (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)   ) == 0) {
02957                         
02958                         if(em->selectmode == SCE_SELECT_FACE) {
02959                             efa->f &= ~SELECT;
02960                             /* must re-select after */
02961                             efa->e1->f &= ~SELECT;
02962                             efa->e2->f &= ~SELECT;
02963                             efa->e3->f &= ~SELECT;
02964                             if(efa->e4) efa->e4->f &= ~SELECT;
02965                         }
02966                         else
02967                             EM_select_face(efa, 0);
02968                     }
02969                     tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
02970                 }
02971                 else if(em->selectmode == SCE_SELECT_FACE) {
02972                     const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
02973                     if((tf->flag & select_flag)==0) {
02974                         EM_select_face(efa, 0);
02975                         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
02976                     }
02977                 }
02978                 else {
02979                     /* EM_deselect_flush will deselect the face */
02980                     if((tf->flag & TF_SEL1)==0)             efa->v1->f &= ~SELECT;
02981                     if((tf->flag & TF_SEL2)==0)             efa->v2->f &= ~SELECT;
02982                     if((tf->flag & TF_SEL3)==0)             efa->v3->f &= ~SELECT;
02983                     if((efa->v4) && (tf->flag & TF_SEL4)==0)    efa->v4->f &= ~SELECT;          
02984 
02985                     tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
02986                 }
02987             }
02988         }
02989     }
02990     else {
02991         for(efa= em->faces.first; efa; efa= efa->next) {
02992             if(efa->f & SELECT) {
02993                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
02994 
02995                 if(facemode) {
02996                     if( (efa->v4==NULL && 
02997                             (   tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==            (TF_SEL1|TF_SEL2|TF_SEL3) )          ||
02998                             (   tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) ==    (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)   ) {
02999                         
03000                         if(em->selectmode == SCE_SELECT_FACE) {
03001                             efa->f &= ~SELECT;
03002                             /* must re-select after */
03003                             efa->e1->f &= ~SELECT;
03004                             efa->e2->f &= ~SELECT;
03005                             efa->e3->f &= ~SELECT;
03006                             if(efa->e4) efa->e4->f &= ~SELECT;
03007                         }
03008                         else
03009                             EM_select_face(efa, 0);
03010                     }
03011 
03012                     tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
03013                 }
03014                 else if(em->selectmode == SCE_SELECT_FACE) {
03015                     const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
03016                     if(tf->flag & select_flag)
03017                         EM_select_face(efa, 0);
03018 
03019                     tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
03020                 }
03021                 else {
03022                     /* EM_deselect_flush will deselect the face */
03023                     if(tf->flag & TF_SEL1)              efa->v1->f &= ~SELECT;
03024                     if(tf->flag & TF_SEL2)              efa->v2->f &= ~SELECT;
03025                     if(tf->flag & TF_SEL3)              efa->v3->f &= ~SELECT;
03026                     if((efa->v4) && tf->flag & TF_SEL4) efa->v4->f &= ~SELECT;
03027 
03028                     tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
03029                 }
03030             }
03031         }
03032     }
03033     
03034     /*deselects too many but ok for now*/
03035     if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX))
03036         EM_deselect_flush(em);
03037     
03038     if(em->selectmode==SCE_SELECT_FACE) {
03039         /* de-selected all edges from faces that were de-selected.
03040          * now make sure all faces that are selected also have selected edges */
03041         for(efa= em->faces.first; efa; efa= efa->next)
03042             if(efa->f & SELECT)
03043                 EM_select_face(efa, 1);
03044     }
03045     
03046     EM_validate_selections(em);
03047     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
03048 
03049     BKE_mesh_end_editmesh(obedit->data, em);
03050     return OPERATOR_FINISHED;
03051 }
03052 
03053 static void UV_OT_hide(wmOperatorType *ot)
03054 {
03055     /* identifiers */
03056     ot->name= "Hide Selected";
03057     ot->description= "Hide (un)selected UV vertices";
03058     ot->idname= "UV_OT_hide";
03059     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03060     
03061     /* api callbacks */
03062     ot->exec= hide_exec;
03063     ot->poll= ED_operator_uvedit;
03064 
03065     /* props */
03066     RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
03067 }
03068 
03069 /****************** reveal operator ******************/
03070 
03071 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
03072 {
03073     SpaceImage *sima= CTX_wm_space_image(C);
03074     ToolSettings *ts= CTX_data_tool_settings(C);
03075     Object *obedit= CTX_data_edit_object(C);
03076     EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
03077     EditFace *efa;
03078     MTFace *tf;
03079     int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
03080     int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
03081     
03082     /* call the mesh function if we are in mesh sync sel */
03083     if(ts->uv_flag & UV_SYNC_SELECTION) {
03084         EM_reveal_mesh(em);
03085         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
03086 
03087         BKE_mesh_end_editmesh(obedit->data, em);
03088         return OPERATOR_FINISHED;
03089     }
03090     
03091     if(facemode) {
03092         if(em->selectmode == SCE_SELECT_FACE) {
03093             for(efa= em->faces.first; efa; efa= efa->next) {
03094                 if(!(efa->h) && !(efa->f & SELECT)) {
03095                     tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
03096                     EM_select_face(efa, 1);
03097                     tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
03098                 }
03099             }
03100         }
03101         else {
03102             /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
03103             if(!stickymode) {
03104                 for(efa= em->faces.first; efa; efa= efa->next) {
03105                     if(!(efa->h) && !(efa->f & SELECT)) {
03106                         /* All verts must be unselected for the face to be selected in the UV view */
03107                         if((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==NULL || (efa->v4->f&SELECT)==0)) {
03108                             tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
03109 
03110                             tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
03111                             /* Cant use EM_select_face here because it unselects the verts
03112                              * and we cant tell if the face was totally unselected or not */
03113                             /*EM_select_face(efa, 1);
03114                              * 
03115                              * See Loop with EM_select_face() below... */
03116                             efa->f |= SELECT;
03117                         }
03118                     }
03119                 }
03120             }
03121             else {
03122                 for(efa= em->faces.first; efa; efa= efa->next) {
03123                     if(!(efa->h) && !(efa->f & SELECT)) {
03124                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
03125 
03126                         if((efa->v1->f & SELECT)==0)                {tf->flag |= TF_SEL1;}
03127                         if((efa->v2->f & SELECT)==0)                {tf->flag |= TF_SEL2;}
03128                         if((efa->v3->f & SELECT)==0)                {tf->flag |= TF_SEL3;}
03129                         if((efa->v4 && (efa->v4->f & SELECT)==0))   {tf->flag |= TF_SEL4;}
03130 
03131                         efa->f |= SELECT;
03132                     }
03133                 }
03134             }
03135             
03136             /* Select all edges and verts now */
03137             for(efa= em->faces.first; efa; efa= efa->next)
03138                 /* we only selected the face flags, and didnt changes edges or verts, fix this now */
03139                 if(!(efa->h) && (efa->f & SELECT))
03140                     EM_select_face(efa, 1);
03141 
03142             EM_select_flush(em);
03143         }
03144     }
03145     else if(em->selectmode == SCE_SELECT_FACE) {
03146         for(efa= em->faces.first; efa; efa= efa->next) {
03147             if(!(efa->h) && !(efa->f & SELECT)) {
03148                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
03149                 efa->f |= SELECT;
03150                 tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
03151             }
03152         }
03153         
03154         /* Select all edges and verts now */
03155         for(efa= em->faces.first; efa; efa= efa->next)
03156             /* we only selected the face flags, and didnt changes edges or verts, fix this now */
03157             if(!(efa->h) && (efa->f & SELECT))
03158                 EM_select_face(efa, 1);
03159     }
03160     else {
03161         for(efa= em->faces.first; efa; efa= efa->next) {
03162             if(!(efa->h) && !(efa->f & SELECT)) {
03163                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
03164 
03165                 if((efa->v1->f & SELECT)==0)                {tf->flag |= TF_SEL1;}
03166                 if((efa->v2->f & SELECT)==0)                {tf->flag |= TF_SEL2;}
03167                 if((efa->v3->f & SELECT)==0)                {tf->flag |= TF_SEL3;}
03168                 if((efa->v4 && (efa->v4->f & SELECT)==0))   {tf->flag |= TF_SEL4;}
03169 
03170                 efa->f |= SELECT;
03171             }
03172         }
03173         
03174         /* Select all edges and verts now */
03175         for(efa= em->faces.first; efa; efa= efa->next)
03176             /* we only selected the face flags, and didnt changes edges or verts, fix this now */
03177             if(!(efa->h) && (efa->f & SELECT))
03178                 EM_select_face(efa, 1);
03179     }
03180 
03181     WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
03182 
03183     BKE_mesh_end_editmesh(obedit->data, em);
03184     return OPERATOR_FINISHED;
03185 }
03186 
03187 static void UV_OT_reveal(wmOperatorType *ot)
03188 {
03189     /* identifiers */
03190     ot->name= "Reveal Hidden";
03191     ot->description= "Reveal all hidden UV vertices";
03192     ot->idname= "UV_OT_reveal";
03193     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03194     
03195     /* api callbacks */
03196     ot->exec= reveal_exec;
03197     ot->poll= ED_operator_uvedit;
03198 }
03199 
03200 /******************** set 3d cursor operator ********************/
03201 
03202 static int set_2d_cursor_exec(bContext *C, wmOperator *op)
03203 {
03204     SpaceImage *sima = CTX_wm_space_image(C);
03205     float location[2];
03206 
03207     if(!sima)
03208         return OPERATOR_CANCELLED;
03209 
03210     RNA_float_get_array(op->ptr, "location", location);
03211     sima->cursor[0]= location[0];
03212     sima->cursor[1]= location[1];
03213     
03214     WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, NULL);
03215     
03216     return OPERATOR_FINISHED;
03217 }
03218 
03219 static int set_2d_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
03220 {
03221     ARegion *ar= CTX_wm_region(C);
03222     float location[2];
03223 
03224     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
03225     RNA_float_set_array(op->ptr, "location", location);
03226 
03227     return set_2d_cursor_exec(C, op);
03228 }
03229 
03230 static void UV_OT_cursor_set(wmOperatorType *ot)
03231 {
03232     /* identifiers */
03233     ot->name= "Set 2D Cursor";
03234     ot->description= "Set 2D cursor location";
03235     ot->idname= "UV_OT_cursor_set";
03236     
03237     /* api callbacks */
03238     ot->exec= set_2d_cursor_exec;
03239     ot->invoke= set_2d_cursor_invoke;
03240     ot->poll= ED_operator_image_active; /* requires space image */;
03241 
03242     /* flags */
03243     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03244 
03245     /* properties */
03246     RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in normalised (0.0-1.0) coordinates", -10.0f, 10.0f);
03247 }
03248 
03249 /********************** set tile operator **********************/
03250 
03251 static int set_tile_exec(bContext *C, wmOperator *op)
03252 {
03253     Image *ima= CTX_data_edit_image(C);
03254     int tile[2];
03255     Object *obedit= CTX_data_edit_object(C);
03256 
03257     RNA_int_get_array(op->ptr, "tile", tile);
03258 
03259     if(uvedit_set_tile(obedit, ima, tile[0] + ima->xrep*tile[1])) {
03260         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
03261         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, NULL);
03262 
03263         return OPERATOR_FINISHED;
03264     }
03265     
03266     return OPERATOR_CANCELLED;
03267 }
03268 
03269 static int set_tile_invoke(bContext *C, wmOperator *op, wmEvent *event)
03270 {
03271     SpaceImage *sima= CTX_wm_space_image(C);
03272     Image *ima= CTX_data_edit_image(C);
03273     ARegion *ar= CTX_wm_region(C);
03274     float fx, fy;
03275     int tile[2];
03276 
03277     if(!ima || !(ima->tpageflag & IMA_TILES))
03278         return OPERATOR_CANCELLED;
03279 
03280     UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fx, &fy);
03281 
03282     if(fx >= 0.0f && fy >= 0.0f && fx < 1.0f && fy < 1.0f) {
03283         fx= fx*ima->xrep;
03284         fy= fy*ima->yrep;
03285         
03286         tile[0]= fx;
03287         tile[1]= fy;
03288         
03289         sima->curtile= tile[1]*ima->xrep + tile[0];
03290         RNA_int_set_array(op->ptr, "tile", tile);
03291     }
03292 
03293     return set_tile_exec(C, op);
03294 }
03295 
03296 static void UV_OT_tile_set(wmOperatorType *ot)
03297 {
03298     /* identifiers */
03299     ot->name= "Set Tile";
03300     ot->description= "Set UV image tile coordinates";
03301     ot->idname= "UV_OT_tile_set";
03302     
03303     /* api callbacks */
03304     ot->exec= set_tile_exec;
03305     ot->invoke= set_tile_invoke;
03306     ot->poll= ED_operator_image_active; /* requires space image */;
03307 
03308     /* flags */
03309     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
03310 
03311     /* properties */
03312     RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate", 0, 10);
03313 }
03314 
03315 /* ************************** registration **********************************/
03316 
03317 void ED_operatortypes_uvedit(void)
03318 {
03319     WM_operatortype_append(UV_OT_select_all);
03320     WM_operatortype_append(UV_OT_select);
03321     WM_operatortype_append(UV_OT_select_loop);
03322     WM_operatortype_append(UV_OT_select_linked);
03323     WM_operatortype_append(UV_OT_select_linked_pick);
03324     WM_operatortype_append(UV_OT_unlink_selected);
03325     WM_operatortype_append(UV_OT_select_pinned);
03326     WM_operatortype_append(UV_OT_select_border);
03327     WM_operatortype_append(UV_OT_circle_select);
03328 
03329     WM_operatortype_append(UV_OT_snap_cursor);
03330     WM_operatortype_append(UV_OT_snap_selected);
03331 
03332     WM_operatortype_append(UV_OT_align);
03333     WM_operatortype_append(UV_OT_stitch);
03334     WM_operatortype_append(UV_OT_weld);
03335     WM_operatortype_append(UV_OT_pin);
03336 
03337     WM_operatortype_append(UV_OT_average_islands_scale);
03338     WM_operatortype_append(UV_OT_cube_project);
03339     WM_operatortype_append(UV_OT_cylinder_project);
03340     WM_operatortype_append(UV_OT_from_view);
03341     WM_operatortype_append(UV_OT_minimize_stretch);
03342     WM_operatortype_append(UV_OT_pack_islands);
03343     WM_operatortype_append(UV_OT_reset);
03344     WM_operatortype_append(UV_OT_sphere_project);
03345     WM_operatortype_append(UV_OT_unwrap);
03346 
03347     WM_operatortype_append(UV_OT_reveal);
03348     WM_operatortype_append(UV_OT_hide);
03349 
03350     WM_operatortype_append(UV_OT_cursor_set);
03351     WM_operatortype_append(UV_OT_tile_set);
03352 }
03353 
03354 void ED_keymap_uvedit(wmKeyConfig *keyconf)
03355 {
03356     wmKeyMap *keymap;
03357     wmKeyMapItem *kmi;
03358     
03359     keymap= WM_keymap_find(keyconf, "UV Editor", 0, 0);
03360     keymap->poll= ED_operator_uvedit;
03361     
03362     /* pick selection */
03363     RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, 0, 0)->ptr, "extend", FALSE);
03364     RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", TRUE);
03365     RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_loop", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "extend", FALSE);
03366     RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_loop", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_ALT, 0)->ptr, "extend", TRUE);
03367 
03368     /* border/circle selection */
03369     kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, 0, 0);
03370     RNA_boolean_set(kmi->ptr, "pinned", FALSE);
03371     kmi = WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, KM_SHIFT, 0);
03372     RNA_boolean_set(kmi->ptr, "pinned", TRUE);
03373 
03374     WM_keymap_add_item(keymap, "UV_OT_circle_select", CKEY, KM_PRESS, 0, 0);
03375 
03376     /* selection manipulation */
03377     RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0)->ptr, "extend", FALSE);
03378     RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked_pick", LKEY, KM_PRESS, 0, 0)->ptr, "extend", FALSE);
03379     RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "extend", TRUE);
03380     RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_linked_pick", LKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", TRUE);
03381 
03382     WM_keymap_add_item(keymap, "UV_OT_unlink_selected", LKEY, KM_PRESS, KM_ALT, 0);
03383     kmi = WM_keymap_add_item(keymap, "UV_OT_select_all", AKEY, KM_PRESS, 0, 0);
03384     RNA_enum_set(kmi->ptr, "action", SEL_TOGGLE);
03385     kmi = WM_keymap_add_item(keymap, "UV_OT_select_all", IKEY, KM_PRESS, KM_CTRL, 0);
03386     RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
03387 
03388     WM_keymap_add_item(keymap, "UV_OT_select_pinned", PKEY, KM_PRESS, KM_SHIFT, 0);
03389 
03390     WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_weldalign", WKEY, KM_PRESS, 0, 0);
03391 
03392     /* uv operations */
03393     WM_keymap_add_item(keymap, "UV_OT_stitch", VKEY, KM_PRESS, 0, 0);
03394     kmi = WM_keymap_add_item(keymap, "UV_OT_pin", PKEY, KM_PRESS, 0, 0);
03395     RNA_boolean_set(kmi->ptr, "clear", FALSE);
03396     kmi = WM_keymap_add_item(keymap, "UV_OT_pin", PKEY, KM_PRESS, KM_ALT, 0);
03397     RNA_boolean_set(kmi->ptr, "clear", TRUE);
03398 
03399     /* unwrap */
03400     WM_keymap_add_item(keymap, "UV_OT_unwrap", EKEY, KM_PRESS, 0, 0);
03401     WM_keymap_add_item(keymap, "UV_OT_minimize_stretch", VKEY, KM_PRESS, KM_CTRL, 0);
03402     WM_keymap_add_item(keymap, "UV_OT_pack_islands", PKEY, KM_PRESS, KM_CTRL, 0);
03403     WM_keymap_add_item(keymap, "UV_OT_average_islands_scale", AKEY, KM_PRESS, KM_CTRL, 0);
03404 
03405     /* hide */
03406     kmi = WM_keymap_add_item(keymap, "UV_OT_hide", HKEY, KM_PRESS, 0, 0);
03407     RNA_boolean_set(kmi->ptr, "unselected", FALSE);
03408     kmi = WM_keymap_add_item(keymap, "UV_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0);
03409     RNA_boolean_set(kmi->ptr, "unselected", TRUE);
03410 
03411     WM_keymap_add_item(keymap, "UV_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
03412 
03413     /* cursor */
03414     WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
03415     WM_keymap_add_item(keymap, "UV_OT_tile_set", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
03416     
03417     /* menus */
03418     WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
03419     WM_keymap_add_menu(keymap, "IMAGE_MT_uvs_select_mode", TABKEY, KM_PRESS, KM_CTRL, 0);
03420 
03421     /* pivot */
03422     kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, 0, 0);
03423     RNA_string_set(kmi->ptr, "data_path", "space_data.uv_editor.pivot_point");
03424     RNA_string_set(kmi->ptr, "value", "CENTER");
03425 
03426     kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", COMMAKEY, KM_PRESS, KM_CTRL, 0);
03427     RNA_string_set(kmi->ptr, "data_path", "space_data.uv_editor.pivot_point");
03428     RNA_string_set(kmi->ptr, "value", "MEDIAN");
03429 
03430     kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0);
03431     RNA_string_set(kmi->ptr, "data_path", "space_data.uv_editor.pivot_point");
03432     RNA_string_set(kmi->ptr, "value", "CURSOR");
03433 
03434     ED_object_generic_keymap(keyconf, keymap, 2);
03435 
03436     transform_keymap_for_space(keyconf, keymap, SPACE_IMAGE);
03437 }
03438