/** * $Id$ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include #ifndef WIN32 #include #else #include #include "BLI_winstuff.h" #endif #include "MEM_guardedalloc.h" #include "BMF_Api.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "BLI_editVert.h" #include "DNA_armature_types.h" #include "DNA_curve_types.h" #include "DNA_lattice_types.h" #include "DNA_meta_types.h" #include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "BKE_utildefines.h" #include "BKE_anim.h" #include "BKE_object.h" #include "BKE_displist.h" #include "BKE_global.h" #include "BKE_lattice.h" #include "BKE_mesh.h" #include "BIF_gl.h" #include "BIF_mywindow.h" #include "BIF_screen.h" #include "BIF_interface.h" #include "BIF_space.h" #include "BIF_editview.h" #include "BIF_glutil.h" #include "BSE_view.h" #include "BSE_edit.h" #include "BSE_trans_types.h" #include "BSE_drawipo.h" #include "BDR_editobject.h" /* old stuff */ #include "blendertimer.h" #include "blendef.h" #include "interface.h" #include "mydevice.h" /*#include "armature.h"*/ /* #include "edit.h" */ #include "nla.h" #ifdef __NLA #include "BIF_editarmature.h" #endif /* editmball.c */ extern ListBase editelems; /* go away ! */ /* from editobject */ extern void make_trans_verts(float *min, float *max, int mode); /* circle selection callback */ typedef void (*select_CBfunc)(short selecting, Object *editobj, short *mval, float rad); extern void obedit_selectionCB(short selecting, Object *editobj, short *mval, float rad); extern void uvedit_selectionCB(short selecting, Object *editobj, short *mval, float rad); void circle_selectCB(select_CBfunc func); int get_border(rcti *rect, short col) { float dvec[4], fac1, fac2; int retval=1; unsigned short event; short mval[2], mvalo[4], val, x1, y1; char str[64]; mywinset(G.curscreen->mainwin); /* pietsje groter, 1 pixel aan de rand */ glReadBuffer(GL_FRONT); glDrawBuffer(GL_FRONT); /* removed my_get_frontbuffer, this crashes when it gets a part outside the screen */ /* solved it with just a redraw! */ mywinset(curarea->win); glDrawBuffer(GL_FRONT); persp(0); initgrabz(0.0, 0.0, 0.0); getmouseco_areawin(mvalo); /* draws the selection initial cross */ sdrawXORline4(0, 0, mvalo[1], curarea->winx, mvalo[1]); sdrawXORline4(1, mvalo[0], 0, mvalo[0], curarea->winy); while(TRUE) { /* als een renderwindow open is en de muis gaat erin */ persp(1); mywinset(curarea->win); persp(0); /* selection loop while mouse pressed */ getmouseco_areawin(mval); if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) { /* aiming cross */ sdrawXORline4(0, 0, mval[1], curarea->winx, mval[1]); sdrawXORline4(1, mval[0], 0, mval[0], curarea->winy); glFlush(); mvalo[0]= mval[0]; mvalo[1]= mval[1]; } event= extern_qread(&val); if(event && val) { if(event==ESCKEY) { retval= 0; break; } else if(event==BKEY) { /* b has been pressed twice: proceed with circle select */ retval= 0; break; } else if(event==LEFTMOUSE) break; else if(event==MIDDLEMOUSE) break; else if(event==RIGHTMOUSE) break; } } /* end while (TRUE) */ /* erase XORed lines */ sdrawXORline4(-1, 0, 0, 0, 0); if(retval) { /* box select */ x1= mval[0]; y1= mval[1]; getmouseco_areawin(mvalo); sdrawXORline4(0, x1, y1, x1, mvalo[1]); sdrawXORline4(1, x1, mvalo[1], mvalo[0], mvalo[1]); sdrawXORline4(2, mvalo[0], mvalo[1], mvalo[0], y1); sdrawXORline4(3, mvalo[0], y1, x1, y1); glFlush(); while(TRUE) { getmouseco_areawin(mval); if(mvalo[0]!=mval[0] || mvalo[1]!=mval[1]) { sdrawXORline4(0, x1, y1, x1, mval[1]); sdrawXORline4(1, x1, mval[1], mval[0], mval[1]); sdrawXORline4(2, mval[0], mval[1], mval[0], y1); sdrawXORline4(3, mval[0], y1, x1, y1); glFlush(); mvalo[0]= mval[0]; mvalo[1]= mval[1]; } event= extern_qread(&val); /* still because of the renderwindow... */ persp(1); mywinset(curarea->win); persp(0); if(val==0) { if(event==ESCKEY) { retval= 0; break; } else if(event==LEFTMOUSE) break; else if(event==MIDDLEMOUSE) break; else if(event==RIGHTMOUSE) break; } if(curarea->spacetype==SPACE_VIEW3D) { glColor3f(0.4375, 0.4375, 0.4375); glRecti(0, 10, 250, 20); glColor3f(0.0, 0.0, 0.0); if(G.vd->persp==0) { window_to_3d(dvec, mvalo[0]-x1, mvalo[1]-y1); glRasterPos2i(10, 10); sprintf(str, "X %.4f Y %.4f Z %.4f Dia %.4f", dvec[0], dvec[1], dvec[2], sqrt(dvec[0]*dvec[0]+dvec[1]*dvec[1]+dvec[2]*dvec[2])); BMF_DrawString(G.fonts, str); } else if(G.vd->persp==2) { rcti vb; calc_viewborder(G.vd, &vb); fac1= (mvalo[0]-x1)/( (float) (vb.xmax-vb.xmin) ); fac1*= 0.01*G.scene->r.size*G.scene->r.xsch; fac2= (mvalo[1]-y1)/( (float) (vb.ymax-vb.ymin) ); fac2*= 0.01*G.scene->r.size*G.scene->r.ysch; glRasterPos2i(10, 10); sprintf(str, "X %.1f Y %.1f Dia %.1f", fabs(fac1), fabs(fac2), sqrt(fac1*fac1 + fac2*fac2) ); BMF_DrawString(G.fonts, str); } } else if(curarea->spacetype==SPACE_IPO) { SpaceIpo *sipo= curarea->spacedata.first; glColor3f(.40625, .40625, .40625); glRecti(20, 30, 170, 40); glColor3f(0.0, 0.0, 0.0); mvalo[2]= x1; mvalo[3]= y1; areamouseco_to_ipoco(&sipo->v2d, mval, dvec, dvec+1); areamouseco_to_ipoco(&sipo->v2d, mvalo+2, dvec+2, dvec+3); glRasterPos2i(30, 30); sprintf(str, "Time: %.4f Y %.4f", dvec[0]-dvec[2], dvec[1]-dvec[3]); BMF_DrawString(G.fonts, str); } } /* end while (TRUE) */ sdrawXORline4(-1, 0, 0, 0, 0); if(retval) { rect->xmin= x1; rect->ymin= y1; rect->xmax= mval[0]; rect->ymax= mval[1]; retval= event; /* normaliseren */ if(rect->xmin>rect->xmax) SWAP(int, rect->xmin, rect->xmax); if(rect->ymin>rect->ymax) SWAP(int, rect->ymin, rect->ymax); if(rect->xmin==rect->xmax) retval= 0; if(rect->ymin==rect->ymax) retval= 0; } } /* wissen */ if(event!=BKEY) { if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_IPO) { scrarea_queue_winredraw(curarea); } } glFlush(); glReadBuffer(GL_BACK); glDrawBuffer(GL_BACK); persp(1); /* pressed B again ? -> brush select */ if(event==BKEY) { switch (curarea->spacetype) { case SPACE_VIEW3D: if (G.obedit) circle_selectCB(&obedit_selectionCB); return 0; case SPACE_IMAGE: // brush select in UV editor circle_selectCB(&uvedit_selectionCB); // this is a hack; we return 0 that the caller from get_border // doesn't execute the selection code for border select.. return 0; } } return retval; } void draw_sel_circle(short *mval, short *mvalo, float rad, float rado, int selecting) { static short no_mvalo=0; if(mval==0 && mvalo==0) { /* signal */ no_mvalo= 1; return; } persp(0); glDrawBuffer(GL_FRONT); /* cirkel tekenen */ if(mvalo && no_mvalo==0) { sdrawXORcirc(mvalo[0], mvalo[1], rado); } if(mval) { sdrawXORcirc(mval[0], mval[1], rad); } glFlush(); persp(1); glDrawBuffer(GL_BACK); no_mvalo= 0; } /** This function does the same as editview.c:circle_select(), * but the selection actions are defined by a callback, making * it (hopefully) reusable for other windows than the 3D view. */ void circle_selectCB(select_CBfunc callback) { static float rad= 40.0; float rado; int firsttime=1; unsigned short event; short mvalo[2], mval[2], val; short selecting=0; Object *obj; if(G.obedit) obj = G.obedit; else obj = OBACT; getmouseco_areawin(mvalo); draw_sel_circle(mvalo, 0, rad, 0.0, selecting); rado= rad; while(TRUE) { /* als een renderwindow open is en de muis gaat erin */ mywinset(curarea->win); getmouseco_areawin(mval); if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || rado!=rad || firsttime) { firsttime= 0; draw_sel_circle(mval, mvalo, rad, rado, selecting); mvalo[0]= mval[0]; mvalo[1]= mval[1]; rado= rad; if(selecting) { callback(selecting, obj, mval, rad); } } event= extern_qread(&val); if (event) { int afbreek= 0; switch(event) { case LEFTMOUSE: case MIDDLEMOUSE: if(val) selecting= event; else selecting= 0; firsttime= 1; break; case PADPLUSKEY: if(val) if(rad<200.0) rad*= 1.2; break; case PADMINUS: if(val) if(rad>5.0) rad/= 1.2; break; case ESCKEY: case SPACEKEY: case RIGHTMOUSE: case GKEY: case SKEY: case RKEY: case XKEY: case EKEY: case TABKEY: afbreek= 1; break; } if(afbreek) break; } } /* cirkel wissen */ draw_sel_circle(0, mvalo, 0, rad, 1); countall(); allqueue(REDRAWINFO, 0); } void count_object(Object *ob, int sel) { Mesh *me; Curve *cu; int tot=0, totf=0; switch(ob->type) { case OB_MESH: G.totmesh++; me= get_mesh(ob); if(me) { G.totvert+= me->totvert; G.totface+= me->totface; if(sel) { G.totvertsel+= me->totvert; G.totfacesel+= me->totface; } } break; case OB_LAMP: G.totlamp++; break; case OB_SURF: case OB_CURVE: case OB_FONT: G.totcurve++; tot=totf= 0; cu= ob->data; if(cu->disp.first==0) makeDispList(ob); count_displist( &cu->disp, &tot, &totf); G.totvert+= tot; G.totface+= totf; if(sel) { G.totvertsel+= tot; G.totfacesel+= totf; } break; case OB_MBALL: count_displist( &ob->disp, &tot, &totf); G.totvert+= tot; G.totface+= totf; if(sel) { G.totvertsel+= tot; G.totfacesel+= totf; } break; } } void countall() { /* extern Lattice *editLatt; in BKE_lattice.h*/ extern ListBase editNurb; /* extern ListBase bpbase; */ Base *base; Object *ob; Mesh *me; Nurb *nu; BezTriple *bezt; BPoint *bp; MetaElem *ml; /* struct BodyPoint *bop; */ struct EditVert *eve; struct EditVlak *evl; #ifdef __NLA struct EditBone *ebo; #endif int a; G.totvert= G.totvertsel= G.totfacesel= G.totface= G.totobj= G.totmesh= G.totlamp= G.totcurve= G.totobjsel= 0; if(G.obedit) { if(G.obedit->type==OB_MESH) { eve= G.edve.first; while(eve) { G.totvert++; if(eve->f & 1) G.totvertsel++; eve= eve->next; } evl= G.edvl.first; while(evl) { G.totface++; if(evl->v1->f & 1) { if(evl->v2->f & 1) { if(evl->v3->f & 1) { if(evl->v4) { if(evl->v4->f & 1) G.totfacesel++; } else { G.totfacesel++; } } } } evl= evl->next; } } #ifdef __NLA else if (G.obedit->type==OB_ARMATURE){ for (ebo=G.edbo.first;ebo;ebo=ebo->next){ /* Synch selection to parent for ik children */ if ((ebo->flag & BONE_IK_TOPARENT) && ebo->parent){ G.totvert--; if (ebo->parent->flag & BONE_TIPSEL) ebo->flag |= BONE_ROOTSEL; else ebo->flag &= ~BONE_ROOTSEL; } if (ebo->flag & BONE_TIPSEL) G.totvertsel++; if (ebo->flag & BONE_ROOTSEL) G.totvertsel++; if ((ebo->flag & BONE_TIPSEL) && (ebo->flag & BONE_ROOTSEL)) ebo->flag |= BONE_SELECTED; else ebo->flag &= ~BONE_SELECTED; // If this is an IK child and it's parent is being moved, remove our root if ((ebo->flag & BONE_IK_TOPARENT)&& (ebo->flag & BONE_ROOTSEL) && ebo->parent && (ebo->parent->flag & BONE_TIPSEL)){ G.totvertsel--; } G.totvert+=2; G.totface++; } } #endif else if ELEM3(G.obedit->type, OB_CURVE, OB_SURF, OB_FONT) { nu= editNurb.first; while(nu) { if((nu->type & 7)==CU_BEZIER) { bezt= nu->bezt; a= nu->pntsu; while(a--) { G.totvert+=3; if(bezt->f1) G.totvertsel++; if(bezt->f2) G.totvertsel++; if(bezt->f3) G.totvertsel++; bezt++; } } else { bp= nu->bp; a= nu->pntsu*nu->pntsv; while(a--) { G.totvert++; if(bp->f1 & 1) G.totvertsel++; bp++; } } nu= nu->next; } } else if(G.obedit->type==OB_MBALL) { ml= editelems.first; while(ml) { G.totvert++; if(ml->flag & SELECT) G.totvertsel++; ml= ml->next; } } else if(G.obedit->type==OB_LATTICE) { bp= editLatt->def; a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw; while(a--) { G.totvert++; if(bp->f1 & 1) G.totvertsel++; bp++; } } allqueue(REDRAWINFO, 1); /* 1, want header->win==0! */ return; } else if(G.f & (G_FACESELECT + G_VERTEXPAINT + G_TEXTUREPAINT +G_WEIGHTPAINT)) { me= get_mesh((G.scene->basact) ? (G.scene->basact->object) : 0); if(me) { G.totface= me->totface; G.totvert= me->totvert; } allqueue(REDRAWINFO, 1); /* 1, want header->win==0! */ return; } if(G.vd==0) return; if(G.scene==0) return; base= (G.scene->base.first); while(base) { if(G.vd->lay & base->lay) { G.totobj++; if(base->flag & SELECT) G.totobjsel++; count_object(base->object, base->flag & SELECT); if(base->object->transflag & OB_DUPLI) { extern ListBase duplilist; make_duplilist(G.scene, base->object); ob= duplilist.first; while(ob) { G.totobj++; count_object(ob, base->flag & SELECT); ob= ob->id.next; } free_duplilist(); } } base= base->next; } allqueue(REDRAWINFO, 1); /* 1, want header->win==0! */ } void snapmenu() { extern TransVert *transvmain; extern int tottrans; extern float originmat[3][3]; /* object.c */ TransVert *tv; Base *base; Object *ob; float gridf, *curs, imat[3][3], bmat[3][3], vec[3], min[3], max[3], centroid[3]; int count, a; short event; event= pupmenu("SNAP %t|Sel -> Grid%x1|Sel -> Curs%x2|Curs-> Grid%x3|Curs-> Sel%x4"); gridf= G.vd->grid; curs= give_cursor(); if(event== 1 || event==2) { /* sel->grid sel->curs */ if(G.obedit) { #ifdef __NLA if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0); #else if ELEM4(G.obedit->type, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0); #endif if(tottrans==0) return; Mat3CpyMat4(bmat, G.obedit->obmat); Mat3Inv(imat, bmat); tv= transvmain; for(a=0; aobmat[3][0]; vec[1]= curs[1]-G.obedit->obmat[3][1]; vec[2]= curs[2]-G.obedit->obmat[3][2]; } else { VECCOPY(vec, tv->loc); Mat3MulVecfl(bmat, vec); VecAddf(vec, vec, G.obedit->obmat[3]); vec[0]= G.vd->grid*floor(.5+ vec[0]/gridf); vec[1]= G.vd->grid*floor(.5+ vec[1]/gridf); vec[2]= G.vd->grid*floor(.5+ vec[2]/gridf); VecSubf(vec, vec, G.obedit->obmat[3]); } Mat3MulVecfl(imat, vec); VECCOPY(tv->loc, vec); } MEM_freeN(transvmain); transvmain= 0; if ELEM(G.obedit->type, OB_SURF, OB_CURVE) makeDispList(G.obedit); if (G.obedit->type == OB_ARMATURE) special_trans_update(0); allqueue(REDRAWVIEW3D, 0); return; } #ifdef __NLA if (G.obpose){ allqueue(REDRAWVIEW3D, 0); return; } #endif base= (G.scene->base.first); while(base) { if( ( ((base)->flag & SELECT) && ((base)->lay & G.vd->lay) && ((base)->object->id.lib==0))) { ob= base->object; if(event==2) { vec[0]= -ob->obmat[3][0] + curs[0]; vec[1]= -ob->obmat[3][1] + curs[1]; vec[2]= -ob->obmat[3][2] + curs[2]; } else { vec[0]= -ob->obmat[3][0]+G.vd->grid*floor(.5+ ob->obmat[3][0]/gridf); vec[1]= -ob->obmat[3][1]+G.vd->grid*floor(.5+ ob->obmat[3][1]/gridf); vec[2]= -ob->obmat[3][2]+G.vd->grid*floor(.5+ ob->obmat[3][2]/gridf); } if(ob->parent) { where_is_object(ob); Mat3Inv(imat, originmat); Mat3MulVecfl(imat, vec); ob->loc[0]+= vec[0]; ob->loc[1]+= vec[1]; ob->loc[2]+= vec[2]; } else { ob->loc[0]+= vec[0]; ob->loc[1]+= vec[1]; ob->loc[2]+= vec[2]; } } base= base->next; } allqueue(REDRAWVIEW3D, 0); } else if(event==3) { /* curs to grid */ curs[0]= G.vd->grid*floor(.5+curs[0]/gridf); curs[1]= G.vd->grid*floor(.5+curs[1]/gridf); curs[2]= G.vd->grid*floor(.5+curs[2]/gridf); allqueue(REDRAWVIEW3D, 0); } else if(event==4) { /* curs to sel */ count= 0; INIT_MINMAX(min, max); centroid[0]= centroid[1]= centroid[2]= 0.0; if(G.obedit) { tottrans=0; #ifdef __NLA if ELEM5(G.obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0); #else if ELEM4(G.obedit->type, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) make_trans_verts(bmat[0], bmat[1], 0); #endif if(tottrans==0) return; Mat3CpyMat4(bmat, G.obedit->obmat); tv= transvmain; for(a=0; aloc); Mat3MulVecfl(bmat, vec); VecAddf(vec, vec, G.obedit->obmat[3]); VecAddf(centroid, centroid, vec); DO_MINMAX(vec, min, max); } if(G.vd->around==V3D_CENTROID) { VecMulf(centroid, 1.0/(float)tottrans); VECCOPY(curs, centroid); } else { curs[0]= (min[0]+max[0])/2; curs[1]= (min[1]+max[1])/2; curs[2]= (min[2]+max[2])/2; } MEM_freeN(transvmain); transvmain= 0; } else { base= (G.scene->base.first); while(base) { if(((base)->flag & SELECT) && ((base)->lay & G.vd->lay) ) { VECCOPY(vec, base->object->obmat[3]); VecAddf(centroid, centroid, vec); DO_MINMAX(vec, min, max); count++; } base= base->next; } if(count) { if(G.vd->around==V3D_CENTROID) { VecMulf(centroid, 1.0/(float)count); VECCOPY(curs, centroid); } else { curs[0]= (min[0]+max[0])/2; curs[1]= (min[1]+max[1])/2; curs[2]= (min[2]+max[2])/2; } } } allqueue(REDRAWVIEW3D, 0); } }