Blender V2.61 - r43446

view3d_select.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 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 = &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 }