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