/** * $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. * * Trackball math (in calctrackballvec()) Copyright (C) Silicon Graphics, Inc. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include #include #ifdef HAVE_CONFIG_H #include #endif #ifdef WIN32 #include #include "BLI_winstuff.h" #else #include #endif #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_arithb.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 "DNA_camera_types.h" #include "DNA_lamp_types.h" #include "DNA_userdef_types.h" #include "BKE_utildefines.h" #include "BKE_object.h" #include "BKE_global.h" #include "BKE_main.h" #include "BIF_gl.h" #include "BIF_space.h" #include "BIF_mywindow.h" #include "BIF_screen.h" #include "BIF_toolbox.h" #include "BSE_view.h" #include "BSE_edit.h" /* For countall */ #include "BSE_drawview.h" /* For inner_play_anim_loop */ #include "BDR_drawobject.h" /* For draw_object */ #include "mydevice.h" #include "blendef.h" /* Modules used */ #include "render.h" /* R. stuff for ogl view render */ #define TRACKBALLSIZE (1.1) #define BL_NEAR_CLIP 0.001 void persp_general(int a) { /* for all window types, not 3D */ if(a== 0) { glPushMatrix(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); myortho2(-0.375, ((float)(curarea->winx))-0.375, -0.375, ((float)(curarea->winy))-0.375); glLoadIdentity(); } else if(a== 1) { glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } } void persp(int a) { /* only 3D windows */ if(curarea->spacetype!=SPACE_VIEW3D) persp_general(a); else if(a == PERSP_STORE) { // only store glMatrixMode(GL_PROJECTION); mygetmatrix(G.vd->winmat1); glMatrixMode(GL_MODELVIEW); mygetmatrix(G.vd->viewmat1); } else if(a== PERSP_WIN) { // only set myortho2(-0.375, (float)(curarea->winx)-0.375, -0.375, (float)(curarea->winy)-0.375); glLoadIdentity(); } else if(a== PERSP_VIEW) { glMatrixMode(GL_PROJECTION); myloadmatrix(G.vd->winmat1); // put back Mat4CpyMat4(curarea->winmat, G.vd->winmat1); // to be sure? glMatrixMode(GL_MODELVIEW); myloadmatrix(G.vd->viewmat); // put back } } float zfac=1.0; void initgrabz(float x, float y, float z) { if(G.vd==0) return; zfac= G.vd->persmat[0][3]*x+ G.vd->persmat[1][3]*y+ G.vd->persmat[2][3]*z+ G.vd->persmat[3][3]; } void window_to_3d(float *vec, short mx, short my) { /* always call initzgrab */ float dx, dy; float fmx, fmy, winx, winy; /* stupid! */ winx= curarea->winx; winy= curarea->winy; fmx= mx; fmy= my; dx= (2.0*fmx)/winx; dx*= zfac; dy= (2.0*fmy)/winy; dy*= zfac; vec[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy); vec[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy); vec[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy); } void project_short(float *vec, short *adr) /* clips */ { float fx, fy, vec4[4]; adr[0]= 3200; VECCOPY(vec4, vec); vec4[3]= 1.0; Mat4MulVec4fl(G.vd->persmat, vec4); if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */ fx= (curarea->winx/2)+(curarea->winx/2)*vec4[0]/vec4[3]; if( fx>0 && fxwinx) { fy= (curarea->winy/2)+(curarea->winy/2)*vec4[1]/vec4[3]; if(fy>0.0 && fy< (float)curarea->winy) { adr[0]= floor(fx); adr[1]= floor(fy); } } } } void project_short_noclip(float *vec, short *adr) { float fx, fy, vec4[4]; adr[0]= 3200; VECCOPY(vec4, vec); vec4[3]= 1.0; Mat4MulVec4fl(G.vd->persmat, vec4); if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */ fx= (curarea->winx/2)+(curarea->winx/2)*vec4[0]/vec4[3]; if( fx>-32700 && fx<32700) { fy= (curarea->winy/2)+(curarea->winy/2)*vec4[1]/vec4[3]; if(fy>-32700.0 && fy<32700.0) { adr[0]= floor(fx); adr[1]= floor(fy); } } } } void project_float(float *vec, float *adr) { float vec4[4]; adr[0]= 3200.0; VECCOPY(vec4, vec); vec4[3]= 1.0; Mat4MulVec4fl(G.vd->persmat, vec4); if( vec4[3]>BL_NEAR_CLIP ) { adr[0]= (curarea->winx/2.0)+(curarea->winx/2.0)*vec4[0]/vec4[3]; adr[1]= (curarea->winy/2.0)+(curarea->winy/2.0)*vec4[1]/vec4[3]; } } int boundbox_clip(float obmat[][4], BoundBox *bb) { /* return 1: draw */ float mat[4][4]; float vec[4], min, max; int a, flag= -1, fl; if(bb==0) return 1; Mat4MulMat4(mat, obmat, G.vd->persmat); for(a=0; a<8; a++) { VECCOPY(vec, bb->vec[a]); vec[3]= 1.0; Mat4MulVec4fl(mat, vec); max= vec[3]; min= -vec[3]; fl= 0; if(vec[0] < min) fl+= 1; if(vec[0] > max) fl+= 2; if(vec[1] < min) fl+= 4; if(vec[1] > max) fl+= 8; if(vec[2] < min) fl+= 16; if(vec[2] > max) fl+= 32; flag &= fl; if(flag==0) return 1; } return 0; } void fdrawline(float x1, float y1, float x2, float y2) { float v[2]; glBegin(GL_LINE_STRIP); v[0] = x1; v[1] = y1; glVertex2fv(v); v[0] = x2; v[1] = y2; glVertex2fv(v); glEnd(); } void fdrawbox(float x1, float y1, float x2, float y2) { float v[2]; glBegin(GL_LINE_STRIP); v[0] = x1; v[1] = y1; glVertex2fv(v); v[0] = x1; v[1] = y2; glVertex2fv(v); v[0] = x2; v[1] = y2; glVertex2fv(v); v[0] = x2; v[1] = y1; glVertex2fv(v); v[0] = x1; v[1] = y1; glVertex2fv(v); glEnd(); } void sdrawline(short x1, short y1, short x2, short y2) { short v[2]; glBegin(GL_LINE_STRIP); v[0] = x1; v[1] = y1; glVertex2sv(v); v[0] = x2; v[1] = y2; glVertex2sv(v); glEnd(); } void sdrawbox(short x1, short y1, short x2, short y2) { short v[2]; glBegin(GL_LINE_STRIP); v[0] = x1; v[1] = y1; glVertex2sv(v); v[0] = x1; v[1] = y2; glVertex2sv(v); v[0] = x2; v[1] = y2; glVertex2sv(v); v[0] = x2; v[1] = y1; glVertex2sv(v); v[0] = x1; v[1] = y1; glVertex2sv(v); glEnd(); } /* the central math in this function was copied from trackball.cpp, sample code from the Developers Toolbox series by SGI. */ /* trackball: better one than a full spherical solution */ void calctrackballvecfirst(rcti *area, short *mval, float *vec) { float x, y, radius, d, z, t; radius= TRACKBALLSIZE; /* normalise x and y */ x= (area->xmax + area->xmin)/2 -mval[0]; x/= (float)((area->xmax - area->xmin)/2); y= (area->ymax + area->ymin)/2 -mval[1]; y/= (float)((area->ymax - area->ymin)/2); d = sqrt(x*x + y*y); if (d < radius*M_SQRT1_2) /* Inside sphere */ z = sqrt(radius*radius - d*d); else { /* On hyperbola */ t = radius / M_SQRT2; z = t*t / d; } vec[0]= x; vec[1]= y; vec[2]= -z; /* yah yah! */ if( fabs(vec[2])>fabs(vec[1]) && fabs(vec[2])>fabs(vec[0]) ) { vec[0]= 0.0; vec[1]= 0.0; if(vec[2]>0.0) vec[2]= 1.0; else vec[2]= -1.0; } else if( fabs(vec[1])>fabs(vec[0]) && fabs(vec[1])>fabs(vec[2]) ) { vec[0]= 0.0; vec[2]= 0.0; if(vec[1]>0.0) vec[1]= 1.0; else vec[1]= -1.0; } else { vec[1]= 0.0; vec[2]= 0.0; if(vec[0]>0.0) vec[0]= 1.0; else vec[0]= -1.0; } } void calctrackballvec(rcti *area, short *mval, float *vec) { float x, y, radius, d, z, t; radius= TRACKBALLSIZE; /* x en y normaliseren */ x= (area->xmax + area->xmin)/2 -mval[0]; x/= (float)((area->xmax - area->xmin)/4); y= (area->ymax + area->ymin)/2 -mval[1]; y/= (float)((area->ymax - area->ymin)/2); d = sqrt(x*x + y*y); if (d < radius*M_SQRT1_2) /* Inside sphere */ z = sqrt(radius*radius - d*d); else { /* On hyperbola */ t = radius / M_SQRT2; z = t*t / d; } vec[0]= x; vec[1]= y; vec[2]= -z; /* yah yah! */ } void viewmove(int mode) { float firstvec[3], newvec[3], dvec[3]; float oldquat[4], q1[4], si, phi, dist0; int firsttime=1; short mvalball[2], mval[2], mvalo[2]; /* sometimes this routine is called from headerbuttons */ areawinset(curarea->win); initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]); QUATCOPY(oldquat, G.vd->viewquat); getmouseco_sc(mvalo); /* work with screen coordinates because of trackball function */ mvalball[0]= mvalo[0]; /* needed for turntable to work */ mvalball[1]= mvalo[1]; dist0= G.vd->dist; calctrackballvec(&curarea->winrct, mvalo, firstvec); /* cumultime(0); */ while(TRUE) { getmouseco_sc(mval); if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || (G.f & G_PLAYANIM)) { if(firsttime) { firsttime= 0; /* are we translating, rotating or zooming? */ if(mode==0) { if(G.vd->view!=0) scrarea_queue_headredraw(curarea); /*for button */ G.vd->view= 0; } if(G.vd->persp==2 || (G.vd->persp==3 && mode!=1)) { G.vd->persp= 1; scrarea_do_windraw(curarea); scrarea_queue_headredraw(curarea); } } if(mode==0) { /* view rotate */ if (U.uiflag & USER_AUTOPERSP) G.vd->persp= 1; if (U.flag & USER_TRACKBALL) mvalball[0]= mval[0]; mvalball[1]= mval[1]; calctrackballvec(&curarea->winrct, mvalball, newvec); VecSubf(dvec, newvec, firstvec); si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]); si/= (2.0*TRACKBALLSIZE); if (U.flag & USER_TRACKBALL) { Crossf(q1+1, firstvec, newvec); Normalise(q1+1); /* Allow for rotation beyond the interval * [-pi, pi] */ while (si > 1.0) si -= 2.0; /* This relation is used instead of * phi = asin(si) so that the angle * of rotation is linearly proportional * to the distance that the mouse is * dragged. */ phi = si * M_PI / 2.0; si= sin(phi); q1[0]= cos(phi); q1[1]*= si; q1[2]*= si; q1[3]*= si; QuatMul(G.vd->viewquat, q1, oldquat); } else { /* is there an acceptable solution? (180 degrees limitor) */ if(si<1.0) { Crossf(q1+1, firstvec, newvec); Normalise(q1+1); phi= asin(si); si= sin(phi); q1[0]= cos(phi); q1[1]*= si; q1[2]*= si; q1[3]*= si; QuatMul(G.vd->viewquat, q1, oldquat); /* rotate around z-axis (mouse x moves) */ phi= 2*(mval[0]-mvalball[0]); phi/= (float)curarea->winx; si= sin(phi); q1[0]= cos(phi); q1[1]= q1[2]= 0.0; q1[3]= si; QuatMul(G.vd->viewquat, G.vd->viewquat, q1); } } } else if(mode==1) { /* translate */ if(G.vd->persp==3) { /* zoom= 0.5+0.5*(float)(2<rt1); */ /* dx-= (mval[0]-mvalo[0])/zoom; */ /* dy-= (mval[1]-mvalo[1])/zoom; */ /* G.vd->rt2= dx; */ /* G.vd->rt3= dy; */ /* if(G.vd->rt2<-320) G.vd->rt2= -320; */ /* if(G.vd->rt2> 320) G.vd->rt2= 320; */ /* if(G.vd->rt3<-250) G.vd->rt3= -250; */ /* if(G.vd->rt3> 250) G.vd->rt3= 250; */ } else { window_to_3d(dvec, mval[0]-mvalo[0], mval[1]-mvalo[1]); VecAddf(G.vd->ofs, G.vd->ofs, dvec); } } else if(mode==2) { if(U.viewzoom==USER_ZOOM_CONT) { // oldstyle zoom G.vd->dist*= 1.0+(float)(mvalo[0]-mval[0]+mvalo[1]-mval[1])/1000.0; } else if(U.viewzoom==USER_ZOOM_SCALE) { int ctr[2], len1, len2; // method which zooms based on how far you move the mouse ctr[0] = (curarea->winrct.xmax + curarea->winrct.xmin)/2; ctr[1] = (curarea->winrct.ymax + curarea->winrct.ymin)/2; len1 = (int)sqrt((ctr[0] - mval[0])*(ctr[0] - mval[0]) + (ctr[1] - mval[1])*(ctr[1] - mval[1])) + 5; len2 = (int)sqrt((ctr[0] - mvalo[0])*(ctr[0] - mvalo[0]) + (ctr[1] - mvalo[1])*(ctr[1] - mvalo[1])) + 5; G.vd->dist= dist0 * ((float)len2/len1); } else { /* USER_ZOOM_DOLLY */ float len1 = (curarea->winrct.ymax - mval[1]) + 5; float len2 = (curarea->winrct.ymax - mvalo[1]) + 5; G.vd->dist= dist0 * (2.0*((len2/len1)-1.0) + 1.0); } /* these limits are in toets.c too */ if(G.vd->dist<0.001*G.vd->grid) G.vd->dist= 0.001*G.vd->grid; if(G.vd->dist>10.0*G.vd->far) G.vd->dist=10.0*G.vd->far; mval[1]= mvalo[1]; /* preserve first value */ mval[0]= mvalo[0]; } mvalo[0]= mval[0]; mvalo[1]= mval[1]; if(G.f & G_PLAYANIM) inner_play_anim_loop(0, 0); if(G.f & G_SIMULATION) break; scrarea_do_windraw(curarea); screen_swapbuffers(); } else { BIF_wait_for_statechange(); } /* this in the end, otherwise get_mbut does not work on a PC... */ if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break; } } short v3d_windowmode=0; /* important to not set windows active in here, can be renderwin for example */ void setwinmatrixview3d(rctf *rect) /* rect: for picking */ { Camera *cam=0; float d, near, far, winx = 0.0, winy = 0.0; float lens, dfac, fac, x1, y1, x2, y2; short orth; lens= G.vd->lens; near= G.vd->near; far= G.vd->far; if(G.vd->persp==2) { near= G.vd->near; far= G.vd->far; if(G.vd->camera) { if(G.vd->camera->type==OB_LAMP ) { Lamp *la; la= G.vd->camera->data; fac= cos( M_PI*la->spotsize/360.0); x1= saacos(fac); lens= 16.0*fac/sin(x1); near= la->clipsta; far= la->clipend; } else if(G.vd->camera->type==OB_CAMERA) { cam= G.vd->camera->data; lens= cam->lens; near= cam->clipsta; far= cam->clipend; if(cam->type==CAM_ORTHO) { lens*= 100.0; near= (near+1.0)*100.0; /* otherwise zbuffer troubles. a Patch! */ far*= 100.0; } } } } if(v3d_windowmode) { // hackish winx= R.rectx; winy= R.recty; } else { winx= curarea->winx; winy= curarea->winy; } if(winx>winy) d= 0.015625*winx*lens; else d= 0.015625*winy*lens; dfac= near/d; if(G.vd->persp==0) { if(winx>winy) x1= -G.vd->dist; else x1= -winx*G.vd->dist/winy; x2= -x1; if(winx>winy) y1= -winy*G.vd->dist/winx; else y1= -G.vd->dist; y2= -y1; orth= 1; } else { if(G.vd->persp==2) { fac= (1.41421+( (float)G.vd->camzoom )/50.0); fac*= fac; } else fac= 2.0; x1= -dfac*(winx/fac); x2= -x1; y1= -dfac*(winy/fac); y2= -y1; orth= 0; } if(rect) { /* picking */ rect->xmin/= winx; rect->xmin= x1+rect->xmin*(x2-x1); rect->ymin/= winy; rect->ymin= y1+rect->ymin*(y2-y1); rect->xmax/= winx; rect->xmax= x1+rect->xmax*(x2-x1); rect->ymax/= winy; rect->ymax= y1+rect->ymax*(y2-y1); if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -far, far); else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, near, far); } else { if(v3d_windowmode) { if(orth) i_ortho(x1, x2, y1, y2, -far, far, R.winmat); else { if(cam && cam->type==CAM_ORTHO) i_window(x1, x2, y1, y2, near, far, R.winmat); else i_window(x1, x2, y1, y2, near, far, R.winmat); } } else { if(orth) myortho(x1, x2, y1, y2, -far, far); else { if(cam && cam->type==CAM_ORTHO) mywindow(x1, x2, y1, y2, near, far); else mywindow(x1, x2, y1, y2, near, far); } } } if(v3d_windowmode==0) { glMatrixMode(GL_PROJECTION); mygetmatrix(curarea->winmat); glMatrixMode(GL_MODELVIEW); } } void obmat_to_viewmat(Object *ob) { float bmat[4][4]; float tmat[3][3]; Mat4CpyMat4(bmat, ob->obmat); Mat4Ortho(bmat); Mat4Invert(G.vd->viewmat, bmat); /* view quat calculation, needed for add object */ Mat3CpyMat4(tmat, G.vd->viewmat); Mat3ToQuat(tmat, G.vd->viewquat); } /* dont set windows active in in here, is used by renderwin too */ void setviewmatrixview3d() { Camera *cam; if(G.vd->persp>=2) { /* obs/camera */ if(G.vd->camera) { where_is_object(G.vd->camera); obmat_to_viewmat(G.vd->camera); if(G.vd->camera->type==OB_CAMERA) { cam= G.vd->camera->data; if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0; } } else { QuatToMat4(G.vd->viewquat, G.vd->viewmat); G.vd->viewmat[3][2]-= G.vd->dist; } } else { QuatToMat4(G.vd->viewquat, G.vd->viewmat); if(G.vd->persp==1) G.vd->viewmat[3][2]-= G.vd->dist; i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat); } } void setcameratoview3d() { Object *ob; float dvec[3]; ob= G.vd->camera; dvec[0]= G.vd->dist*G.vd->viewinv[2][0]; dvec[1]= G.vd->dist*G.vd->viewinv[2][1]; dvec[2]= G.vd->dist*G.vd->viewinv[2][2]; VECCOPY(ob->loc, dvec); VecSubf(ob->loc, ob->loc, G.vd->ofs); G.vd->viewquat[0]= -G.vd->viewquat[0]; if (ob->transflag & OB_QUAT) { QUATCOPY(ob->quat, G.vd->viewquat); } else { QuatToEul(G.vd->viewquat, ob->rot); } G.vd->viewquat[0]= -G.vd->viewquat[0]; } /* IGLuint-> GLuint*/ short selectprojektie(unsigned int *buffer, short x1, short y1, short x2, short y2) { rctf rect; Base *base; short mval[2], code, hits; G.f |= G_PICKSEL; if(x1==0 && x2==0 && y1==0 && y2==0) { getmouseco_areawin(mval); rect.xmin= mval[0]-12; // seems to be default value for bones only now rect.xmax= mval[0]+12; rect.ymin= mval[1]-12; rect.ymax= mval[1]+12; } else { rect.xmin= x1; rect.xmax= x2; rect.ymin= y1; rect.ymax= y2; } /* get rid of overlay button matrix */ persp(PERSP_VIEW); setwinmatrixview3d(&rect); Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat); if(G.vd->drawtype > OB_WIRE) { G.zbuf= TRUE; glEnable(GL_DEPTH_TEST); } glSelectBuffer( MAXPICKBUF, (GLuint *)buffer); glRenderMode(GL_SELECT); glInitNames(); /* these two calls whatfor? It doesnt work otherwise */ glPushName(-1); code= 1; if(G.obedit && G.obedit->type==OB_MBALL) { draw_object(BASACT); } else if ((G.obedit && G.obedit->type==OB_ARMATURE)||(G.obpose && G.obpose->type==OB_ARMATURE)) { draw_object(BASACT); } else { base= G.scene->base.first; while(base) { if(base->lay & G.vd->lay) { base->selcol= code; glLoadName(code); draw_object(base); code++; } base= base->next; } } glPopName(); /* see above (pushname) */ hits= glRenderMode(GL_RENDER); if(hits<0) error("Too many objects in select buffer"); G.f &= ~G_PICKSEL; setwinmatrixview3d(0); Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat); if(G.vd->drawtype > OB_WIRE) { G.zbuf= 0; glDisable(GL_DEPTH_TEST); } persp(PERSP_WIN); return hits; } float *give_cursor() { if(G.vd && G.vd->localview) return G.vd->cursor; else return G.scene->cursor; } unsigned int free_localbit() { unsigned int lay; ScrArea *sa; bScreen *sc; lay= 0; /* sometimes we loose a localview: when an area is closed */ /* check all areas: which localviews are in use? */ sc= G.main->screen.first; while(sc) { sa= sc->areabase.first; while(sa) { SpaceLink *sl= sa->spacedata.first; while(sl) { if(sl->spacetype==SPACE_VIEW3D) { View3D *v3d= (View3D*) sl; lay |= v3d->lay; } sl= sl->next; } sa= sa->next; } sc= sc->id.next; } if( (lay & 0x01000000)==0) return 0x01000000; if( (lay & 0x02000000)==0) return 0x02000000; if( (lay & 0x04000000)==0) return 0x04000000; if( (lay & 0x08000000)==0) return 0x08000000; if( (lay & 0x10000000)==0) return 0x10000000; if( (lay & 0x20000000)==0) return 0x20000000; if( (lay & 0x40000000)==0) return 0x40000000; if( (lay & 0x80000000)==0) return 0x80000000; return 0; } void initlocalview() { Base *base; float size = 0.0, min[3], max[3], afm[3]; unsigned int locallay; int ok=0; if(G.vd->localvd) return; min[0]= min[1]= min[2]= 1.0e10; max[0]= max[1]= max[2]= -1.0e10; locallay= free_localbit(); if(locallay==0) { error("Sorry, no more than 8 localviews"); ok= 0; } else { if(G.obedit) { minmax_object(G.obedit, min, max); ok= 1; BASACT->lay |= locallay; G.obedit->lay= BASACT->lay; } else { base= FIRSTBASE; while(base) { if TESTBASE(base) { minmax_object(base->object, min, max); base->lay |= locallay; base->object->lay= base->lay; ok= 1; } base= base->next; } } afm[0]= (max[0]-min[0]); afm[1]= (max[1]-min[1]); afm[2]= (max[2]-min[2]); size= 0.7*MAX3(afm[0], afm[1], afm[2]); if(size<=0.01) size= 0.01; } if(ok) { G.vd->localvd= MEM_mallocN(sizeof(View3D), "localview"); memcpy(G.vd->localvd, G.vd, sizeof(View3D)); G.vd->ofs[0]= -(min[0]+max[0])/2.0; G.vd->ofs[1]= -(min[1]+max[1])/2.0; G.vd->ofs[2]= -(min[2]+max[2])/2.0; G.vd->dist= size; // correction for window aspect ratio if(curarea->winy>2 && curarea->winx>2) { size= (float)curarea->winx/(float)curarea->winy; if(size<1.0) size= 1.0/size; G.vd->dist*= size; } if(G.vd->persp>1) { G.vd->persp= 1; } G.vd->near= 0.1; G.vd->cursor[0]= -G.vd->ofs[0]; G.vd->cursor[1]= -G.vd->ofs[1]; G.vd->cursor[2]= -G.vd->ofs[2]; G.vd->lay= locallay; countall(); scrarea_queue_winredraw(curarea); } else { /* clear flags */ base= FIRSTBASE; while(base) { if( base->lay & locallay ) { base->lay-= locallay; if(base->lay==0) base->lay= G.vd->layact; if(base->object != G.obedit) base->flag |= SELECT; base->object->lay= base->lay; } base= base->next; } scrarea_queue_headredraw(curarea); G.vd->localview= 0; } } void centreview() /* like a localview without local! */ { Base *base; float size, min[3], max[3], afm[3]; int ok=0; min[0]= min[1]= min[2]= 1.0e10; max[0]= max[1]= max[2]= -1.0e10; if(G.obedit) { minmax_verts(min, max); //minmax_object(G.obedit, min, max); ok= 1; } else { base= FIRSTBASE; while(base) { if TESTBASE(base) { minmax_object(base->object, min, max); ok= 1; } base= base->next; } } if(ok==0) return; afm[0]= (max[0]-min[0]); afm[1]= (max[1]-min[1]); afm[2]= (max[2]-min[2]); size= 0.7*MAX3(afm[0], afm[1], afm[2]); if(size<=0.01) size= 0.01; G.vd->ofs[0]= -(min[0]+max[0])/2.0; G.vd->ofs[1]= -(min[1]+max[1])/2.0; G.vd->ofs[2]= -(min[2]+max[2])/2.0; G.vd->dist= size; // correction for window aspect ratio if(curarea->winy>2 && curarea->winx>2) { size= (float)curarea->winx/(float)curarea->winy; if(size<1.0) size= 1.0/size; G.vd->dist*= size; } if(G.vd->persp>1) { G.vd->persp= 1; } G.vd->cursor[0]= -G.vd->ofs[0]; G.vd->cursor[1]= -G.vd->ofs[1]; G.vd->cursor[2]= -G.vd->ofs[2]; scrarea_queue_winredraw(curarea); } void restore_localviewdata(View3D *vd) { if(vd->localvd==0) return; VECCOPY(vd->ofs, vd->localvd->ofs); vd->dist= vd->localvd->dist; vd->persp= vd->localvd->persp; vd->view= vd->localvd->view; vd->near= vd->localvd->near; vd->far= vd->localvd->far; vd->lay= vd->localvd->lay; vd->layact= vd->localvd->layact; vd->drawtype= vd->localvd->drawtype; vd->camera= vd->localvd->camera; QUATCOPY(vd->viewquat, vd->localvd->viewquat); } void endlocalview(ScrArea *sa) { View3D *v3d; struct Base *base; unsigned int locallay; if(sa->spacetype!=SPACE_VIEW3D) return; v3d= sa->spacedata.first; if(v3d->localvd) { locallay= v3d->lay & 0xFF000000; restore_localviewdata(v3d); MEM_freeN(v3d->localvd); v3d->localvd= 0; v3d->localview= 0; /* for when in other window the layers have changed */ if(v3d->scenelock) v3d->lay= G.scene->lay; base= FIRSTBASE; while(base) { if( base->lay & locallay ) { base->lay-= locallay; if(base->lay==0) base->lay= v3d->layact; if(base->object != G.obedit) base->flag |= SELECT; base->object->lay= base->lay; } base= base->next; } countall(); allqueue(REDRAWVIEW3D, 0); /* because of select */ } } void view3d_home(int centre) { Base *base; float size, min[3], max[3], afm[3]; int ok= 1, onedone=0; if(centre) { min[0]= min[1]= min[2]= 0.0; max[0]= max[1]= max[2]= 0.0; } else { min[0]= min[1]= min[2]= 1.0e10; max[0]= max[1]= max[2]= -1.0e10; } base= FIRSTBASE; if(base==0) return; while(base) { if(base->lay & G.vd->lay) { onedone= 1; minmax_object(base->object, min, max); } base= base->next; } if(!onedone) return; afm[0]= (max[0]-min[0]); afm[1]= (max[1]-min[1]); afm[2]= (max[2]-min[2]); size= 0.7*MAX3(afm[0], afm[1], afm[2]); if(size==0.0) ok= 0; if(ok) { G.vd->ofs[0]= -(min[0]+max[0])/2.0; G.vd->ofs[1]= -(min[1]+max[1])/2.0; G.vd->ofs[2]= -(min[2]+max[2])/2.0; G.vd->dist= size; // correction for window aspect ratio if(curarea->winy>2 && curarea->winx>2) { size= (float)curarea->winx/(float)curarea->winy; if(size<1.0) size= 1.0/size; G.vd->dist*= size; } if(G.vd->persp==2) G.vd->persp= 1; scrarea_queue_winredraw(curarea); } } void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3]) { float alignaxis[3]; float norm[3], axis[3], angle; alignaxis[0]= alignaxis[1]= alignaxis[2]= 0.0; alignaxis[axisidx]= 1.0; norm[0]= vec[0], norm[1]= vec[1], norm[2]= vec[2]; Normalise(norm); angle= acos(Inpf(alignaxis, norm)); Crossf(axis, alignaxis, norm); VecRotToQuat(axis, -angle, v3d->viewquat); v3d->view= 0; if (v3d->persp>=2) v3d->persp= 0; /* switch out of camera mode */ }