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