|
Blender
V2.59
|
00001 /* 00002 * $Id: view3d_select.c 38887 2011-08-01 02:58:44Z 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) 2008 Blender Foundation. 00021 * All rights reserved. 00022 * 00023 * 00024 * Contributor(s): Blender Foundation 00025 * 00026 * ***** END GPL LICENSE BLOCK ***** 00027 */ 00028 00034 #include <string.h> 00035 #include <stdio.h> 00036 #include <math.h> 00037 #include <float.h> 00038 #include <assert.h> 00039 00040 #include "DNA_action_types.h" 00041 #include "DNA_armature_types.h" 00042 #include "DNA_curve_types.h" 00043 #include "DNA_meta_types.h" 00044 #include "DNA_meshdata_types.h" 00045 #include "DNA_object_types.h" 00046 #include "DNA_scene_types.h" 00047 00048 #include "MEM_guardedalloc.h" 00049 00050 #include "BLI_math.h" 00051 #include "BLI_blenlib.h" 00052 #include "BLI_editVert.h" 00053 #include "BLI_rand.h" 00054 #include "BLI_linklist.h" 00055 #include "BLI_utildefines.h" 00056 00057 #include "BKE_context.h" 00058 #include "BKE_paint.h" 00059 #include "BKE_armature.h" 00060 00061 00062 #include "BIF_gl.h" 00063 #include "BIF_glutil.h" 00064 00065 #include "WM_api.h" 00066 #include "WM_types.h" 00067 00068 #include "RNA_access.h" 00069 #include "RNA_define.h" 00070 00071 #include "ED_armature.h" 00072 #include "ED_curve.h" 00073 #include "ED_particle.h" 00074 #include "ED_mesh.h" 00075 #include "ED_object.h" 00076 #include "ED_screen.h" 00077 #include "ED_mball.h" 00078 00079 #include "UI_interface.h" 00080 #include "UI_resources.h" 00081 00082 #include "view3d_intern.h" // own include 00083 00084 // TODO: should return whether there is valid context to continue 00085 void view3d_set_viewcontext(bContext *C, ViewContext *vc) 00086 { 00087 memset(vc, 0, sizeof(ViewContext)); 00088 vc->ar= CTX_wm_region(C); 00089 vc->scene= CTX_data_scene(C); 00090 vc->v3d= CTX_wm_view3d(C); 00091 vc->rv3d= CTX_wm_region_view3d(C); 00092 vc->obact= CTX_data_active_object(C); 00093 vc->obedit= CTX_data_edit_object(C); 00094 } 00095 00096 int view3d_get_view_aligned_coordinate(ViewContext *vc, float fp[3], const int mval[2], const short do_fallback) 00097 { 00098 float dvec[3]; 00099 int mval_cpy[2]; 00100 00101 mval_cpy[0]= mval[0]; 00102 mval_cpy[1]= mval[1]; 00103 00104 project_int_noclip(vc->ar, fp, mval_cpy); 00105 00106 initgrabz(vc->rv3d, fp[0], fp[1], fp[2]); 00107 00108 if(mval_cpy[0]!=IS_CLIPPED) { 00109 float mval_f[2]; 00110 VECSUB2D(mval_f, mval_cpy, mval); 00111 ED_view3d_win_to_delta(vc->ar, mval_f, dvec); 00112 sub_v3_v3(fp, dvec); 00113 00114 return TRUE; 00115 } 00116 else { 00117 /* fallback to the view center */ 00118 if(do_fallback) { 00119 negate_v3_v3(fp, vc->rv3d->ofs); 00120 return view3d_get_view_aligned_coordinate(vc, fp, mval, FALSE); 00121 } 00122 else { 00123 return FALSE; 00124 } 00125 } 00126 } 00127 00128 /* 00129 * ob == NULL if you want global matrices 00130 * */ 00131 void view3d_get_transformation(ARegion *ar, RegionView3D *rv3d, Object *ob, bglMats *mats) 00132 { 00133 float cpy[4][4]; 00134 int i, j; 00135 00136 if (ob) { 00137 mul_m4_m4m4(cpy, ob->obmat, rv3d->viewmat); 00138 } else { 00139 copy_m4_m4(cpy, rv3d->viewmat); 00140 } 00141 00142 for(i = 0; i < 4; ++i) { 00143 for(j = 0; j < 4; ++j) { 00144 mats->projection[i*4+j] = rv3d->winmat[i][j]; 00145 mats->modelview[i*4+j] = cpy[i][j]; 00146 } 00147 } 00148 00149 mats->viewport[0] = ar->winrct.xmin; 00150 mats->viewport[1] = ar->winrct.ymin; 00151 mats->viewport[2] = ar->winx; 00152 mats->viewport[3] = ar->winy; 00153 } 00154 00155 /* ********************** view3d_select: selection manipulations ********************* */ 00156 00157 /* local prototypes */ 00158 00159 static void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select) 00160 { 00161 EditVert *eve; 00162 int index= em_wireoffs; 00163 00164 for(eve= em->verts.first; eve; eve= eve->next, index++) { 00165 if(eve->h==0) { 00166 if(EM_check_backbuf(index)) { 00167 eve->f = select?(eve->f|1):(eve->f&~1); 00168 } 00169 } 00170 } 00171 } 00172 00173 static void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select) 00174 { 00175 EditEdge *eed; 00176 int index= em_solidoffs; 00177 00178 for(eed= em->edges.first; eed; eed= eed->next, index++) { 00179 if(eed->h==0) { 00180 if(EM_check_backbuf(index)) { 00181 EM_select_edge(eed, select); 00182 } 00183 } 00184 } 00185 } 00186 00187 static void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select) 00188 { 00189 EditFace *efa; 00190 int index= 1; 00191 00192 for(efa= em->faces.first; efa; efa= efa->next, index++) { 00193 if(efa->h==0) { 00194 if(EM_check_backbuf(index)) { 00195 EM_select_face_fgon(em, efa, select); 00196 } 00197 } 00198 } 00199 } 00200 00201 static void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select) 00202 { 00203 MFace *mface = me->mface; 00204 int a; 00205 00206 if (mface) { 00207 for(a=1; a<=me->totface; a++, mface++) { 00208 if(EM_check_backbuf(a)) { 00209 mface->flag = select?(mface->flag|ME_FACE_SEL):(mface->flag&~ME_FACE_SEL); 00210 } 00211 } 00212 } 00213 } 00214 00215 /* *********************** GESTURE AND LASSO ******************* */ 00216 00217 static int view3d_selectable_data(bContext *C) 00218 { 00219 Object *ob = CTX_data_active_object(C); 00220 00221 if (!ED_operator_region_view3d_active(C)) 00222 return 0; 00223 00224 if(ob) { 00225 if (ob->mode & OB_MODE_EDIT) { 00226 if(ob->type == OB_FONT) { 00227 return 0; 00228 } 00229 } 00230 else { 00231 if (ob->mode & OB_MODE_SCULPT) { 00232 return 0; 00233 } 00234 if (ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT) && !paint_facesel_test(ob)) { 00235 return 0; 00236 } 00237 } 00238 } 00239 00240 return 1; 00241 } 00242 00243 00244 /* helper also for borderselect */ 00245 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2) 00246 { 00247 return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2); 00248 } 00249 00250 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2) 00251 { 00252 int d1, d2, d3, d4; 00253 00254 /* check points in rect */ 00255 if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1; 00256 00257 /* check points completely out rect */ 00258 if(x1<rect->xmin && x2<rect->xmin) return 0; 00259 if(x1>rect->xmax && x2>rect->xmax) return 0; 00260 if(y1<rect->ymin && y2<rect->ymin) return 0; 00261 if(y1>rect->ymax && y2>rect->ymax) return 0; 00262 00263 /* simple check lines intersecting. */ 00264 d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin ); 00265 d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax ); 00266 d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax ); 00267 d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin ); 00268 00269 if(d1<0 && d2<0 && d3<0 && d4<0) return 0; 00270 if(d1>0 && d2>0 && d3>0 && d4>0) return 0; 00271 00272 return 1; 00273 } 00274 00275 00276 #define MOVES_GESTURE 50 00277 #define MOVES_LASSO 500 00278 00279 int lasso_inside(int mcords[][2], short moves, int sx, int sy) 00280 { 00281 /* we do the angle rule, define that all added angles should be about zero or 2*PI */ 00282 float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2]; 00283 int a; 00284 int *p1, *p2; 00285 00286 if(sx==IS_CLIPPED) 00287 return 0; 00288 00289 p1= mcords[moves-1]; 00290 p2= mcords[0]; 00291 00292 /* first vector */ 00293 fp1[0]= (float)(p1[0]-sx); 00294 fp1[1]= (float)(p1[1]-sy); 00295 len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]); 00296 fp1[0]/= len; 00297 fp1[1]/= len; 00298 00299 for(a=0; a<moves; a++) { 00300 /* second vector */ 00301 fp2[0]= (float)(p2[0]-sx); 00302 fp2[1]= (float)(p2[1]-sy); 00303 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]); 00304 fp2[0]/= len; 00305 fp2[1]/= len; 00306 00307 /* dot and angle and cross */ 00308 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1]; 00309 ang= fabs(saacos(dot)); 00310 00311 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy)); 00312 00313 if(cross<0.0f) angletot-= ang; 00314 else angletot+= ang; 00315 00316 /* circulate */ 00317 fp1[0]= fp2[0]; fp1[1]= fp2[1]; 00318 p1= p2; 00319 p2= mcords[a+1]; 00320 } 00321 00322 if( fabs(angletot) > 4.0 ) return 1; 00323 return 0; 00324 } 00325 00326 /* edge version for lasso select. we assume boundbox check was done */ 00327 int lasso_inside_edge(int mcords[][2], short moves, int x0, int y0, int x1, int y1) 00328 { 00329 int v1[2], v2[2]; 00330 int a; 00331 00332 if(x0==IS_CLIPPED || x1==IS_CLIPPED) 00333 return 0; 00334 00335 v1[0] = x0, v1[1] = y0; 00336 v2[0] = x1, v2[1] = y1; 00337 00338 /* check points in lasso */ 00339 if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1; 00340 if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1; 00341 00342 /* no points in lasso, so we have to intersect with lasso edge */ 00343 00344 if( isect_line_line_v2_int(mcords[0], mcords[moves-1], v1, v2) > 0) return 1; 00345 for(a=0; a<moves-1; a++) { 00346 if( isect_line_line_v2_int(mcords[a], mcords[a+1], v1, v2) > 0) return 1; 00347 } 00348 00349 return 0; 00350 } 00351 00352 00353 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 00354 and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK 00355 */ 00356 static void do_lasso_select_pose(ViewContext *vc, Object *ob, int mcords[][2], short moves, short select) 00357 { 00358 bPoseChannel *pchan; 00359 float vec[3]; 00360 int sco1[2], sco2[2]; 00361 bArmature *arm= ob->data; 00362 00363 if(ob->type!=OB_ARMATURE || ob->pose==NULL) return; 00364 00365 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { 00366 if (PBONE_VISIBLE(arm, pchan->bone) && (pchan->bone->flag & BONE_UNSELECTABLE)==0) { 00367 mul_v3_m4v3(vec, ob->obmat, pchan->pose_head); 00368 project_int(vc->ar, vec, sco1); 00369 mul_v3_m4v3(vec, ob->obmat, pchan->pose_tail); 00370 project_int(vc->ar, vec, sco2); 00371 00372 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) { 00373 if(select) pchan->bone->flag |= BONE_SELECTED; 00374 else pchan->bone->flag &= ~BONE_SELECTED; 00375 } 00376 } 00377 } 00378 } 00379 00380 static void object_deselect_all_visible(Scene *scene, View3D *v3d) 00381 { 00382 Base *base; 00383 00384 for(base= scene->base.first; base; base= base->next) { 00385 if(BASE_SELECTABLE(v3d, base)) { 00386 ED_base_object_select(base, BA_DESELECT); 00387 } 00388 } 00389 } 00390 00391 static void do_lasso_select_objects(ViewContext *vc, int mcords[][2], short moves, short extend, short select) 00392 { 00393 Base *base; 00394 00395 if (extend == 0 && select) 00396 object_deselect_all_visible(vc->scene, vc->v3d); 00397 00398 for(base= vc->scene->base.first; base; base= base->next) { 00399 if(BASE_SELECTABLE(vc->v3d, base)) { /* use this to avoid un-needed lasso lookups */ 00400 project_short(vc->ar, base->object->obmat[3], &base->sx); 00401 if(lasso_inside(mcords, moves, base->sx, base->sy)) { 00402 00403 if(select) ED_base_object_select(base, BA_SELECT); 00404 else ED_base_object_select(base, BA_DESELECT); 00405 base->object->flag= base->flag; 00406 } 00407 if(base->object->mode & OB_MODE_POSE) { 00408 do_lasso_select_pose(vc, base->object, mcords, moves, select); 00409 } 00410 } 00411 } 00412 } 00413 00414 static void lasso_select_boundbox(rcti *rect, int mcords[][2], short moves) 00415 { 00416 short a; 00417 00418 rect->xmin= rect->xmax= mcords[0][0]; 00419 rect->ymin= rect->ymax= mcords[0][1]; 00420 00421 for(a=1; a<moves; a++) { 00422 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0]; 00423 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0]; 00424 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1]; 00425 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1]; 00426 } 00427 } 00428 00429 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int UNUSED(index)) 00430 { 00431 struct { ViewContext vc; rcti *rect; int (*mcords)[2], moves, select, pass, done; } *data = userData; 00432 00433 if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) { 00434 eve->f = data->select?(eve->f|1):(eve->f&~1); 00435 } 00436 } 00437 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index) 00438 { 00439 struct { ViewContext vc; rcti *rect; int (*mcords)[2], moves, select, pass, done; } *data = userData; 00440 00441 if (EM_check_backbuf(em_solidoffs+index)) { 00442 if (data->pass==0) { 00443 if ( edge_fully_inside_rect(data->rect, x0, y0, x1, y1) && 00444 lasso_inside(data->mcords, data->moves, x0, y0) && 00445 lasso_inside(data->mcords, data->moves, x1, y1)) { 00446 EM_select_edge(eed, data->select); 00447 data->done = 1; 00448 } 00449 } else { 00450 if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) { 00451 EM_select_edge(eed, data->select); 00452 } 00453 } 00454 } 00455 } 00456 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int UNUSED(index)) 00457 { 00458 struct { ViewContext vc; rcti *rect; int (*mcords)[2], moves, select, pass, done; } *data = userData; 00459 00460 if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) { 00461 EM_select_face_fgon(data->vc.em, efa, data->select); 00462 } 00463 } 00464 00465 static void do_lasso_select_mesh(ViewContext *vc, int mcords[][2], short moves, short extend, short select) 00466 { 00467 struct { ViewContext vc; rcti *rect; int (*mcords)[2], moves, select, pass, done; } data; 00468 ToolSettings *ts= vc->scene->toolsettings; 00469 rcti rect; 00470 int bbsel; 00471 00472 lasso_select_boundbox(&rect, mcords, moves); 00473 00474 /* set editmesh */ 00475 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh; 00476 00477 data.vc= *vc; 00478 data.rect = ▭ 00479 data.mcords = mcords; 00480 data.moves = moves; 00481 data.select = select; 00482 data.done = 0; 00483 data.pass = 0; 00484 00485 if (extend == 0 && select) 00486 EM_deselect_all(vc->em); 00487 00488 /* for non zbuf projections, dont change the GL state */ 00489 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); 00490 00491 glLoadMatrixf(vc->rv3d->viewmat); 00492 bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); 00493 00494 if(ts->selectmode & SCE_SELECT_VERTEX) { 00495 if (bbsel) { 00496 EM_backbuf_checkAndSelectVerts(vc->em, select); 00497 } 00498 else { 00499 mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1); 00500 } 00501 } 00502 if(ts->selectmode & SCE_SELECT_EDGE) { 00503 /* Does both bbsel and non-bbsel versions (need screen cos for both) */ 00504 data.pass = 0; 00505 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0); 00506 00507 if (data.done==0) { 00508 data.pass = 1; 00509 mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, 0); 00510 } 00511 } 00512 00513 if(ts->selectmode & SCE_SELECT_FACE) { 00514 if (bbsel) { 00515 EM_backbuf_checkAndSelectFaces(vc->em, select); 00516 } 00517 else { 00518 mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data); 00519 } 00520 } 00521 00522 EM_free_backbuf(); 00523 EM_selectmode_flush(vc->em); 00524 } 00525 00526 #if 0 00527 /* this is an exception in that its the only lasso that dosnt use the 3d view (uses space image view) */ 00528 static void do_lasso_select_mesh_uv(int mcords[][2], short moves, short select) 00529 { 00530 EditFace *efa; 00531 MTFace *tf; 00532 int screenUV[2], nverts, i, ok = 1; 00533 rcti rect; 00534 00535 lasso_select_boundbox(&rect, mcords, moves); 00536 00537 if (draw_uvs_face_check()) { /* Face Center Sel */ 00538 float cent[2]; 00539 ok = 0; 00540 for (efa= em->faces.first; efa; efa= efa->next) { 00541 /* assume not touched */ 00542 efa->tmp.l = 0; 00543 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00544 if ((select) != (simaFaceSel_Check(efa, tf))) { 00545 uv_center(tf->uv, cent, (void *)efa->v4); 00546 uvco_to_areaco_noclip(cent, screenUV); 00547 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) { 00548 efa->tmp.l = ok = 1; 00549 } 00550 } 00551 } 00552 /* (de)selects all tagged faces and deals with sticky modes */ 00553 if (ok) 00554 uvface_setsel__internal(select); 00555 00556 } else { /* Vert Sel*/ 00557 for (efa= em->faces.first; efa; efa= efa->next) { 00558 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); 00559 if (uvedit_face_visible(scene, ima, efa, tf)) { 00560 nverts= efa->v4? 4: 3; 00561 for(i=0; i<nverts; i++) { 00562 if ((select) != (simaUVSel_Check(efa, tf, i))) { 00563 uvco_to_areaco_noclip(tf->uv[i], screenUV); 00564 if (BLI_in_rcti(&rect, screenUV[0], screenUV[1]) && lasso_inside(mcords, moves, screenUV[0], screenUV[1])) { 00565 if (select) { 00566 simaUVSel_Set(efa, tf, i); 00567 } else { 00568 simaUVSel_UnSet(efa, tf, i); 00569 } 00570 } 00571 } 00572 } 00573 } 00574 } 00575 } 00576 if (ok && G.sima->flag & SI_SYNC_UVSEL) { 00577 if (select) EM_select_flush(vc->em); 00578 else EM_deselect_flush(vc->em); 00579 } 00580 } 00581 #endif 00582 00583 static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y) 00584 { 00585 struct { ViewContext *vc; int (*mcords)[2]; short moves; short select; } *data = userData; 00586 Object *obedit= data->vc->obedit; 00587 Curve *cu= (Curve*)obedit->data; 00588 00589 if (lasso_inside(data->mcords, data->moves, x, y)) { 00590 if (bp) { 00591 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT); 00592 if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL; 00593 } else { 00594 if (cu->drawflag & CU_HIDE_HANDLES) { 00595 /* can only be beztindex==0 here since handles are hidden */ 00596 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT); 00597 } else { 00598 if (beztindex==0) { 00599 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT); 00600 } else if (beztindex==1) { 00601 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT); 00602 } else { 00603 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT); 00604 } 00605 } 00606 00607 if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL; 00608 } 00609 } 00610 } 00611 00612 static void do_lasso_select_curve(ViewContext *vc, int mcords[][2], short moves, short extend, short select) 00613 { 00614 struct { ViewContext *vc; int (*mcords)[2]; short moves; short select; } data; 00615 00616 /* set vc->editnurb */ 00617 data.vc = vc; 00618 data.mcords = mcords; 00619 data.moves = moves; 00620 data.select = select; 00621 00622 if (extend == 0 && select) 00623 CU_deselect_all(vc->obedit); 00624 00625 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 00626 nurbs_foreachScreenVert(vc, do_lasso_select_curve__doSelect, &data); 00627 } 00628 00629 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y) 00630 { 00631 struct { int (*mcords)[2]; short moves; short select; } *data = userData; 00632 00633 if (lasso_inside(data->mcords, data->moves, x, y)) { 00634 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT); 00635 } 00636 } 00637 static void do_lasso_select_lattice(ViewContext *vc, int mcords[][2], short moves, short extend, short select) 00638 { 00639 struct { int (*mcords)[2]; short moves; short select; } data; 00640 00641 /* set editdata in vc */ 00642 data.mcords = mcords; 00643 data.moves = moves; 00644 data.select = select; 00645 00646 if (extend == 0 && select) 00647 ED_setflagsLatt(vc->obedit, 0); 00648 00649 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 00650 lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data); 00651 } 00652 00653 static void do_lasso_select_armature(ViewContext *vc, int mcords[][2], short moves, short extend, short select) 00654 { 00655 bArmature *arm= vc->obedit->data; 00656 EditBone *ebone; 00657 float vec[3]; 00658 short sco1[2], sco2[2], didpoint; 00659 int change= FALSE; 00660 00661 if (extend==0 && select) 00662 ED_armature_deselect_all_visible(vc->obedit); 00663 00664 /* set editdata in vc */ 00665 00666 for (ebone= arm->edbo->first; ebone; ebone=ebone->next) { 00667 if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_UNSELECTABLE)==0) { 00668 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); 00669 project_short(vc->ar, vec, sco1); 00670 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); 00671 project_short(vc->ar, vec, sco2); 00672 00673 didpoint= 0; 00674 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) { 00675 if(select) ebone->flag |= BONE_ROOTSEL; 00676 else ebone->flag &= ~BONE_ROOTSEL; 00677 didpoint= 1; 00678 change= TRUE; 00679 } 00680 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) { 00681 if(select) ebone->flag |= BONE_TIPSEL; 00682 else ebone->flag &= ~BONE_TIPSEL; 00683 didpoint= 1; 00684 change= TRUE; 00685 } 00686 /* if one of points selected, we skip the bone itself */ 00687 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) { 00688 if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED; 00689 else ebone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); 00690 change= TRUE; 00691 } 00692 } 00693 } 00694 00695 if(change) { 00696 ED_armature_sync_selection(arm->edbo); 00697 ED_armature_validate_active(arm); 00698 WM_main_add_notifier(NC_OBJECT|ND_BONE_SELECT, vc->obedit); 00699 } 00700 } 00701 00702 00703 00704 00705 static void do_lasso_select_meta(ViewContext *vc, int mcords[][2], short moves, short extend, short select) 00706 { 00707 MetaBall *mb = (MetaBall*)vc->obedit->data; 00708 MetaElem *ml; 00709 float vec[3]; 00710 short sco[2]; 00711 00712 if (extend == 0 && select) { 00713 for(ml= mb->editelems->first; ml; ml= ml->next) { 00714 ml->flag &= ~SELECT; 00715 } 00716 } 00717 00718 for(ml= mb->editelems->first; ml; ml= ml->next) { 00719 00720 mul_v3_m4v3(vec, vc->obedit->obmat, &ml->x); 00721 project_short(vc->ar, vec, sco); 00722 00723 if(lasso_inside(mcords, moves, sco[0], sco[1])) { 00724 if(select) ml->flag |= SELECT; 00725 else ml->flag &= ~SELECT; 00726 } 00727 } 00728 } 00729 00730 static void do_lasso_select_paintface(ViewContext *vc, int mcords[][2], short moves, short extend, short select) 00731 { 00732 Object *ob= vc->obact; 00733 Mesh *me= ob?ob->data:NULL; 00734 rcti rect; 00735 00736 if(me==NULL || me->totface==0) 00737 return; 00738 00739 if(extend==0 && select) 00740 paintface_deselect_all_visible(ob, SEL_DESELECT, FALSE); /* flush selection at the end */ 00741 00742 em_vertoffs= me->totface+1; /* max index array */ 00743 00744 lasso_select_boundbox(&rect, mcords, moves); 00745 EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); 00746 00747 EM_backbuf_checkAndSelectTFaces(me, select); 00748 00749 EM_free_backbuf(); 00750 00751 paintface_flush_flags(ob); 00752 } 00753 00754 #if 0 00755 static void do_lasso_select_node(int mcords[][2], short moves, short select) 00756 { 00757 SpaceNode *snode = sa->spacedata.first; 00758 00759 bNode *node; 00760 rcti rect; 00761 short node_cent[2]; 00762 float node_centf[2]; 00763 00764 lasso_select_boundbox(&rect, mcords, moves); 00765 00766 /* store selection in temp test flag */ 00767 for(node= snode->edittree->nodes.first; node; node= node->next) { 00768 00769 node_centf[0] = (node->totr.xmin+node->totr.xmax)/2; 00770 node_centf[1] = (node->totr.ymin+node->totr.ymax)/2; 00771 00772 ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent); 00773 if (BLI_in_rcti(&rect, node_cent[0], node_cent[1]) && lasso_inside(mcords, moves, node_cent[0], node_cent[1])) { 00774 if (select) { 00775 node->flag |= SELECT; 00776 } else { 00777 node->flag &= ~SELECT; 00778 } 00779 } 00780 } 00781 BIF_undo_push("Lasso select nodes"); 00782 } 00783 #endif 00784 00785 static void view3d_lasso_select(bContext *C, ViewContext *vc, int mcords[][2], short moves, short extend, short select) 00786 { 00787 Object *ob = CTX_data_active_object(C); 00788 00789 if(vc->obedit==NULL) { /* Object Mode */ 00790 if(paint_facesel_test(ob)) 00791 do_lasso_select_paintface(vc, mcords, moves, extend, select); 00792 else if(ob && ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT)) 00793 ; 00794 else if(ob && ob->mode & OB_MODE_PARTICLE_EDIT) 00795 PE_lasso_select(C, mcords, moves, extend, select); 00796 else { 00797 do_lasso_select_objects(vc, mcords, moves, extend, select); 00798 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, vc->scene); 00799 } 00800 } 00801 else { /* Edit Mode */ 00802 switch(vc->obedit->type) { 00803 case OB_MESH: 00804 do_lasso_select_mesh(vc, mcords, moves, extend, select); 00805 break; 00806 case OB_CURVE: 00807 case OB_SURF: 00808 do_lasso_select_curve(vc, mcords, moves, extend, select); 00809 break; 00810 case OB_LATTICE: 00811 do_lasso_select_lattice(vc, mcords, moves, extend, select); 00812 break; 00813 case OB_ARMATURE: 00814 do_lasso_select_armature(vc, mcords, moves, extend, select); 00815 break; 00816 case OB_MBALL: 00817 do_lasso_select_meta(vc, mcords, moves, extend, select); 00818 break; 00819 default: 00820 assert(!"lasso select on incorrect object type"); 00821 } 00822 00823 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc->obedit->data); 00824 } 00825 } 00826 00827 00828 /* lasso operator gives properties, but since old code works 00829 with short array we convert */ 00830 static int view3d_lasso_select_exec(bContext *C, wmOperator *op) 00831 { 00832 ViewContext vc; 00833 int i= 0; 00834 int mcords[1024][2]; 00835 00836 RNA_BEGIN(op->ptr, itemptr, "path") { 00837 float loc[2]; 00838 00839 RNA_float_get_array(&itemptr, "loc", loc); 00840 mcords[i][0]= (int)loc[0]; 00841 mcords[i][1]= (int)loc[1]; 00842 i++; 00843 if(i>=1024) break; 00844 } 00845 RNA_END; 00846 00847 if(i>1) { 00848 short extend, select; 00849 view3d_operator_needs_opengl(C); 00850 00851 /* setup view context for argument to callbacks */ 00852 view3d_set_viewcontext(C, &vc); 00853 00854 extend= RNA_boolean_get(op->ptr, "extend"); 00855 select= !RNA_boolean_get(op->ptr, "deselect"); 00856 view3d_lasso_select(C, &vc, mcords, i, extend, select); 00857 00858 return OPERATOR_FINISHED; 00859 } 00860 return OPERATOR_PASS_THROUGH; 00861 } 00862 00863 void VIEW3D_OT_select_lasso(wmOperatorType *ot) 00864 { 00865 ot->name= "Lasso Select"; 00866 ot->description= "Select items using lasso selection"; 00867 ot->idname= "VIEW3D_OT_select_lasso"; 00868 00869 ot->invoke= WM_gesture_lasso_invoke; 00870 ot->modal= WM_gesture_lasso_modal; 00871 ot->exec= view3d_lasso_select_exec; 00872 ot->poll= view3d_selectable_data; 00873 ot->cancel= WM_gesture_lasso_cancel; 00874 00875 /* flags */ 00876 ot->flag= OPTYPE_UNDO; 00877 00878 RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); 00879 RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items."); 00880 RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first."); 00881 } 00882 00883 00884 /* ************************************************* */ 00885 00886 #if 0 00887 /* smart function to sample a rect spiralling outside, nice for backbuf selection */ 00888 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo) 00889 { 00890 Base *base; 00891 unsigned int *bufmin,*bufmax; 00892 int a,b,rc,tel,len,dirvec[4][2],maxob; 00893 unsigned int retval=0; 00894 00895 base= LASTBASE; 00896 if(base==0) return 0; 00897 maxob= base->selcol; 00898 00899 len= (size-1)/2; 00900 rc= 0; 00901 00902 dirvec[0][0]= 1; 00903 dirvec[0][1]= 0; 00904 dirvec[1][0]= 0; 00905 dirvec[1][1]= -size; 00906 dirvec[2][0]= -1; 00907 dirvec[2][1]= 0; 00908 dirvec[3][0]= 0; 00909 dirvec[3][1]= size; 00910 00911 bufmin= buf; 00912 bufmax= buf+ size*size; 00913 buf+= len*size+ len; 00914 00915 for(tel=1;tel<=size;tel++) { 00916 00917 for(a=0;a<2;a++) { 00918 for(b=0;b<tel;b++) { 00919 00920 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf; 00921 if( *buf==dontdo ) retval= dontdo; /* if only color dontdo is available, still return dontdo */ 00922 00923 buf+= (dirvec[rc][0]+dirvec[rc][1]); 00924 00925 if(buf<bufmin || buf>=bufmax) return retval; 00926 } 00927 rc++; 00928 rc &= 3; 00929 } 00930 } 00931 return retval; 00932 } 00933 #endif 00934 00935 /* ************************** mouse select ************************* */ 00936 00937 00938 /* The max number of menu items in an object select menu */ 00939 #define SEL_MENU_SIZE 22 00940 00941 static void deselectall_except(Scene *scene, Base *b) /* deselect all except b */ 00942 { 00943 Base *base; 00944 00945 for(base= FIRSTBASE; base; base= base->next) { 00946 if (base->flag & SELECT) { 00947 if(b!=base) { 00948 ED_base_object_select(base, BA_DESELECT); 00949 } 00950 } 00951 } 00952 } 00953 00954 static Base *mouse_select_menu(bContext *C, ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], short extend) 00955 { 00956 short baseCount = 0; 00957 short ok; 00958 LinkNode *linklist= NULL; 00959 00960 CTX_DATA_BEGIN(C, Base*, base, selectable_bases) { 00961 ok= FALSE; 00962 00963 /* two selection methods, the CTRL select uses max dist of 15 */ 00964 if(buffer) { 00965 int a; 00966 for(a=0; a<hits; a++) { 00967 /* index was converted */ 00968 if(base->selcol==buffer[ (4 * a) + 3 ]) 00969 ok= TRUE; 00970 } 00971 } 00972 else { 00973 int temp, dist=15; 00974 00975 project_short(vc->ar, base->object->obmat[3], &base->sx); 00976 00977 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]); 00978 if(temp < dist) 00979 ok= TRUE; 00980 } 00981 00982 if(ok) { 00983 baseCount++; 00984 BLI_linklist_prepend(&linklist, base); 00985 00986 if (baseCount==SEL_MENU_SIZE) 00987 break; 00988 } 00989 } 00990 CTX_DATA_END; 00991 00992 if(baseCount) 00993 00994 00995 if(baseCount==0) { 00996 return NULL; 00997 } 00998 if(baseCount == 1) { 00999 Base *base= (Base *)linklist->link; 01000 BLI_linklist_free(linklist, NULL); 01001 return base; 01002 } 01003 else { 01004 /* UI */ 01005 uiPopupMenu *pup= uiPupMenuBegin(C, "Select Object", ICON_NONE); 01006 uiLayout *layout= uiPupMenuLayout(pup); 01007 uiLayout *split= uiLayoutSplit(layout, 0, 0); 01008 uiLayout *column= uiLayoutColumn(split, 0); 01009 LinkNode *node; 01010 01011 node= linklist; 01012 while(node) { 01013 Base *base=node->link; 01014 Object *ob= base->object; 01015 char *name= ob->id.name+2; 01016 /* annoying!, since we need to set 2 props cant use this. */ 01017 /* uiItemStringO(column, name, 0, "OBJECT_OT_select_name", "name", name); */ 01018 01019 { 01020 PointerRNA ptr; 01021 01022 WM_operator_properties_create(&ptr, "OBJECT_OT_select_name"); 01023 RNA_string_set(&ptr, "name", name); 01024 RNA_boolean_set(&ptr, "extend", extend); 01025 uiItemFullO(column, "OBJECT_OT_select_name", name, uiIconFromID((ID *)ob), ptr.data, WM_OP_EXEC_DEFAULT, 0); 01026 } 01027 01028 node= node->next; 01029 } 01030 01031 uiPupMenuEnd(C, pup); 01032 01033 BLI_linklist_free(linklist, NULL); 01034 return NULL; 01035 } 01036 } 01037 01038 /* we want a select buffer with bones, if there are... */ 01039 /* so check three selection levels and compare */ 01040 static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2]) 01041 { 01042 rcti rect; 01043 int offs; 01044 short a, hits15, hits9=0, hits5=0; 01045 short has_bones15=0, has_bones9=0, has_bones5=0; 01046 01047 BLI_init_rcti(&rect, mval[0]-14, mval[0]+14, mval[1]-14, mval[1]+14); 01048 hits15= view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect); 01049 if(hits15>0) { 01050 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1; 01051 01052 offs= 4*hits15; 01053 BLI_init_rcti(&rect, mval[0]-9, mval[0]+9, mval[1]-9, mval[1]+9); 01054 hits9= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect); 01055 if(hits9>0) { 01056 for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1; 01057 01058 offs+= 4*hits9; 01059 BLI_init_rcti(&rect, mval[0]-5, mval[0]+5, mval[1]-5, mval[1]+5); 01060 hits5= view3d_opengl_select(vc, buffer+offs, MAXPICKBUF-offs, &rect); 01061 if(hits5>0) { 01062 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1; 01063 } 01064 } 01065 01066 if(has_bones5) { 01067 offs= 4*hits15 + 4*hits9; 01068 memcpy(buffer, buffer+offs, 4*offs); 01069 return hits5; 01070 } 01071 if(has_bones9) { 01072 offs= 4*hits15; 01073 memcpy(buffer, buffer+offs, 4*offs); 01074 return hits9; 01075 } 01076 if(has_bones15) { 01077 return hits15; 01078 } 01079 01080 if(hits5>0) { 01081 offs= 4*hits15 + 4*hits9; 01082 memcpy(buffer, buffer+offs, 4*offs); 01083 return hits5; 01084 } 01085 if(hits9>0) { 01086 offs= 4*hits15; 01087 memcpy(buffer, buffer+offs, 4*offs); 01088 return hits9; 01089 } 01090 return hits15; 01091 } 01092 01093 return 0; 01094 } 01095 01096 /* returns basact */ 01097 static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, const int mval[2], Base *startbase, int has_bones) 01098 { 01099 Scene *scene= vc->scene; 01100 View3D *v3d= vc->v3d; 01101 Base *base, *basact= NULL; 01102 static int lastmval[2]={-100, -100}; 01103 int a, donearest= 0; 01104 01105 /* define if we use solid nearest select or not */ 01106 if(v3d->drawtype>OB_WIRE) { 01107 donearest= 1; 01108 if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) { 01109 if(!has_bones) /* hrms, if theres bones we always do nearest */ 01110 donearest= 0; 01111 } 01112 } 01113 lastmval[0]= mval[0]; lastmval[1]= mval[1]; 01114 01115 if(donearest) { 01116 unsigned int min= 0xFFFFFFFF; 01117 int selcol= 0, notcol=0; 01118 01119 01120 if(has_bones) { 01121 /* we skip non-bone hits */ 01122 for(a=0; a<hits; a++) { 01123 if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) { 01124 min= buffer[4*a+1]; 01125 selcol= buffer[4*a+3] & 0xFFFF; 01126 } 01127 } 01128 } 01129 else { 01130 /* only exclude active object when it is selected... */ 01131 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 01132 01133 for(a=0; a<hits; a++) { 01134 if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) { 01135 min= buffer[4*a+1]; 01136 selcol= buffer[4*a+3] & 0xFFFF; 01137 } 01138 } 01139 } 01140 01141 base= FIRSTBASE; 01142 while(base) { 01143 if(BASE_SELECTABLE(v3d, base)) { 01144 if(base->selcol==selcol) break; 01145 } 01146 base= base->next; 01147 } 01148 if(base) basact= base; 01149 } 01150 else { 01151 01152 base= startbase; 01153 while(base) { 01154 /* skip objects with select restriction, to prevent prematurely ending this loop 01155 * with an un-selectable choice */ 01156 if (base->object->restrictflag & OB_RESTRICT_SELECT) { 01157 base=base->next; 01158 if(base==NULL) base= FIRSTBASE; 01159 if(base==startbase) break; 01160 } 01161 01162 if(BASE_SELECTABLE(v3d, base)) { 01163 for(a=0; a<hits; a++) { 01164 if(has_bones) { 01165 /* skip non-bone objects */ 01166 if((buffer[4*a+3] & 0xFFFF0000)) { 01167 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF)) 01168 basact= base; 01169 } 01170 } 01171 else { 01172 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF)) 01173 basact= base; 01174 } 01175 } 01176 } 01177 01178 if(basact) break; 01179 01180 base= base->next; 01181 if(base==NULL) base= FIRSTBASE; 01182 if(base==startbase) break; 01183 } 01184 } 01185 01186 return basact; 01187 } 01188 01189 /* mval comes from event->mval, only use within region handlers */ 01190 Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2]) 01191 { 01192 ViewContext vc; 01193 Base *basact= NULL; 01194 unsigned int buffer[4*MAXPICKBUF]; 01195 int hits; 01196 01197 /* setup view context for argument to callbacks */ 01198 view3d_operator_needs_opengl(C); 01199 view3d_set_viewcontext(C, &vc); 01200 01201 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval); 01202 01203 if(hits>0) { 01204 int a, has_bones= 0; 01205 01206 for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1; 01207 01208 basact= mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones); 01209 } 01210 01211 return basact; 01212 } 01213 01214 /* mval is region coords */ 01215 static int mouse_select(bContext *C, const int mval[2], short extend, short obcenter, short enumerate) 01216 { 01217 ViewContext vc; 01218 ARegion *ar= CTX_wm_region(C); 01219 View3D *v3d= CTX_wm_view3d(C); 01220 Scene *scene= CTX_data_scene(C); 01221 Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL; 01222 int temp, a, dist=100; 01223 int retval = 0; 01224 short hits; 01225 01226 /* setup view context for argument to callbacks */ 01227 view3d_set_viewcontext(C, &vc); 01228 01229 /* always start list from basact in wire mode */ 01230 startbase= FIRSTBASE; 01231 if(BASACT && BASACT->next) startbase= BASACT->next; 01232 01233 /* This block uses the control key to make the object selected by its center point rather than its contents */ 01234 /* XXX later on, in editmode do not activate */ 01235 if(vc.obedit==NULL && obcenter) { 01236 01237 /* note; shift+alt goes to group-flush-selecting */ 01238 if(enumerate) { 01239 basact= mouse_select_menu(C, &vc, NULL, 0, mval, extend); 01240 } else { 01241 base= startbase; 01242 while(base) { 01243 if (BASE_SELECTABLE(v3d, base)) { 01244 project_short(ar, base->object->obmat[3], &base->sx); 01245 01246 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]); 01247 if(base==BASACT) temp+=10; 01248 if(temp<dist ) { 01249 01250 dist= temp; 01251 basact= base; 01252 } 01253 } 01254 base= base->next; 01255 01256 if(base==NULL) base= FIRSTBASE; 01257 if(base==startbase) break; 01258 } 01259 } 01260 } 01261 else { 01262 unsigned int buffer[4*MAXPICKBUF]; 01263 01264 /* if objects have posemode set, the bones are in the same selection buffer */ 01265 01266 hits= mixed_bones_object_selectbuffer(&vc, buffer, mval); 01267 01268 if(hits>0) { 01269 int has_bones= 0; 01270 01271 for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1; 01272 01273 /* note; shift+alt goes to group-flush-selecting */ 01274 if(has_bones==0 && enumerate) { 01275 basact= mouse_select_menu(C, &vc, buffer, hits, mval, extend); 01276 } else { 01277 basact= mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones); 01278 } 01279 01280 if(has_bones && basact) { 01281 if(ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend) ) { /* then bone is found */ 01282 01283 /* we make the armature selected: 01284 not-selected active object in posemode won't work well for tools */ 01285 basact->flag|= SELECT; 01286 basact->object->flag= basact->flag; 01287 01288 retval = 1; 01289 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, basact->object); 01290 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE, basact->object); 01291 01292 /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */ 01293 if(BASACT && BASACT->object->mode & OB_MODE_WEIGHT_PAINT) { 01294 /* prevent activating */ 01295 basact= NULL; 01296 } 01297 01298 } 01299 /* prevent bone selecting to pass on to object selecting */ 01300 if(basact==BASACT) 01301 basact= NULL; 01302 } 01303 } 01304 } 01305 01306 /* so, do we have something selected? */ 01307 if(basact) { 01308 retval = 1; 01309 01310 if(vc.obedit) { 01311 /* only do select */ 01312 deselectall_except(scene, basact); 01313 ED_base_object_select(basact, BA_SELECT); 01314 } 01315 /* also prevent making it active on mouse selection */ 01316 else if (BASE_SELECTABLE(v3d, basact)) { 01317 01318 oldbasact= BASACT; 01319 01320 if(!extend) { 01321 deselectall_except(scene, basact); 01322 ED_base_object_select(basact, BA_SELECT); 01323 } 01324 else if(0) { 01325 // XXX select_all_from_groups(basact); 01326 } 01327 else { 01328 if(basact->flag & SELECT) { 01329 if(basact==oldbasact) 01330 ED_base_object_select(basact, BA_DESELECT); 01331 } 01332 else ED_base_object_select(basact, BA_SELECT); 01333 } 01334 01335 if(oldbasact != basact) { 01336 ED_base_object_activate(C, basact); /* adds notifier */ 01337 } 01338 01339 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene); 01340 } 01341 } 01342 01343 return retval; 01344 } 01345 01346 /* ******************** border and circle ************************************** */ 01347 01348 01349 int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2) 01350 { 01351 int radsq= rad*rad; 01352 float v1[2], v2[2], v3[2]; 01353 01354 /* check points in circle itself */ 01355 if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1; 01356 if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1; 01357 01358 /* pointdistline */ 01359 v3[0]= centx; 01360 v3[1]= centy; 01361 v1[0]= x1; 01362 v1[1]= y1; 01363 v2[0]= x2; 01364 v2[1]= y2; 01365 01366 if( dist_to_line_segment_v2(v3, v1, v2) < (float)rad ) return 1; 01367 01368 return 0; 01369 } 01370 01371 static void do_nurbs_box_select__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y) 01372 { 01373 struct { ViewContext *vc; rcti *rect; int select; } *data = userData; 01374 Object *obedit= data->vc->obedit; 01375 Curve *cu= (Curve*)obedit->data; 01376 01377 if (BLI_in_rcti(data->rect, x, y)) { 01378 if (bp) { 01379 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT); 01380 if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL; 01381 } else { 01382 if (cu->drawflag & CU_HIDE_HANDLES) { 01383 /* can only be beztindex==0 here since handles are hidden */ 01384 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT); 01385 } else { 01386 if (beztindex==0) { 01387 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT); 01388 } else if (beztindex==1) { 01389 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT); 01390 } else { 01391 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT); 01392 } 01393 } 01394 01395 if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL; 01396 } 01397 } 01398 } 01399 static int do_nurbs_box_select(ViewContext *vc, rcti *rect, int select, int extend) 01400 { 01401 struct { ViewContext *vc; rcti *rect; int select; } data; 01402 01403 data.vc = vc; 01404 data.rect = rect; 01405 data.select = select; 01406 01407 if (extend == 0 && select) 01408 CU_deselect_all(vc->obedit); 01409 01410 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 01411 nurbs_foreachScreenVert(vc, do_nurbs_box_select__doSelect, &data); 01412 01413 return OPERATOR_FINISHED; 01414 } 01415 01416 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y) 01417 { 01418 struct { ViewContext vc; rcti *rect; int select; } *data = userData; 01419 01420 if (BLI_in_rcti(data->rect, x, y)) { 01421 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT); 01422 } 01423 } 01424 static int do_lattice_box_select(ViewContext *vc, rcti *rect, int select, int extend) 01425 { 01426 struct { ViewContext vc; rcti *rect; int select, pass, done; } data; 01427 01428 data.vc= *vc; 01429 data.rect = rect; 01430 data.select = select; 01431 01432 if (extend == 0 && select) 01433 ED_setflagsLatt(vc->obedit, 0); 01434 01435 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 01436 lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data); 01437 01438 return OPERATOR_FINISHED; 01439 } 01440 01441 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int UNUSED(index)) 01442 { 01443 struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData; 01444 01445 if (BLI_in_rcti(data->rect, x, y)) { 01446 eve->f = data->select?(eve->f|1):(eve->f&~1); 01447 } 01448 } 01449 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index) 01450 { 01451 struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData; 01452 01453 if(EM_check_backbuf(em_solidoffs+index)) { 01454 if (data->pass==0) { 01455 if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) { 01456 EM_select_edge(eed, data->select); 01457 data->done = 1; 01458 } 01459 } else { 01460 if (edge_inside_rect(data->rect, x0, y0, x1, y1)) { 01461 EM_select_edge(eed, data->select); 01462 } 01463 } 01464 } 01465 } 01466 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int UNUSED(index)) 01467 { 01468 struct { ViewContext vc; rcti *rect; short select, pass, done; } *data = userData; 01469 01470 if (BLI_in_rcti(data->rect, x, y)) { 01471 EM_select_face_fgon(data->vc.em, efa, data->select); 01472 } 01473 } 01474 static int do_mesh_box_select(ViewContext *vc, rcti *rect, int select, int extend) 01475 { 01476 struct { ViewContext vc; rcti *rect; short select, pass, done; } data; 01477 ToolSettings *ts= vc->scene->toolsettings; 01478 int bbsel; 01479 01480 data.vc= *vc; 01481 data.rect = rect; 01482 data.select = select; 01483 data.pass = 0; 01484 data.done = 0; 01485 01486 if (extend == 0 && select) 01487 EM_deselect_all(vc->em); 01488 01489 /* for non zbuf projections, dont change the GL state */ 01490 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); 01491 01492 glLoadMatrixf(vc->rv3d->viewmat); 01493 bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax); 01494 01495 if(ts->selectmode & SCE_SELECT_VERTEX) { 01496 if (bbsel) { 01497 EM_backbuf_checkAndSelectVerts(vc->em, select); 01498 } else { 01499 mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1); 01500 } 01501 } 01502 if(ts->selectmode & SCE_SELECT_EDGE) { 01503 /* Does both bbsel and non-bbsel versions (need screen cos for both) */ 01504 01505 data.pass = 0; 01506 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0); 01507 01508 if (data.done==0) { 01509 data.pass = 1; 01510 mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, 0); 01511 } 01512 } 01513 01514 if(ts->selectmode & SCE_SELECT_FACE) { 01515 if(bbsel) { 01516 EM_backbuf_checkAndSelectFaces(vc->em, select); 01517 } else { 01518 mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data); 01519 } 01520 } 01521 01522 EM_free_backbuf(); 01523 01524 EM_selectmode_flush(vc->em); 01525 01526 return OPERATOR_FINISHED; 01527 } 01528 01529 static int do_meta_box_select(ViewContext *vc, rcti *rect, int select, int extend) 01530 { 01531 MetaBall *mb = (MetaBall*)vc->obedit->data; 01532 MetaElem *ml; 01533 int a; 01534 01535 unsigned int buffer[4*MAXPICKBUF]; 01536 short hits; 01537 01538 hits= view3d_opengl_select(vc, buffer, MAXPICKBUF, rect); 01539 01540 if (extend == 0 && select) { 01541 for(ml= mb->editelems->first; ml; ml= ml->next) { 01542 ml->flag &= ~SELECT; 01543 } 01544 } 01545 01546 for(ml= mb->editelems->first; ml; ml= ml->next) { 01547 for(a=0; a<hits; a++) { 01548 if(ml->selcol1==buffer[ (4 * a) + 3 ]) { 01549 ml->flag |= MB_SCALE_RAD; 01550 if(select) ml->flag |= SELECT; 01551 else ml->flag &= ~SELECT; 01552 break; 01553 } 01554 if(ml->selcol2==buffer[ (4 * a) + 3 ]) { 01555 ml->flag &= ~MB_SCALE_RAD; 01556 if(select) ml->flag |= SELECT; 01557 else ml->flag &= ~SELECT; 01558 break; 01559 } 01560 } 01561 } 01562 01563 return OPERATOR_FINISHED; 01564 } 01565 01566 static int do_armature_box_select(ViewContext *vc, rcti *rect, short select, short extend) 01567 { 01568 bArmature *arm= vc->obedit->data; 01569 EditBone *ebone; 01570 int a; 01571 01572 unsigned int buffer[4*MAXPICKBUF]; 01573 short hits; 01574 01575 hits= view3d_opengl_select(vc, buffer, MAXPICKBUF, rect); 01576 01577 /* clear flag we use to detect point was affected */ 01578 for(ebone= arm->edbo->first; ebone; ebone= ebone->next) 01579 ebone->flag &= ~BONE_DONE; 01580 01581 if (extend==0 && select) 01582 ED_armature_deselect_all_visible(vc->obedit); 01583 01584 /* first we only check points inside the border */ 01585 for (a=0; a<hits; a++){ 01586 int index = buffer[(4*a)+3]; 01587 if (index!=-1) { 01588 ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY)); 01589 if ((ebone->flag & BONE_UNSELECTABLE)==0) { 01590 if (index & BONESEL_TIP) { 01591 ebone->flag |= BONE_DONE; 01592 if (select) ebone->flag |= BONE_TIPSEL; 01593 else ebone->flag &= ~BONE_TIPSEL; 01594 } 01595 01596 if (index & BONESEL_ROOT) { 01597 ebone->flag |= BONE_DONE; 01598 if (select) ebone->flag |= BONE_ROOTSEL; 01599 else ebone->flag &= ~BONE_ROOTSEL; 01600 } 01601 } 01602 } 01603 } 01604 01605 /* now we have to flush tag from parents... */ 01606 for(ebone= arm->edbo->first; ebone; ebone= ebone->next) { 01607 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) { 01608 if(ebone->parent->flag & BONE_DONE) 01609 ebone->flag |= BONE_DONE; 01610 } 01611 } 01612 01613 /* only select/deselect entire bones when no points where in the rect */ 01614 for (a=0; a<hits; a++){ 01615 int index = buffer[(4*a)+3]; 01616 if (index!=-1) { 01617 ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY)); 01618 if (index & BONESEL_BONE) { 01619 if ((ebone->flag & BONE_UNSELECTABLE)==0) { 01620 if(!(ebone->flag & BONE_DONE)) { 01621 if (select) 01622 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED); 01623 else 01624 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED); 01625 } 01626 } 01627 } 01628 } 01629 } 01630 01631 ED_armature_sync_selection(arm->edbo); 01632 01633 return OPERATOR_CANCELLED; 01634 } 01635 01636 static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, int select, int extend) 01637 { 01638 Bone *bone; 01639 Object *ob= vc->obact; 01640 unsigned int *vbuffer=NULL; /* selection buffer */ 01641 unsigned int *col; /* color in buffer */ 01642 int bone_only; 01643 int bone_selected=0; 01644 int totobj= MAXPICKBUF; // XXX solve later 01645 short hits; 01646 01647 if((ob) && (ob->mode & OB_MODE_POSE)) 01648 bone_only= 1; 01649 else 01650 bone_only= 0; 01651 01652 if (extend == 0 && select) { 01653 if (bone_only) { 01654 CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones) { 01655 if ((pchan->bone->flag & BONE_UNSELECTABLE)==0) { 01656 pchan->bone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); 01657 } 01658 } 01659 CTX_DATA_END; 01660 } else { 01661 object_deselect_all_visible(vc->scene, vc->v3d); 01662 } 01663 } 01664 01665 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */ 01666 vbuffer = MEM_mallocN(4 * (totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer"); 01667 hits= view3d_opengl_select(vc, vbuffer, 4*(totobj+MAXPICKBUF), rect); 01668 /* 01669 LOGIC NOTES (theeth): 01670 The buffer and ListBase have the same relative order, which makes the selection 01671 very simple. Loop through both data sets at the same time, if the color 01672 is the same as the object, we have a hit and can move to the next color 01673 and object pair, if not, just move to the next object, 01674 keeping the same color until we have a hit. 01675 01676 The buffer order is defined by OGL standard, hopefully no stupid GFX card 01677 does it incorrectly. 01678 */ 01679 01680 if (hits>0) { /* no need to loop if there's no hit */ 01681 Base *base; 01682 col = vbuffer + 3; 01683 01684 for(base= vc->scene->base.first; base && hits; base= base->next) { 01685 if(BASE_SELECTABLE(vc->v3d, base)) { 01686 while (base->selcol == (*col & 0xFFFF)) { /* we got an object */ 01687 01688 if(*col & 0xFFFF0000) { /* we got a bone */ 01689 bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY)); 01690 if(bone) { 01691 if(select) { 01692 if ((bone->flag & BONE_UNSELECTABLE)==0) { 01693 bone->flag |= BONE_SELECTED; 01694 bone_selected=1; 01695 // XXX select_actionchannel_by_name(base->object->action, bone->name, 1); 01696 } 01697 } 01698 else { 01699 bArmature *arm= base->object->data; 01700 bone->flag &= ~BONE_SELECTED; 01701 // XXX select_actionchannel_by_name(base->object->action, bone->name, 0); 01702 if(arm->act_bone==bone) 01703 arm->act_bone= NULL; 01704 01705 } 01706 } 01707 } 01708 else if(!bone_only) { 01709 if (select) 01710 ED_base_object_select(base, BA_SELECT); 01711 else 01712 ED_base_object_select(base, BA_DESELECT); 01713 } 01714 01715 col+=4; /* next color */ 01716 hits--; 01717 if(hits==0) break; 01718 } 01719 } 01720 01721 if (bone_selected) { 01722 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, base->object); 01723 } 01724 } 01725 01726 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, vc->scene); 01727 01728 } 01729 MEM_freeN(vbuffer); 01730 01731 return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED; 01732 } 01733 01734 static int view3d_borderselect_exec(bContext *C, wmOperator *op) 01735 { 01736 ViewContext vc; 01737 rcti rect; 01738 short extend; 01739 short select; 01740 01741 int ret= OPERATOR_CANCELLED; 01742 01743 view3d_operator_needs_opengl(C); 01744 01745 /* setup view context for argument to callbacks */ 01746 view3d_set_viewcontext(C, &vc); 01747 01748 select= (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT); 01749 rect.xmin= RNA_int_get(op->ptr, "xmin"); 01750 rect.ymin= RNA_int_get(op->ptr, "ymin"); 01751 rect.xmax= RNA_int_get(op->ptr, "xmax"); 01752 rect.ymax= RNA_int_get(op->ptr, "ymax"); 01753 extend = RNA_boolean_get(op->ptr, "extend"); 01754 01755 if(vc.obedit) { 01756 switch(vc.obedit->type) { 01757 case OB_MESH: 01758 vc.em= ((Mesh *)vc.obedit->data)->edit_mesh; 01759 ret= do_mesh_box_select(&vc, &rect, select, extend); 01760 // if (EM_texFaceCheck()) 01761 if(ret & OPERATOR_FINISHED) { 01762 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data); 01763 } 01764 break; 01765 case OB_CURVE: 01766 case OB_SURF: 01767 ret= do_nurbs_box_select(&vc, &rect, select, extend); 01768 break; 01769 case OB_MBALL: 01770 ret= do_meta_box_select(&vc, &rect, select, extend); 01771 break; 01772 case OB_ARMATURE: 01773 ret= do_armature_box_select(&vc, &rect, select, extend); 01774 if(ret & OPERATOR_FINISHED) { 01775 WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, vc.obedit); 01776 } 01777 break; 01778 case OB_LATTICE: 01779 ret= do_lattice_box_select(&vc, &rect, select, extend); 01780 if(ret & OPERATOR_FINISHED) { 01781 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, vc.obedit->data); 01782 } 01783 break; 01784 default: 01785 assert(!"border select on incorrect object type"); 01786 } 01787 } 01788 else { /* no editmode, unified for bones and objects */ 01789 if(vc.obact && vc.obact->mode & OB_MODE_SCULPT) { 01790 /* pass */ 01791 } 01792 else if(vc.obact && paint_facesel_test(vc.obact)) { 01793 ret= do_paintface_box_select(&vc, &rect, select, extend); 01794 } 01795 else if(vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) { 01796 ret= PE_border_select(C, &rect, select, extend); 01797 } 01798 else { /* object mode with none active */ 01799 ret= do_object_pose_box_select(C, &vc, &rect, select, extend); 01800 } 01801 } 01802 01803 return ret; 01804 } 01805 01806 01807 /* *****************Selection Operators******************* */ 01808 01809 /* ****** Border Select ****** */ 01810 void VIEW3D_OT_select_border(wmOperatorType *ot) 01811 { 01812 /* identifiers */ 01813 ot->name= "Border Select"; 01814 ot->description= "Select items using border selection"; 01815 ot->idname= "VIEW3D_OT_select_border"; 01816 01817 /* api callbacks */ 01818 ot->invoke= WM_border_select_invoke; 01819 ot->exec= view3d_borderselect_exec; 01820 ot->modal= WM_border_select_modal; 01821 ot->poll= view3d_selectable_data; 01822 ot->cancel= WM_border_select_cancel; 01823 01824 /* flags */ 01825 ot->flag= OPTYPE_UNDO; 01826 01827 /* rna */ 01828 WM_operator_properties_gesture_border(ot, TRUE); 01829 } 01830 01831 /* ****** Mouse Select ****** */ 01832 01833 01834 static int view3d_select_invoke(bContext *C, wmOperator *op, wmEvent *event) 01835 { 01836 Object *obedit= CTX_data_edit_object(C); 01837 Object *obact= CTX_data_active_object(C); 01838 short extend= RNA_boolean_get(op->ptr, "extend"); 01839 short center= RNA_boolean_get(op->ptr, "center"); 01840 short enumerate= RNA_boolean_get(op->ptr, "enumerate"); 01841 int retval = 0; 01842 01843 view3d_operator_needs_opengl(C); 01844 01845 if(obedit) { 01846 if(obedit->type==OB_MESH) 01847 retval = mouse_mesh(C, event->mval, extend); 01848 else if(obedit->type==OB_ARMATURE) 01849 retval = mouse_armature(C, event->mval, extend); 01850 else if(obedit->type==OB_LATTICE) 01851 retval = mouse_lattice(C, event->mval, extend); 01852 else if(ELEM(obedit->type, OB_CURVE, OB_SURF)) 01853 retval = mouse_nurb(C, event->mval, extend); 01854 else if(obedit->type==OB_MBALL) 01855 retval = mouse_mball(C, event->mval, extend); 01856 01857 } 01858 else if(obact && obact->mode & OB_MODE_SCULPT) 01859 return OPERATOR_CANCELLED; 01860 else if(obact && obact->mode & OB_MODE_PARTICLE_EDIT) 01861 return PE_mouse_particles(C, event->mval, extend); 01862 else if(obact && paint_facesel_test(obact)) 01863 retval = paintface_mouse_select(C, obact, event->mval, extend); 01864 else 01865 retval = mouse_select(C, event->mval, extend, center, enumerate); 01866 01867 /* passthrough allows tweaks 01868 * FINISHED to signal one operator worked 01869 * */ 01870 if (retval) 01871 return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED; 01872 else 01873 return OPERATOR_PASS_THROUGH; /* nothing selected, just passthrough */ 01874 } 01875 01876 void VIEW3D_OT_select(wmOperatorType *ot) 01877 { 01878 /* identifiers */ 01879 ot->name= "Activate/Select"; 01880 ot->description= "Activate/select item(s)"; 01881 ot->idname= "VIEW3D_OT_select"; 01882 01883 /* api callbacks */ 01884 ot->invoke= view3d_select_invoke; 01885 ot->poll= ED_operator_view3d_active; 01886 01887 /* flags */ 01888 ot->flag= OPTYPE_UNDO; 01889 01890 /* properties */ 01891 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first."); 01892 RNA_def_boolean(ot->srna, "center", 0, "Center", "Use the object center when selecting (object mode only)."); 01893 RNA_def_boolean(ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)."); 01894 } 01895 01896 01897 /* -------------------- circle select --------------------------------------------- */ 01898 01899 static void mesh_circle_doSelectVert(void *userData, EditVert *eve, int x, int y, int UNUSED(index)) 01900 { 01901 struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; 01902 int mx = x - data->mval[0], my = y - data->mval[1]; 01903 float r = sqrt(mx*mx + my*my); 01904 01905 if (r<=data->radius) { 01906 eve->f = data->select?(eve->f|1):(eve->f&~1); 01907 } 01908 } 01909 static void mesh_circle_doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int UNUSED(index)) 01910 { 01911 struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; 01912 01913 if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) { 01914 EM_select_edge(eed, data->select); 01915 } 01916 } 01917 static void mesh_circle_doSelectFace(void *userData, EditFace *efa, int x, int y, int UNUSED(index)) 01918 { 01919 struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; 01920 int mx = x - data->mval[0], my = y - data->mval[1]; 01921 float r = sqrt(mx*mx + my*my); 01922 01923 if (r<=data->radius) { 01924 EM_select_face_fgon(data->vc->em, efa, data->select); 01925 } 01926 } 01927 01928 static void mesh_circle_select(ViewContext *vc, int select, const int mval[2], float rad) 01929 { 01930 ToolSettings *ts= vc->scene->toolsettings; 01931 int bbsel; 01932 struct {ViewContext *vc; short select; int mval[2]; float radius; } data; 01933 01934 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f)); 01935 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 01936 01937 vc->em= ((Mesh *)vc->obedit->data)->edit_mesh; 01938 01939 data.vc = vc; 01940 data.select = select; 01941 data.mval[0] = mval[0]; 01942 data.mval[1] = mval[1]; 01943 data.radius = rad; 01944 01945 if(ts->selectmode & SCE_SELECT_VERTEX) { 01946 if(bbsel) { 01947 EM_backbuf_checkAndSelectVerts(vc->em, select==LEFTMOUSE); 01948 } else { 01949 mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, 1); 01950 } 01951 } 01952 01953 if(ts->selectmode & SCE_SELECT_EDGE) { 01954 if (bbsel) { 01955 EM_backbuf_checkAndSelectEdges(vc->em, select==LEFTMOUSE); 01956 } else { 01957 mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, 0); 01958 } 01959 } 01960 01961 if(ts->selectmode & SCE_SELECT_FACE) { 01962 if(bbsel) { 01963 EM_backbuf_checkAndSelectFaces(vc->em, select==LEFTMOUSE); 01964 } else { 01965 mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data); 01966 } 01967 } 01968 01969 EM_free_backbuf(); 01970 EM_selectmode_flush(vc->em); 01971 } 01972 01973 static void paint_facesel_circle_select(ViewContext *vc, int select, const int mval[2], float rad) 01974 { 01975 Object *ob= vc->obact; 01976 Mesh *me = ob?ob->data:NULL; 01977 int bbsel; 01978 01979 if (me) { 01980 em_vertoffs= me->totface+1; /* max index array */ 01981 01982 bbsel= EM_init_backbuf_circle(vc, mval[0], mval[1], (short)(rad+1.0f)); 01983 EM_backbuf_checkAndSelectTFaces(me, select==LEFTMOUSE); 01984 EM_free_backbuf(); 01985 } 01986 } 01987 01988 01989 static void nurbscurve_circle_doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, int x, int y) 01990 { 01991 struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; 01992 int mx = x - data->mval[0], my = y - data->mval[1]; 01993 float r = sqrt(mx*mx + my*my); 01994 Object *obedit= data->vc->obedit; 01995 Curve *cu= (Curve*)obedit->data; 01996 01997 if (r<=data->radius) { 01998 if (bp) { 01999 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT); 02000 02001 if (bp == cu->lastsel && !(bp->f1 & 1)) cu->lastsel = NULL; 02002 } else { 02003 if (cu->drawflag & CU_HIDE_HANDLES) { 02004 /* can only be beztindex==0 here since handles are hidden */ 02005 bezt->f1 = bezt->f2 = bezt->f3 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT); 02006 } else { 02007 if (beztindex==0) { 02008 bezt->f1 = data->select?(bezt->f1|SELECT):(bezt->f1&~SELECT); 02009 } else if (beztindex==1) { 02010 bezt->f2 = data->select?(bezt->f2|SELECT):(bezt->f2&~SELECT); 02011 } else { 02012 bezt->f3 = data->select?(bezt->f3|SELECT):(bezt->f3&~SELECT); 02013 } 02014 } 02015 02016 if (bezt == cu->lastsel && !(bezt->f2 & 1)) cu->lastsel = NULL; 02017 } 02018 } 02019 } 02020 static void nurbscurve_circle_select(ViewContext *vc, int select, const int mval[2], float rad) 02021 { 02022 struct {ViewContext *vc; short select; int mval[2]; float radius; } data; 02023 02024 /* set vc-> edit data */ 02025 02026 data.select = select; 02027 data.mval[0] = mval[0]; 02028 data.mval[1] = mval[1]; 02029 data.radius = rad; 02030 data.vc = vc; 02031 02032 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 02033 nurbs_foreachScreenVert(vc, nurbscurve_circle_doSelect, &data); 02034 } 02035 02036 02037 static void latticecurve_circle_doSelect(void *userData, BPoint *bp, int x, int y) 02038 { 02039 struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; 02040 int mx = x - data->mval[0], my = y - data->mval[1]; 02041 float r = sqrt(mx*mx + my*my); 02042 02043 if (r<=data->radius) { 02044 bp->f1 = data->select?(bp->f1|SELECT):(bp->f1&~SELECT); 02045 } 02046 } 02047 static void lattice_circle_select(ViewContext *vc, int select, const int mval[2], float rad) 02048 { 02049 struct {ViewContext *vc; short select; int mval[2]; float radius; } data; 02050 02051 /* set vc-> edit data */ 02052 02053 data.select = select; 02054 data.mval[0] = mval[0]; 02055 data.mval[1] = mval[1]; 02056 data.radius = rad; 02057 02058 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 02059 lattice_foreachScreenVert(vc, latticecurve_circle_doSelect, &data); 02060 } 02061 02062 02063 // NOTE: pose-bone case is copied from editbone case... 02064 static short pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, int x, int y) 02065 { 02066 struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; 02067 int mx = x - data->mval[0], my = y - data->mval[1]; 02068 float r = sqrt(mx*mx + my*my); 02069 02070 if (r <= data->radius) { 02071 if (data->select) 02072 pchan->bone->flag |= BONE_SELECTED; 02073 else 02074 pchan->bone->flag &= ~BONE_SELECTED; 02075 return 1; 02076 } 02077 return 0; 02078 } 02079 static void pose_circle_select(ViewContext *vc, int select, const int mval[2], float rad) 02080 { 02081 struct {ViewContext *vc; short select; int mval[2]; float radius; } data; 02082 bPose *pose = vc->obact->pose; 02083 bPoseChannel *pchan; 02084 int change= FALSE; 02085 02086 /* set vc->edit data */ 02087 data.select = select; 02088 data.mval[0] = mval[0]; 02089 data.mval[1] = mval[1]; 02090 data.radius = rad; 02091 02092 ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); /* for foreach's screen/vert projection */ 02093 02094 /* check each PoseChannel... */ 02095 // TODO: could be optimised at some point 02096 for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { 02097 short sco1[2], sco2[2], didpoint=0; 02098 float vec[3]; 02099 02100 /* project head location to screenspace */ 02101 mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_head); 02102 project_short(vc->ar, vec, sco1); 02103 02104 /* project tail location to screenspace */ 02105 mul_v3_m4v3(vec, vc->obact->obmat, pchan->pose_tail); 02106 project_short(vc->ar, vec, sco2); 02107 02108 /* check if the head and/or tail is in the circle 02109 * - the call to check also does the selection already 02110 */ 02111 if (pchan_circle_doSelectJoint(&data, pchan, sco1[0], sco1[1])) 02112 didpoint= 1; 02113 if (pchan_circle_doSelectJoint(&data, pchan, sco2[0], sco2[1])) 02114 didpoint= 1; 02115 02116 change |= didpoint; 02117 } 02118 02119 if (change) { 02120 WM_main_add_notifier(NC_OBJECT|ND_BONE_SELECT, vc->obact); 02121 } 02122 } 02123 02124 static short armature_circle_doSelectJoint(void *userData, EditBone *ebone, int x, int y, short head) 02125 { 02126 struct {ViewContext *vc; short select; int mval[2]; float radius; } *data = userData; 02127 int mx = x - data->mval[0], my = y - data->mval[1]; 02128 float r = sqrt(mx*mx + my*my); 02129 02130 if (r <= data->radius) { 02131 if (head) { 02132 if (data->select) 02133 ebone->flag |= BONE_ROOTSEL; 02134 else 02135 ebone->flag &= ~BONE_ROOTSEL; 02136 } 02137 else { 02138 if (data->select) 02139 ebone->flag |= BONE_TIPSEL; 02140 else 02141 ebone->flag &= ~BONE_TIPSEL; 02142 } 02143 return 1; 02144 } 02145 return 0; 02146 } 02147 static void armature_circle_select(ViewContext *vc, int select, const int mval[2], float rad) 02148 { 02149 struct {ViewContext *vc; short select, mval[2]; float radius; } data; 02150 bArmature *arm= vc->obedit->data; 02151 EditBone *ebone; 02152 int change= FALSE; 02153 02154 /* set vc->edit data */ 02155 data.select = select; 02156 data.mval[0] = mval[0]; 02157 data.mval[1] = mval[1]; 02158 data.radius = rad; 02159 02160 ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 02161 02162 /* check each EditBone... */ 02163 // TODO: could be optimised at some point 02164 for (ebone= arm->edbo->first; ebone; ebone=ebone->next) { 02165 short sco1[2], sco2[2], didpoint=0; 02166 float vec[3]; 02167 02168 /* project head location to screenspace */ 02169 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->head); 02170 project_short(vc->ar, vec, sco1); 02171 02172 /* project tail location to screenspace */ 02173 mul_v3_m4v3(vec, vc->obedit->obmat, ebone->tail); 02174 project_short(vc->ar, vec, sco2); 02175 02176 /* check if the head and/or tail is in the circle 02177 * - the call to check also does the selection already 02178 */ 02179 if (armature_circle_doSelectJoint(&data, ebone, sco1[0], sco1[1], 1)) 02180 didpoint= 1; 02181 if (armature_circle_doSelectJoint(&data, ebone, sco2[0], sco2[1], 0)) 02182 didpoint= 1; 02183 02184 /* only if the endpoints didn't get selected, deal with the middle of the bone too */ 02185 // XXX should we just do this always? 02186 if ( (didpoint==0) && edge_inside_circle(mval[0], mval[1], rad, sco1[0], sco1[1], sco2[0], sco2[1]) ) { 02187 if (select) 02188 ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED; 02189 else 02190 ebone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL); 02191 change= TRUE; 02192 } 02193 02194 change |= didpoint; 02195 } 02196 02197 if(change) { 02198 ED_armature_sync_selection(arm->edbo); 02199 ED_armature_validate_active(arm); 02200 WM_main_add_notifier(NC_OBJECT|ND_BONE_SELECT, vc->obedit); 02201 } 02202 } 02203 02206 static void obedit_circle_select(ViewContext *vc, short select, const int mval[2], float rad) 02207 { 02208 switch(vc->obedit->type) { 02209 case OB_MESH: 02210 mesh_circle_select(vc, select, mval, rad); 02211 break; 02212 case OB_CURVE: 02213 case OB_SURF: 02214 nurbscurve_circle_select(vc, select, mval, rad); 02215 break; 02216 case OB_LATTICE: 02217 lattice_circle_select(vc, select, mval, rad); 02218 break; 02219 case OB_ARMATURE: 02220 armature_circle_select(vc, select, mval, rad); 02221 break; 02222 default: 02223 return; 02224 } 02225 } 02226 02227 /* not a real operator, only for circle test */ 02228 static int view3d_circle_select_exec(bContext *C, wmOperator *op) 02229 { 02230 ScrArea *sa= CTX_wm_area(C); 02231 ARegion *ar= CTX_wm_region(C); 02232 Scene *scene= CTX_data_scene(C); 02233 Object *obact= CTX_data_active_object(C); 02234 View3D *v3d= sa->spacedata.first; 02235 int x= RNA_int_get(op->ptr, "x"); 02236 int y= RNA_int_get(op->ptr, "y"); 02237 int radius= RNA_int_get(op->ptr, "radius"); 02238 int gesture_mode= RNA_int_get(op->ptr, "gesture_mode"); 02239 int select; 02240 02241 select= (gesture_mode==GESTURE_MODAL_SELECT); 02242 02243 if( CTX_data_edit_object(C) || paint_facesel_test(obact) || 02244 (obact && (obact->mode & (OB_MODE_PARTICLE_EDIT|OB_MODE_POSE))) ) 02245 { 02246 ViewContext vc; 02247 int mval[2]; 02248 02249 view3d_operator_needs_opengl(C); 02250 02251 view3d_set_viewcontext(C, &vc); 02252 mval[0]= x; 02253 mval[1]= y; 02254 02255 if(CTX_data_edit_object(C)) { 02256 obedit_circle_select(&vc, select, mval, (float)radius); 02257 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data); 02258 } 02259 else if(paint_facesel_test(obact)) { 02260 paint_facesel_circle_select(&vc, select, mval, (float)radius); 02261 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obact->data); 02262 } 02263 else if(obact->mode & OB_MODE_POSE) 02264 pose_circle_select(&vc, select, mval, (float)radius); 02265 else 02266 return PE_circle_select(C, select, mval, (float)radius); 02267 } 02268 else if(obact && obact->mode & OB_MODE_SCULPT) { 02269 return OPERATOR_CANCELLED; 02270 } 02271 else { 02272 Base *base; 02273 select= select?BA_SELECT:BA_DESELECT; 02274 for(base= FIRSTBASE; base; base= base->next) { 02275 if(BASE_SELECTABLE(v3d, base)) { 02276 project_short(ar, base->object->obmat[3], &base->sx); 02277 if(base->sx!=IS_CLIPPED) { 02278 int dx= base->sx-x; 02279 int dy= base->sy-y; 02280 if( dx*dx + dy*dy < radius*radius) 02281 ED_base_object_select(base, select); 02282 } 02283 } 02284 } 02285 02286 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, CTX_data_scene(C)); 02287 } 02288 02289 return OPERATOR_FINISHED; 02290 } 02291 02292 void VIEW3D_OT_select_circle(wmOperatorType *ot) 02293 { 02294 ot->name= "Circle Select"; 02295 ot->description= "Select items using circle selection"; 02296 ot->idname= "VIEW3D_OT_select_circle"; 02297 02298 ot->invoke= WM_gesture_circle_invoke; 02299 ot->modal= WM_gesture_circle_modal; 02300 ot->exec= view3d_circle_select_exec; 02301 ot->poll= view3d_selectable_data; 02302 ot->cancel= WM_gesture_circle_cancel; 02303 02304 /* flags */ 02305 ot->flag= OPTYPE_UNDO; 02306 02307 RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX); 02308 RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); 02309 RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX); 02310 RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX); 02311 }