/** * $Id$ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include #include #include #ifdef HAVE_CONFIG_H #include #endif #ifndef WIN32 #include #else #include #endif #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "IMB_imbuf_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_userdef_types.h" #include "DNA_space_types.h" #include "DNA_image_types.h" #include "DNA_object_types.h" // only for uvedit_selectionCB() (struct Object) #include "BKE_colortools.h" #include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_displist.h" #include "BKE_object.h" #include "BKE_utildefines.h" #include "BIF_gl.h" #include "BIF_glutil.h" #include "BIF_interface.h" #include "BIF_screen.h" #include "BIF_drawimage.h" #include "BIF_editview.h" #include "BIF_space.h" #include "BIF_editsima.h" #include "BIF_toolbox.h" #include "BIF_transform.h" #include "BIF_mywindow.h" #include "BSE_drawipo.h" #include "BSE_edit.h" #include "BSE_trans_types.h" #include "BDR_editobject.h" #include "BDR_unwrapper.h" #include "BMF_Api.h" #include "blendef.h" #include "mydevice.h" /* local prototypes */ void clever_numbuts_sima(void); void sel_uvco_inside_radius(short , TFace *, int , float *, float *, short); void uvedit_selectionCB(short , Object *, short *, float ); /* used in edit.c*/ void object_uvs_changed(Object *ob) { DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWIMAGE, 0); } void object_tface_flags_changed(Object *ob, int updateButtons) { if (updateButtons) allqueue(REDRAWBUTSEDIT, 0); allqueue(REDRAWVIEW3D, 0); allqueue(REDRAWIMAGE, 0); } int is_uv_tface_editing_allowed_silent(void) { Mesh *me; if(G.obedit) return 0; if(G.sima->mode!=SI_TEXTURE) return 0; if(!(G.f & G_FACESELECT)) return 0; me= get_mesh(OBACT); if(me==0 || me->tface==0) return 0; return 1; } int is_uv_tface_editing_allowed(void) { if(G.obedit) error("Unable to perform action in Edit Mode"); return is_uv_tface_editing_allowed_silent(); } void get_connected_limit_tface_uv(float *limit) { if(G.sima->image && G.sima->image->ibuf && G.sima->image->ibuf->x > 0 && G.sima->image->ibuf->y > 0) { limit[0]= 0.05/(float)G.sima->image->ibuf->x; limit[1]= 0.05/(float)G.sima->image->ibuf->y; } else limit[0]= limit[1]= 0.05/256.0; } void clever_numbuts_sima(void) { float ocent[2], cent[2]= {0.0, 0.0}; int imx, imy; int i, nactive= 0; Mesh *me; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); if (G.sima->image && G.sima->image->ibuf) { imx= G.sima->image->ibuf->x; imy= G.sima->image->ibuf->y; } else imx= imy= 256; for (i=0; itotface; i++) { MFace *mf= &((MFace*) me->mface)[i]; TFace *tf= &((TFace*) me->tface)[i]; if (!(tf->flag & TF_SELECT)) continue; if (tf->flag & TF_SEL1) { cent[0]+= tf->uv[0][0]; cent[1]+= tf->uv[0][1]; nactive++; } if (tf->flag & TF_SEL2) { cent[0]+= tf->uv[1][0]; cent[1]+= tf->uv[1][1]; nactive++; } if (tf->flag & TF_SEL3) { cent[0]+= tf->uv[2][0]; cent[1]+= tf->uv[2][1]; nactive++; } if (mf->v4 && (tf->flag & TF_SEL4)) { cent[0]+= tf->uv[3][0]; cent[1]+= tf->uv[3][1]; nactive++; } } if (nactive) { cent[0]= (cent[0]*imx)/nactive; cent[1]= (cent[1]*imy)/nactive; add_numbut(0, NUM|FLO, "LocX:", -imx*20, imx*20, ¢[0], NULL); add_numbut(1, NUM|FLO, "LocY:", -imy*20, imy*20, ¢[1], NULL); ocent[0]= cent[0]; ocent[1]= cent[1]; if (do_clever_numbuts((nactive==1)?"Active Vertex":"Selected Center", 2, REDRAW)) { float delta[2]; delta[0]= (cent[0]-ocent[0])/imx; delta[1]= (cent[1]-ocent[1])/imy; for (i=0; itotface; i++) { MFace *mf= &((MFace*) me->mface)[i]; TFace *tf= &((TFace*) me->tface)[i]; if (!(tf->flag & TF_SELECT)) continue; if (tf->flag & TF_SEL1) { tf->uv[0][0]+= delta[0]; tf->uv[0][1]+= delta[1]; } if (tf->flag & TF_SEL2) { tf->uv[1][0]+= delta[0]; tf->uv[1][1]+= delta[1]; } if (tf->flag & TF_SEL3) { tf->uv[2][0]+= delta[0]; tf->uv[2][1]+= delta[1]; } if (mf->v4 && (tf->flag & TF_SEL4)) { tf->uv[3][0]+= delta[0]; tf->uv[3][1]+= delta[1]; } } object_uvs_changed(OBACT); } } } void be_square_tface_uv(Mesh *me) { TFace *tface; MFace *mface; int a; /* if 1 vertex selected: doit (with the selected vertex) */ mface= (MFace*)me->mface; tface= (TFace*)me->tface; for(a=me->totface; a>0; a--, tface++, mface++) { if(mface->v4) { if(tface->flag & TF_SELECT) { if(tface->flag & TF_SEL1) { if( tface->uv[1][0] == tface->uv[2][0] ) { tface->uv[1][1]= tface->uv[0][1]; tface->uv[3][0]= tface->uv[0][0]; } else { tface->uv[1][0]= tface->uv[0][0]; tface->uv[3][1]= tface->uv[0][1]; } } if(tface->flag & TF_SEL2) { if( tface->uv[2][1] == tface->uv[3][1] ) { tface->uv[2][0]= tface->uv[1][0]; tface->uv[0][1]= tface->uv[1][1]; } else { tface->uv[2][1]= tface->uv[1][1]; tface->uv[0][0]= tface->uv[1][0]; } } if(tface->flag & TF_SEL3) { if( tface->uv[3][0] == tface->uv[0][0] ) { tface->uv[3][1]= tface->uv[2][1]; tface->uv[1][0]= tface->uv[2][0]; } else { tface->uv[3][0]= tface->uv[2][0]; tface->uv[1][1]= tface->uv[2][1]; } } if(tface->flag & TF_SEL4) { if( tface->uv[0][1] == tface->uv[1][1] ) { tface->uv[0][0]= tface->uv[3][0]; tface->uv[2][1]= tface->uv[3][1]; } else { tface->uv[0][1]= tface->uv[3][1]; tface->uv[2][0]= tface->uv[3][0]; } } } } } } void transform_aspect_ratio_tface_uv(float *aspx, float *aspy) { int w, h; transform_width_height_tface_uv(&w, &h); *aspx= (float)w/256.0f; *aspy= (float)h/256.0f; } void transform_width_height_tface_uv(int *width, int *height) { if(G.sima->image && G.sima->image->ibuf) { *width= G.sima->image->ibuf->x; *height= G.sima->image->ibuf->y; } else { *width= 256; *height= 256; } } void mirror_tface_uv(char mirroraxis) { if (mirroraxis == 'x') Mirror(1); /* global x */ else if (mirroraxis == 'y') Mirror(2); /* global y */ } void mirrormenu_tface_uv(void) { short mode= 0; if( is_uv_tface_editing_allowed()==0 ) return; mode= pupmenu("Mirror%t|X Axis%x1|Y Axis%x2|"); if(mode==-1) return; if(mode==1) mirror_tface_uv('x'); else if(mode==2) mirror_tface_uv('y'); BIF_undo_push("Mirror UV"); } void weld_align_tface_uv(char tool) { MFace *mface; TFace *tface; Mesh *me; float min[2], max[2], cent[2]; int a; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); if (!minmax_tface_uv(min, max)) return; cent[0]= (min[0]+max[0])/2.0; cent[1]= (min[1]+max[1])/2.0; if(tool == 'x' || tool == 'w') { tface= me->tface; mface= me->mface; for(a=me->totface; a>0; a--, tface++, mface++) { if(tface->flag & TF_SELECT) { if(tface->flag & TF_SEL1) tface->uv[0][0]= cent[0]; if(tface->flag & TF_SEL2) tface->uv[1][0]= cent[0]; if(tface->flag & TF_SEL3) tface->uv[2][0]= cent[0]; if(mface->v4 && (tface->flag & TF_SEL4)) tface->uv[3][0]= cent[0]; } } } if(tool == 'y' || tool == 'w') { tface= me->tface; mface= me->mface; for(a=me->totface; a>0; a--, tface++, mface++) { if(tface->flag & TF_SELECT) { if(tface->flag & TF_SEL1) tface->uv[0][1]= cent[1]; if(tface->flag & TF_SEL2) tface->uv[1][1]= cent[1]; if(tface->flag & TF_SEL3) tface->uv[2][1]= cent[1]; if(mface->v4 && (tface->flag & TF_SEL4)) tface->uv[3][1]= cent[1]; } } } object_uvs_changed(OBACT); } void weld_align_menu_tface_uv(void) { short mode= 0; if( is_uv_tface_editing_allowed()==0 ) return; mode= pupmenu("Weld/Align%t|Weld%x1|Align X%x2|Align Y%x3|"); if(mode==-1) return; if(mode==1) weld_align_tface_uv('w'); else if(mode==2) weld_align_tface_uv('x'); else if(mode==3) weld_align_tface_uv('y'); if(mode==1) BIF_undo_push("Weld UV"); else if(mode==2 || mode==3) BIF_undo_push("Align UV"); } void select_swap_tface_uv(void) { Mesh *me; TFace *tface; MFace *mface; int a, sel=0; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); for(a=me->totface, tface= me->tface; a>0; a--, tface++) { if(tface->flag & TF_SELECT) { if(tface->flag & (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4)) { sel= 1; break; } } } mface= me->mface; for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) { if(tface->flag & TF_SELECT) { if(mface->v4) { if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4); else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4); } else { if(sel) tface->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4); else tface->flag |= (TF_SEL1+TF_SEL2+TF_SEL3); } } } BIF_undo_push("Select swap UV"); allqueue(REDRAWIMAGE, 0); } static int msel_hit(float *limit, unsigned int *hitarray, unsigned int vertexid, float **uv, float *uv2, int sticky) { int i; for(i=0; i< 4; i++) { if(hitarray[i] == vertexid) { if(sticky == 2) { if(fabs(uv[i][0]-uv2[0]) < limit[0] && fabs(uv[i][1]-uv2[1]) < limit[1]) return 1; } else return 1; } } return 0; } static void find_nearest_tface(TFace **nearesttf, MFace **nearestmf) { Mesh *me; TFace *tf; MFace *mf; int a, i, nverts, mindist, dist, fcenter[2], uval[2]; short mval[2]; getmouseco_areawin(mval); mindist= 0x7FFFFFF; *nearesttf= NULL; *nearestmf= NULL; me= get_mesh(OBACT); mf= (MFace*)me->mface; tf= (TFace*)me->tface; for(a=me->totface; a>0; a--, tf++, mf++) { if(tf->flag & TF_SELECT) { fcenter[0]= fcenter[1]= 0; nverts= mf->v4? 4: 3; for(i=0; iuv[i], uval); fcenter[0] += uval[0]; fcenter[1] += uval[1]; } fcenter[0] /= nverts; fcenter[1] /= nverts; dist= abs(mval[0]- fcenter[0])+ abs(mval[1]- fcenter[1]); if (dist < mindist) { *nearesttf= tf; *nearestmf= mf; mindist= dist; } } } } static int nearest_uv_between(TFace *tf, int nverts, int id, short *mval, int *uval) { float m[3], v1[3], v2[3], c1, c2; int id1, id2; id1= (id+nverts-1)%nverts; id2= (id+nverts+1)%nverts; m[0] = (float)(mval[0]-uval[0]); m[1] = (float)(mval[1]-uval[1]); Vec2Subf(v1, tf->uv[id1], tf->uv[id]); Vec2Subf(v2, tf->uv[id2], tf->uv[id]); /* m and v2 on same side of v-v1? */ c1= v1[0]*m[1] - v1[1]*m[0]; c2= v1[0]*v2[1] - v1[1]*v2[0]; if (c1*c2 < 0.0f) return 0; /* m and v1 on same side of v-v2? */ c1= v2[0]*m[1] - v2[1]*m[0]; c2= v2[0]*v1[1] - v2[1]*v1[0]; return (c1*c2 >= 0.0f); } static void find_nearest_uv(TFace **nearesttf, unsigned int *nearestv, int *nearestuv) { Mesh *me; TFace *tf; MFace *mf; int a, i, nverts, mindist, dist, uval[2]; short mval[2]; getmouseco_areawin(mval); mindist= 0x7FFFFFF; *nearesttf= NULL; me= get_mesh(OBACT); mf= (MFace*)me->mface; tf= (TFace*)me->tface; for(a=me->totface; a>0; a--, tf++, mf++) { if(tf->flag & TF_SELECT) { nverts= mf->v4? 4: 3; for(i=0; iuv[i], uval); dist= abs(mval[0]-uval[0]) + abs(mval[1]-uval[1]); if(tf->flag & TF_SEL_MASK(i)) dist += 5; if(dist<=mindist) { if(dist==mindist) if (!nearest_uv_between(tf, nverts, i, mval, uval)) continue; mindist= dist; *nearesttf= tf; *nearestuv= i; if (i==0) *nearestv= mf->v1; else if (i==1) *nearestv= mf->v2; else if (i==2) *nearestv= mf->v3; else *nearestv= mf->v4; } } } } } void mouse_select_sima(void) { Mesh *me; TFace *tf, *nearesttf; MFace *mf, *nearestmf=NULL; int a, selectsticky, sticky, actface, nearestuv, i; unsigned int hitv[4], nearestv; float *hituv[4], limit[2]; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); get_connected_limit_tface_uv(limit); actface= (G.qual & LR_ALTKEY || G.sima->flag & SI_SELACTFACE); if(G.qual & LR_CTRLKEY) { if(G.sima->flag & SI_STICKYUVS) sticky= 0; else sticky= 1; } else { if(G.sima->flag & SI_STICKYUVS) sticky= 1; else if(G.sima->flag & SI_LOCALSTICKY) sticky= 2; else sticky= 0; } if(actface) { find_nearest_tface(&nearesttf, &nearestmf); if(nearesttf==NULL) return; nearesttf->flag |= TF_ACTIVE; for (i=0; i<4; i++) hituv[i]= nearesttf->uv[i]; hitv[0]= nearestmf->v1; hitv[1]= nearestmf->v2; hitv[2]= nearestmf->v3; hitv[3]= nearestmf->v4? nearestmf->v4: 0xFFFFFFFF; } else { find_nearest_uv(&nearesttf, &nearestv, &nearestuv); if(nearesttf==NULL) return; if(sticky) { for(i=0; i<4; i++) hitv[i]= 0xFFFFFFFF; hitv[nearestuv]= nearestv; hituv[nearestuv]= nearesttf->uv[nearestuv]; } } if(G.qual & LR_SHIFTKEY) { /* (de)select face */ if(actface) { if(!(~nearesttf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) && (!nearestmf->v4 || nearesttf->flag & TF_SEL4)) { nearesttf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); selectsticky= 0; } else { nearesttf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4; selectsticky= 1; } } /* (de)select uv node */ else { if(nearesttf->flag & TF_SEL_MASK(nearestuv)) { nearesttf->flag &= ~TF_SEL_MASK(nearestuv); selectsticky= 0; } else { nearesttf->flag |= TF_SEL_MASK(nearestuv); selectsticky= 1; } } /* (de)select sticky uv nodes */ if(sticky || actface) { mf= (MFace*)me->mface; tf= (TFace*)me->tface; /* deselect */ if(selectsticky==0) { for(a=me->totface; a>0; a--, tf++, mf++) { if(!(tf->flag & TF_SELECT)) continue; if(nearesttf && tf!=nearesttf) tf->flag &=~ TF_ACTIVE; if (!sticky) continue; if(msel_hit(limit, hitv, mf->v1, hituv, tf->uv[0], sticky)) tf->flag &= ~TF_SEL1; if(msel_hit(limit, hitv, mf->v2, hituv, tf->uv[1], sticky)) tf->flag &= ~TF_SEL2; if(msel_hit(limit, hitv, mf->v3, hituv, tf->uv[2], sticky)) tf->flag &= ~TF_SEL3; if (mf->v4) if(msel_hit(limit, hitv, mf->v4, hituv, tf->uv[3], sticky)) tf->flag &= ~TF_SEL4; } } /* select */ else { for(a=me->totface; a>0; a--, tf++, mf++) { if(!(tf->flag & TF_SELECT)) continue; if(nearesttf && tf!=nearesttf) tf->flag &=~ TF_ACTIVE; if (!sticky) continue; if(msel_hit(limit, hitv, mf->v1, hituv, tf->uv[0], sticky)) tf->flag |= TF_SEL1; if(msel_hit(limit, hitv, mf->v2, hituv, tf->uv[1], sticky)) tf->flag |= TF_SEL2; if(msel_hit(limit, hitv, mf->v3, hituv, tf->uv[2], sticky)) tf->flag |= TF_SEL3; if (mf->v4) if(msel_hit(limit, hitv, mf->v4, hituv, tf->uv[3], sticky)) tf->flag |= TF_SEL4; } } } } else { /* select face and deselect other faces */ if(actface) { mf= (MFace*)me->mface; tf= (TFace*)me->tface; for(a=me->totface; a>0; a--, tf++, mf++) { tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); if(nearesttf && tf!=nearesttf) tf->flag &= ~TF_ACTIVE; } if(nearesttf) nearesttf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); } /* deselect uvs, and select sticky uvs */ mf= (MFace*)me->mface; tf= (TFace*)me->tface; for(a=me->totface; a>0; a--, tf++, mf++) { if(tf->flag & TF_SELECT) { if(!actface) tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); if(!sticky) continue; if(msel_hit(limit, hitv, mf->v1, hituv, tf->uv[0], sticky)) tf->flag |= TF_SEL1; if(msel_hit(limit, hitv, mf->v2, hituv, tf->uv[1], sticky)) tf->flag |= TF_SEL2; if(msel_hit(limit, hitv, mf->v3, hituv, tf->uv[2], sticky)) tf->flag |= TF_SEL3; if(mf->v4) if(msel_hit(limit, hitv, mf->v4, hituv, tf->uv[3], sticky)) tf->flag |= TF_SEL4; } } if(!actface) nearesttf->flag |= TF_SEL_MASK(nearestuv); } force_draw(1); BIF_undo_push("Select UV"); rightmouse_transform(); } void borderselect_sima(short whichuvs) { Mesh *me; TFace *tface; MFace *mface; rcti rect; rctf rectf; int a, val; short mval[2]; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); val= get_border(&rect, 3); if(val) { mval[0]= rect.xmin; mval[1]= rect.ymin; areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin); mval[0]= rect.xmax; mval[1]= rect.ymax; areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax); mface= me->mface; for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) { if(tface->flag & TF_SELECT) { if (whichuvs == UV_SELECT_ALL) { if(BLI_in_rctf(&rectf, (float)tface->uv[0][0], (float)tface->uv[0][1])) { if(val==LEFTMOUSE) tface->flag |= TF_SEL1; else tface->flag &= ~TF_SEL1; } if(BLI_in_rctf(&rectf, (float)tface->uv[1][0], (float)tface->uv[1][1])) { if(val==LEFTMOUSE) tface->flag |= TF_SEL2; else tface->flag &= ~TF_SEL2; } if(BLI_in_rctf(&rectf, (float)tface->uv[2][0], (float)tface->uv[2][1])) { if(val==LEFTMOUSE) tface->flag |= TF_SEL3; else tface->flag &= ~TF_SEL3; } if(mface->v4 && BLI_in_rctf(&rectf, (float)tface->uv[3][0], (float)tface->uv[3][1])) { if(val==LEFTMOUSE) tface->flag |= TF_SEL4; else tface->flag &= ~TF_SEL4; } } else if (whichuvs == UV_SELECT_PINNED) { if ((tface->unwrap & TF_PIN1) && BLI_in_rctf(&rectf, (float)tface->uv[0][0], (float)tface->uv[0][1])) { if(val==LEFTMOUSE) tface->flag |= TF_SEL1; else tface->flag &= ~TF_SEL1; } if ((tface->unwrap & TF_PIN2) && BLI_in_rctf(&rectf, (float)tface->uv[1][0], (float)tface->uv[1][1])) { if(val==LEFTMOUSE) tface->flag |= TF_SEL2; else tface->flag &= ~TF_SEL2; } if ((tface->unwrap & TF_PIN3) && BLI_in_rctf(&rectf, (float)tface->uv[2][0], (float)tface->uv[2][1])) { if(val==LEFTMOUSE) tface->flag |= TF_SEL3; else tface->flag &= ~TF_SEL3; } if ((mface->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, (float)tface->uv[3][0], (float)tface->uv[3][1])) { if(val==LEFTMOUSE) tface->flag |= TF_SEL4; else tface->flag &= ~TF_SEL4; } } } } BIF_undo_push("Border select UV"); scrarea_queue_winredraw(curarea); } } /** This is an ugly function to set the Tface selection flags depending * on whether its UV coordinates are inside the normalized * area with radius rad and offset offset. These coordinates must be * normalized to 1.0 * Just for readability... */ void sel_uvco_inside_radius(short sel, TFace *tface, int index, float *offset, float *ell, short select_mask) { // normalized ellipse: ell[0] = scaleX, // [1] = scaleY float *uv = tface->uv[index]; float x, y, r2; x = (uv[0] - offset[0]) * ell[0]; y = (uv[1] - offset[1]) * ell[1]; r2 = x * x + y * y; if (r2 < 1.0) { if (sel == LEFTMOUSE) tface->flag |= select_mask; else tface->flag &= ~select_mask; } } // see below: /** gets image dimensions of the 2D view 'v' */ static void getSpaceImageDimension(SpaceImage *sima, float *xy) { Image *img = sima->image; float z; z = sima->zoom; if (img && img->ibuf) { xy[0] = img->ibuf->x * z; xy[1] = img->ibuf->y * z; } else { xy[0] = 256 * z; xy[1] = 256 * z; } } /** Callback function called by circle_selectCB to enable * brush select in UV editor. */ void uvedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) { float offset[2]; Mesh *me; MFace *mface; TFace *tface; int i; float ellipse[2]; // we need to deal with ellipses, as // non square textures require for circle // selection. this ellipse is normalized; r = 1.0 me = get_mesh(editobj); getSpaceImageDimension(curarea->spacedata.first, ellipse); ellipse[0] /= rad; ellipse[1] /= rad; areamouseco_to_ipoco(G.v2d, mval, &offset[0], &offset[1]); mface= me->mface; tface= me->tface; if (selecting) { for(i = 0; i < me->totface; i++) { sel_uvco_inside_radius(selecting, tface, 0, offset, ellipse, TF_SEL1); sel_uvco_inside_radius(selecting, tface, 1, offset, ellipse, TF_SEL2); sel_uvco_inside_radius(selecting, tface, 2, offset, ellipse, TF_SEL3); if (mface->v4) sel_uvco_inside_radius(selecting, tface, 3, offset, ellipse, TF_SEL4); tface++; mface++; } if(G.f & G_DRAWFACES) { /* full redraw only if necessary */ draw_sel_circle(0, 0, 0, 0, 0); /* signal */ force_draw(0); } else { /* force_draw() is no good here... */ glDrawBuffer(GL_FRONT); draw_tfaces(); bglFlush(); glDrawBuffer(GL_BACK); } } } void mouseco_to_curtile(void) { float fx, fy; short mval[2]; if( is_uv_tface_editing_allowed()==0) return; if(G.sima->image && G.sima->image->tpageflag & IMA_TILES) { G.sima->flag |= SI_EDITTILE; while(get_mbut()&L_MOUSE) { calc_image_view(G.sima, 'f'); getmouseco_areawin(mval); areamouseco_to_ipoco(G.v2d, mval, &fx, &fy); if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) { fx= (fx)*G.sima->image->xrep; fy= (fy)*G.sima->image->yrep; mval[0]= fx; mval[1]= fy; G.sima->curtile= mval[1]*G.sima->image->xrep + mval[0]; } scrarea_do_windraw(curarea); screen_swapbuffers(); } G.sima->flag &= ~SI_EDITTILE; image_changed(G.sima, 1); allqueue(REDRAWVIEW3D, 0); scrarea_queue_winredraw(curarea); } } void hide_tface_uv(int swap) { Mesh *me; TFace *tface; MFace *mface; int a; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); if(swap) { mface= me->mface; for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) { if(tface->flag & TF_SELECT) { if((tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))==0) { if(!mface->v4) tface->flag &= ~TF_SELECT; else if(!(tface->flag & TF_SEL4)) tface->flag &= ~TF_SELECT; } } } } else { mface= me->mface; for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) { if(tface->flag & TF_SELECT) { if(tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) tface->flag &= ~TF_SELECT; else if(mface->v4 && tface->flag & TF_SEL4) tface->flag &= ~TF_SELECT; } } } BIF_undo_push("Hide UV"); object_tface_flags_changed(OBACT, 0); } void reveal_tface_uv(void) { Mesh *me; TFace *tface; MFace *mface; int a; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); mface= me->mface; for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) if(!(tface->flag & TF_HIDE)) if(!(tface->flag & TF_SELECT)) tface->flag |= (TF_SELECT|TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); BIF_undo_push("Reveal UV"); object_tface_flags_changed(OBACT, 0); } void stitch_uv_tface(int mode) { Mesh *me; TFace *tf; int a, vtot; float newuv[2], limit[2]; UvMapVert *vlist, *iterv, *v; UvVertMap *vmap; if(is_uv_tface_editing_allowed()==0) return; limit[0]= limit[1]= 20.0; if(mode==1) { add_numbut(0, NUM|FLO, "Limit:", 0.1, 1000.0, &limit[0], NULL); if (!do_clever_numbuts("Stitch UVs", 1, REDRAW)) return; } if(G.sima->image && G.sima->image->ibuf && G.sima->image->ibuf->x > 0 && G.sima->image->ibuf->y > 0) { limit[1]= limit[0]/(float)G.sima->image->ibuf->y; limit[0]= limit[0]/(float)G.sima->image->ibuf->x; } else limit[0]= limit[1]= limit[0]/256.0; me= get_mesh(OBACT); tf= me->tface; vmap= make_uv_vert_map(me->mface, tf, me->totface, me->totvert, 1, limit); if(vmap == NULL) return; if(mode==0) { for(a=0; atotvert; a++) { v = get_uv_map_vert(vmap, a); if(v == NULL) continue; newuv[0]= 0; newuv[1]= 0; vtot= 0; for(iterv=v; iterv; iterv=iterv->next) { if (tf[iterv->f].flag & TF_SEL_MASK(iterv->tfindex)) { newuv[0] += tf[iterv->f].uv[iterv->tfindex][0]; newuv[1] += tf[iterv->f].uv[iterv->tfindex][1]; vtot++; } } if (vtot > 1) { newuv[0] /= vtot; newuv[1] /= vtot; for(iterv=v; iterv; iterv=iterv->next) { if (tf[iterv->f].flag & TF_SEL_MASK(iterv->tfindex)) { tf[iterv->f].uv[iterv->tfindex][0]= newuv[0]; tf[iterv->f].uv[iterv->tfindex][1]= newuv[1]; } } } } } else if(mode==1) { for(a=0; atotvert; a++) { vlist= get_uv_map_vert(vmap, a); while(vlist) { newuv[0]= 0; newuv[1]= 0; vtot= 0; for(iterv=vlist; iterv; iterv=iterv->next) { if((iterv != vlist) && iterv->separate) break; if (tf[iterv->f].flag & TF_SEL_MASK(iterv->tfindex)) { newuv[0] += tf[iterv->f].uv[iterv->tfindex][0]; newuv[1] += tf[iterv->f].uv[iterv->tfindex][1]; vtot++; } } if (vtot > 1) { newuv[0] /= vtot; newuv[1] /= vtot; for(iterv=vlist; iterv; iterv=iterv->next) { if((iterv != vlist) && iterv->separate) break; if (tf[iterv->f].flag & TF_SEL_MASK(iterv->tfindex)) { tf[iterv->f].uv[iterv->tfindex][0]= newuv[0]; tf[iterv->f].uv[iterv->tfindex][1]= newuv[1]; } } } vlist= iterv; } } } free_uv_vert_map(vmap); if(G.sima->flag & SI_BE_SQUARE) be_square_tface_uv(me); BIF_undo_push("Stitch UV"); object_uvs_changed(OBACT); } void select_linked_tface_uv(int mode) { Mesh *me; MFace *mf; TFace *tf, *nearesttf=NULL; UvVertMap *vmap; UvMapVert *vlist, *iterv, *startv; unsigned int *stack, stacksize= 0, nearestv; char *flag; int a, nearestuv, i, nverts; float limit[2]; if(is_uv_tface_editing_allowed()==0) return; me= get_mesh(OBACT); if (mode == 2) { nearesttf= NULL; nearestuv= 0; } if (mode!=2) { find_nearest_uv(&nearesttf, &nearestv, &nearestuv); if(nearesttf==NULL) return; } get_connected_limit_tface_uv(limit); vmap= make_uv_vert_map(me->mface, me->tface, me->totface, me->totvert, 1, limit); if(vmap == NULL) return; stack= MEM_mallocN(sizeof(*stack)*me->totface, "UvLinkStack"); flag= MEM_callocN(sizeof(*flag)*me->totface, "UvLinkFlag"); if (mode == 2) { tf= me->tface; for(a=0; atotface; a++, tf++) if(!(tf->flag & TF_HIDE) && (tf->flag & TF_SELECT)) if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) { stack[stacksize]= a; stacksize++; flag[a]= 1; } } else { tf= me->tface; for(a=0; atotface; a++, tf++) if(tf == nearesttf) { stack[stacksize]= a; stacksize++; flag[a]= 1; break; } } while(stacksize > 0) { stacksize--; a= stack[stacksize]; mf= me->mface+a; tf= me->tface+a; nverts= mf->v4? 4: 3; for(i=0; iv1 + i)); startv= vlist; for(iterv=vlist; iterv; iterv=iterv->next) { if(iterv->separate) startv= iterv; if(iterv->f == a) break; } for(iterv=startv; iterv; iterv=iterv->next) { if((startv != iterv) && (iterv->separate)) break; else if(!flag[iterv->f]) { flag[iterv->f]= 1; stack[stacksize]= iterv->f;; stacksize++; } } } } if(mode==0 || mode==2) { for(a=0, tf=me->tface; atotface; a++, tf++) if(flag[a]) tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); else tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); } else if(mode==1) { mf= me->mface; for(a=0, tf=me->tface; atotface; a++, tf++, mf++) { if(flag[a]) { if (mf->v4) { if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))) break; } else if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) break; } } if (atotface) { for(a=0, tf=me->tface; atotface; a++, tf++) if(flag[a]) tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); } else { for(a=0, tf=me->tface; atotface; a++, tf++) if(flag[a]) tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); } } MEM_freeN(stack); MEM_freeN(flag); free_uv_vert_map(vmap); BIF_undo_push("Select linked UV"); scrarea_queue_winredraw(curarea); } void unlink_selection(void) { Mesh *me; TFace *tface; MFace *mface; int a; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); mface= me->mface; for(a=me->totface, tface= me->tface; a>0; a--, tface++, mface++) { if(tface->flag & TF_SELECT) { if(mface->v4) { if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4); } else { if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3); } } } BIF_undo_push("Unlink UV selection"); scrarea_queue_winredraw(curarea); } void toggle_uv_select(int mode) { switch(mode){ case 'f': G.sima->flag ^= SI_SELACTFACE; break; case 's': G.sima->flag ^= SI_STICKYUVS; if (G.sima->flag & SI_STICKYUVS) G.sima->flag &= ~SI_LOCALSTICKY; else G.sima->flag |= SI_LOCALSTICKY; break; case 'l': G.sima->flag ^= SI_LOCALSTICKY; if (G.sima->flag & SI_LOCALSTICKY) G.sima->flag &= ~SI_STICKYUVS; break; case 'o': G.sima->flag &= ~SI_STICKYUVS; G.sima->flag &= ~SI_LOCALSTICKY; break; } allqueue(REDRAWIMAGE, 0); } void pin_tface_uv(int mode) { Mesh *me; TFace *tface; MFace *mface; int a; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); mface= me->mface; tface= me->tface; for(a=me->totface; a>0; a--, tface++, mface++) { if(tface->flag & TF_SELECT) { if(mode ==1){ if(tface->flag & TF_SEL1) tface->unwrap |= TF_PIN1; if(tface->flag & TF_SEL2) tface->unwrap |= TF_PIN2; if(tface->flag & TF_SEL3) tface->unwrap |= TF_PIN3; if(mface->v4) if(tface->flag & TF_SEL4) tface->unwrap |= TF_PIN4; } else if (mode ==0){ if(tface->flag & TF_SEL1) tface->unwrap &= ~TF_PIN1; if(tface->flag & TF_SEL2) tface->unwrap &= ~TF_PIN2; if(tface->flag & TF_SEL3) tface->unwrap &= ~TF_PIN3; if(mface->v4) if(tface->flag & TF_SEL4) tface->unwrap &= ~TF_PIN4; } } } BIF_undo_push("Pin UV"); scrarea_queue_winredraw(curarea); } void select_pinned_tface_uv(void) { Mesh *me; TFace *tface; MFace *mface; int a; if( is_uv_tface_editing_allowed()==0 ) return; me= get_mesh(OBACT); mface= me->mface; tface= me->tface; for(a=me->totface; a>0; a--, tface++, mface++) { if(tface->flag & TF_SELECT) { if (tface->unwrap & TF_PIN1) tface->flag |= TF_SEL1; if (tface->unwrap & TF_PIN2) tface->flag |= TF_SEL2; if (tface->unwrap & TF_PIN3) tface->flag |= TF_SEL3; if(mface->v4) { if (tface->unwrap & TF_PIN4) tface->flag |= TF_SEL4; } } } BIF_undo_push("Select Pinned UVs"); scrarea_queue_winredraw(curarea); } int minmax_tface_uv(float *min, float *max) { Mesh *me; TFace *tf; MFace *mf; int a, sel; if( is_uv_tface_editing_allowed()==0 ) return 0; me= get_mesh(OBACT); INIT_MINMAX2(min, max); sel= 0; mf= (MFace*)me->mface; tf= (TFace*)me->tface; for(a=me->totface; a>0; a--, tf++, mf++) { if(tf->flag & TF_HIDE); else if(tf->flag & TF_SELECT) { if (tf->flag & TF_SEL1) { DO_MINMAX2(tf->uv[0], min, max); } if (tf->flag & TF_SEL2) { DO_MINMAX2(tf->uv[1], min, max); } if (tf->flag & TF_SEL3) { DO_MINMAX2(tf->uv[2], min, max); } if (mf->v4 && tf->flag & TF_SEL4) { DO_MINMAX2(tf->uv[3], min, max); } sel = 1; } } return sel; } static void sima_show_info(int x, int y, char *cp, float *fp, int *zp, float *zpf) { short ofs; char str[256]; ofs= sprintf(str, "X: %d Y: %d ", x, y); if(cp) ofs+= sprintf(str+ofs, "| R: %d G: %d B: %d A: %d ", cp[0], cp[1], cp[2], cp[3]); if(fp) ofs+= sprintf(str+ofs, "| R: %.3f G: %.3f B: %.3f A: %.3f ", fp[0], fp[1], fp[2], fp[3]); if(zp) ofs+= sprintf(str+ofs, "| Z: %.4f ", 0.5+0.5*( ((float)*zp)/(float)0x7fffffff)); if(zpf) ofs+= sprintf(str+ofs, "| Z: %.3f ", *zpf); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glColor4f(.0,.0,.0,.25); glRectf(0.0, 0.0, curarea->winx, 30.0); glDisable(GL_BLEND); glColor3ub(255, 255, 255); glRasterPos2i(10, 10); BMF_DrawString(G.fonts, str); } void sima_sample_color(void) { ImBuf *ibuf; float fx, fy; short mval[2], mvalo[2], firsttime=1; if(G.sima->image==NULL) return; if(G.sima->image->ibuf==NULL) return; ibuf= G.sima->image->ibuf; calc_image_view(G.sima, 'f'); getmouseco_areawin(mvalo); while(get_mbut() & L_MOUSE) { getmouseco_areawin(mval); if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || firsttime) { firsttime= 0; areamouseco_to_ipoco(G.v2d, mval, &fx, &fy); if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) { float *fp= NULL, *zpf= NULL; int *zp= NULL; char *cp= NULL; int x= (int) (fx*ibuf->x); int y= (int) (fy*ibuf->y); if(x>=ibuf->x) x= ibuf->x-1; if(y>=ibuf->y) y= ibuf->y-1; if(ibuf->rect) cp= (char *)(ibuf->rect + y*ibuf->x + x); if(ibuf->zbuf) zp= ibuf->zbuf + y*ibuf->x + x; if(ibuf->zbuf_float) zpf= ibuf->zbuf_float + y*ibuf->x + x; if(ibuf->rect_float) fp= (ibuf->rect_float + 4*(y*ibuf->x + x)); if(G.sima->cumap) { float vec[3]; if(fp==NULL) { fp= vec; vec[0]= (float)cp[0]/255.0f; vec[1]= (float)cp[1]/255.0f; vec[2]= (float)cp[2]/255.0f; } if(G.qual & LR_CTRLKEY) { curvemapping_set_black_white(G.sima->cumap, NULL, fp); curvemapping_do_image(G.sima->cumap, G.sima->image); } else if(G.qual & LR_SHIFTKEY) { curvemapping_set_black_white(G.sima->cumap, fp, NULL); curvemapping_do_image(G.sima->cumap, G.sima->image); } } scrarea_do_windraw(curarea); myortho2(-0.375, curarea->winx-0.375, -0.375, curarea->winy-0.375); glLoadIdentity(); sima_show_info(x, y, cp, fp, zp, zpf); screen_swapbuffers(); } } BIF_wait_for_statechange(); } scrarea_queue_winredraw(curarea); }