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