1861 lines
43 KiB
C
1861 lines
43 KiB
C
/**
|
|
* $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 <math.h>
|
|
#include <string.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include <io.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_arithb.h"
|
|
|
|
#include "DNA_action_types.h"
|
|
#include "DNA_armature_types.h"
|
|
#include "DNA_camera_types.h"
|
|
#include "DNA_lamp_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_space_types.h"
|
|
#include "DNA_userdef_types.h"
|
|
#include "DNA_view3d_types.h"
|
|
|
|
#include "BKE_action.h"
|
|
#include "BKE_anim.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_object.h"
|
|
#include "BKE_sculpt.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BIF_editparticle.h"
|
|
#include "BIF_gl.h"
|
|
#include "BIF_previewrender.h"
|
|
#include "BIF_mywindow.h"
|
|
#include "BIF_retopo.h"
|
|
#include "BIF_space.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 "BDR_editface.h" /* For minmax_tface */
|
|
#include "BDR_sculptmode.h"
|
|
|
|
#include "mydevice.h"
|
|
#include "blendef.h"
|
|
|
|
#include "PIL_time.h" /* smoothview */
|
|
|
|
#define TRACKBALLSIZE (1.1)
|
|
#define BL_NEAR_CLIP 0.001
|
|
|
|
|
|
/* local prototypes ----------*/
|
|
void setcameratoview3d(void); /* windows.c & toets.c */
|
|
|
|
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
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void initgrabz(float x, float y, float z)
|
|
{
|
|
if(G.vd==NULL) return;
|
|
G.vd->zfac= G.vd->persmat[0][3]*x+ G.vd->persmat[1][3]*y+ G.vd->persmat[2][3]*z+ G.vd->persmat[3][3];
|
|
|
|
/* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that
|
|
* (accounting for near zero values)
|
|
* */
|
|
if (G.vd->zfac < 1.e-6f && G.vd->zfac > -1.e-6f) G.vd->zfac = 1.0f;
|
|
|
|
/* Negative zfac means x, y, z was behind the camera (in perspective).
|
|
* This gives flipped directions, so revert back to ok default case.
|
|
*/
|
|
if (G.vd->zfac < 0.0f) G.vd->zfac = 1.0f;
|
|
}
|
|
|
|
void window_to_3d(float *vec, short mx, short my)
|
|
{
|
|
/* always call initgrabz */
|
|
float dx, dy;
|
|
|
|
dx= 2.0f*mx*G.vd->zfac/curarea->winx;
|
|
dy= 2.0f*my*G.vd->zfac/curarea->winy;
|
|
|
|
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]= IS_CLIPPED;
|
|
|
|
if(G.vd->flag & V3D_CLIPPING) {
|
|
if(view3d_test_clipping(G.vd, vec))
|
|
return;
|
|
}
|
|
|
|
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)*(1 + vec4[0]/vec4[3]);
|
|
|
|
if( fx>0 && fx<curarea->winx) {
|
|
|
|
fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
|
|
|
|
if(fy>0.0 && fy< (float)curarea->winy) {
|
|
adr[0]= floor(fx);
|
|
adr[1]= floor(fy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void project_int(float *vec, int *adr)
|
|
{
|
|
float fx, fy, vec4[4];
|
|
|
|
adr[0]= 2140000000.0f;
|
|
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)*(1 + vec4[0]/vec4[3]);
|
|
|
|
if( fx>-2140000000.0f && fx<2140000000.0f) {
|
|
fy= (curarea->winy/2)*(1 + vec4[1]/vec4[3]);
|
|
|
|
if(fy>-2140000000.0f && fy<2140000000.0f) {
|
|
adr[0]= floor(fx);
|
|
adr[1]= floor(fy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void project_short_noclip(float *vec, short *adr)
|
|
{
|
|
float fx, fy, vec4[4];
|
|
|
|
adr[0]= IS_CLIPPED;
|
|
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)*(1 + vec4[0]/vec4[3]);
|
|
|
|
if( fx>-32700 && fx<32700) {
|
|
|
|
fy= (curarea->winy/2)*(1 + 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]= IS_CLIPPED;
|
|
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];
|
|
}
|
|
}
|
|
|
|
void view3d_get_object_project_mat(ScrArea *area, Object *ob, float pmat[4][4], float vmat[4][4])
|
|
{
|
|
if (area->spacetype!=SPACE_VIEW3D || !area->spacedata.first) {
|
|
Mat4One(pmat);
|
|
Mat4One(vmat);
|
|
} else {
|
|
View3D *vd = area->spacedata.first;
|
|
|
|
Mat4MulMat4(vmat, ob->obmat, vd->viewmat);
|
|
Mat4MulMat4(pmat, vmat, vd->winmat1);
|
|
Mat4CpyMat4(vmat, ob->obmat);
|
|
}
|
|
}
|
|
|
|
/* projectmat brings it to window coords, wmat to rotated world space */
|
|
void view3d_project_short_clip(ScrArea *area, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
|
|
{
|
|
View3D *v3d= area->spacedata.first;
|
|
float fx, fy, vec4[4];
|
|
|
|
adr[0]= IS_CLIPPED;
|
|
|
|
/* clipplanes in eye space */
|
|
if(v3d->flag & V3D_CLIPPING) {
|
|
VECCOPY(vec4, vec);
|
|
Mat4MulVecfl(wmat, vec4);
|
|
if(view3d_test_clipping(v3d, vec4))
|
|
return;
|
|
}
|
|
|
|
VECCOPY(vec4, vec);
|
|
vec4[3]= 1.0;
|
|
|
|
Mat4MulVec4fl(projmat, vec4);
|
|
|
|
/* clipplanes in window space */
|
|
if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
|
|
fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
|
|
|
|
if( fx>0 && fx<area->winx) {
|
|
|
|
fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
|
|
|
|
if(fy>0.0 && fy< (float)area->winy) {
|
|
adr[0]= floor(fx);
|
|
adr[1]= floor(fy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void view3d_project_short_noclip(ScrArea *area, float *vec, short *adr, float mat[4][4])
|
|
{
|
|
float fx, fy, vec4[4];
|
|
|
|
adr[0]= IS_CLIPPED;
|
|
|
|
VECCOPY(vec4, vec);
|
|
vec4[3]= 1.0;
|
|
|
|
Mat4MulVec4fl(mat, vec4);
|
|
|
|
if( vec4[3]>BL_NEAR_CLIP ) { /* 0.001 is the NEAR clipping cutoff for picking */
|
|
fx= (area->winx/2)*(1 + vec4[0]/vec4[3]);
|
|
|
|
if( fx>-32700 && fx<32700) {
|
|
|
|
fy= (area->winy/2)*(1 + vec4[1]/vec4[3]);
|
|
|
|
if(fy>-32700.0 && fy<32700.0) {
|
|
adr[0]= floor(fx);
|
|
adr[1]= floor(fy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void view3d_project_float(ScrArea *area, float *vec, float *adr, float mat[4][4])
|
|
{
|
|
float vec4[4];
|
|
|
|
adr[0]= IS_CLIPPED;
|
|
VECCOPY(vec4, vec);
|
|
vec4[3]= 1.0;
|
|
|
|
Mat4MulVec4fl(mat, vec4);
|
|
|
|
if( vec4[3]>FLT_EPSILON ) {
|
|
adr[0] = (area->winx/2.0)+(area->winx/2.0)*vec4[0]/vec4[3];
|
|
adr[1] = (area->winy/2.0)+(area->winy/2.0)*vec4[1]/vec4[3];
|
|
} else {
|
|
adr[0] = adr[1] = 0.0;
|
|
}
|
|
}
|
|
|
|
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==NULL) return 1;
|
|
if(bb->flag & OB_BB_DISABLED) 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;
|
|
|
|
/* normalize 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 normalizeren */
|
|
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)
|
|
{
|
|
Object *ob = OBACT;
|
|
float firstvec[3], newvec[3], dvec[3];
|
|
float reverse, oldquat[4], q1[4], si, phi, dist0;
|
|
float ofs[3], obofs[3]= {0.0f, 0.0f, 0.0f};
|
|
int firsttime=1;
|
|
short mvalball[2], mval[2], mvalo[2], mval_area[2];
|
|
short use_sel = 0;
|
|
short preview3d_event= 1;
|
|
|
|
/* 3D window may not be defined */
|
|
if( !G.vd ) {
|
|
fprintf( stderr, "G.vd == NULL in viewmove()\n" );
|
|
return;
|
|
}
|
|
|
|
/* 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_areawin(mval_area); /* for zoom to mouse loc */
|
|
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); */
|
|
|
|
if(!G.obedit && (G.f & G_SCULPTMODE) && ob && G.vd->pivot_last) {
|
|
use_sel= 1;
|
|
VecCopyf(ofs, G.vd->ofs);
|
|
|
|
VecCopyf(obofs,&sculpt_session()->pivot.x);
|
|
Mat4MulVecfl(ob->obmat, obofs);
|
|
obofs[0]= -obofs[0];
|
|
obofs[1]= -obofs[1];
|
|
obofs[2]= -obofs[2];
|
|
}
|
|
else if (ob && (U.uiflag & USER_ORBIT_SELECTION)) {
|
|
use_sel = 1;
|
|
|
|
VECCOPY(ofs, G.vd->ofs);
|
|
|
|
/* If there's no selection, obofs is unmodified, so <0,0,0> */
|
|
calculateTransformCenter(V3D_CENTROID, obofs);
|
|
VecMulf(obofs, -1.0f);
|
|
}
|
|
else
|
|
ofs[0] = ofs[1] = ofs[2] = 0.0f;
|
|
|
|
reverse= 1.0f;
|
|
if (G.vd->persmat[2][1] < 0.0f)
|
|
reverse= -1.0f;
|
|
|
|
while(TRUE) {
|
|
getmouseco_sc(mval);
|
|
|
|
// if playanim = alt+A, screenhandlers are for animated UI, python, etc
|
|
if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || (G.f & G_PLAYANIM) || do_screenhandlers(G.curscreen)) {
|
|
|
|
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 && mode!=1 && G.vd->camera) {
|
|
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);
|
|
|
|
Normalize(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);
|
|
|
|
if (use_sel) {
|
|
/* compute the post multiplication quat, to rotate the offset correctly */
|
|
QUATCOPY(q1, oldquat);
|
|
QuatConj(q1);
|
|
QuatMul(q1, q1, G.vd->viewquat);
|
|
|
|
QuatConj(q1); /* conj == inv for unit quat */
|
|
VECCOPY(G.vd->ofs, ofs);
|
|
VecSubf(G.vd->ofs, G.vd->ofs, obofs);
|
|
QuatMulVecf(q1, G.vd->ofs);
|
|
VecAddf(G.vd->ofs, G.vd->ofs, obofs);
|
|
}
|
|
} else {
|
|
/* New turntable view code by John Aughey */
|
|
|
|
float m[3][3];
|
|
float m_inv[3][3];
|
|
float xvec[3] = {1,0,0};
|
|
/* Sensitivity will control how fast the viewport rotates. 0.0035 was
|
|
obtained experimentally by looking at viewport rotation sensitivities
|
|
on other modeling programs. */
|
|
/* Perhaps this should be a configurable user parameter. */
|
|
const float sensitivity = 0.0035;
|
|
|
|
/* Get the 3x3 matrix and its inverse from the quaternion */
|
|
QuatToMat3(G.vd->viewquat, m);
|
|
Mat3Inv(m_inv,m);
|
|
|
|
/* Determine the direction of the x vector (for rotating up and down) */
|
|
/* This can likely be compuated directly from the quaternion. */
|
|
Mat3MulVecfl(m_inv,xvec);
|
|
|
|
/* Perform the up/down rotation */
|
|
phi = sensitivity * -(mval[1] - mvalo[1]);
|
|
si = sin(phi);
|
|
q1[0] = cos(phi);
|
|
q1[1] = si * xvec[0];
|
|
q1[2] = si * xvec[1];
|
|
q1[3] = si * xvec[2];
|
|
QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
|
|
|
|
if (use_sel) {
|
|
QuatConj(q1); /* conj == inv for unit quat */
|
|
VecSubf(G.vd->ofs, G.vd->ofs, obofs);
|
|
QuatMulVecf(q1, G.vd->ofs);
|
|
VecAddf(G.vd->ofs, G.vd->ofs, obofs);
|
|
}
|
|
|
|
/* Perform the orbital rotation */
|
|
phi = sensitivity * reverse * (mval[0] - mvalo[0]);
|
|
q1[0] = cos(phi);
|
|
q1[1] = q1[2] = 0.0;
|
|
q1[3] = sin(phi);
|
|
QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
|
|
|
|
if (use_sel) {
|
|
QuatConj(q1);
|
|
VecSubf(G.vd->ofs, G.vd->ofs, obofs);
|
|
QuatMulVecf(q1, G.vd->ofs);
|
|
VecAddf(G.vd->ofs, G.vd->ofs, obofs);
|
|
}
|
|
}
|
|
}
|
|
else if(mode==1) { /* translate */
|
|
if(G.vd->persp==2) {
|
|
float max= (float)MAX2(curarea->winx, curarea->winy);
|
|
|
|
G.vd->camdx += (mvalo[0]-mval[0])/(max);
|
|
G.vd->camdy += (mvalo[1]-mval[1])/(max);
|
|
CLAMP(G.vd->camdx, -1.0f, 1.0f);
|
|
CLAMP(G.vd->camdy, -1.0f, 1.0f);
|
|
preview3d_event= 0;
|
|
}
|
|
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) {
|
|
float zfac=1.0;
|
|
if(U.viewzoom==USER_ZOOM_CONT) {
|
|
// oldstyle zoom
|
|
zfac = 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;
|
|
|
|
zfac = dist0 * ((float)len2/len1) / G.vd->dist;
|
|
}
|
|
else { /* USER_ZOOM_DOLLY */
|
|
float len1 = (curarea->winrct.ymax - mval[1]) + 5;
|
|
float len2 = (curarea->winrct.ymax - mvalo[1]) + 5;
|
|
zfac = dist0 * (2.0*((len2/len1)-1.0) + 1.0) / G.vd->dist;
|
|
}
|
|
|
|
if(zfac != 1.0 && zfac*G.vd->dist > 0.001*G.vd->grid &&
|
|
zfac*G.vd->dist < 10.0*G.vd->far)
|
|
view_zoom_mouseloc(zfac, mval_area);
|
|
|
|
/* 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];
|
|
|
|
if(G.vd->persp==0 || G.vd->persp==2) preview3d_event= 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;
|
|
|
|
/* If in retopo paint mode, update lines */
|
|
if(retopo_mesh_paint_check() && G.vd->retopo_view_data) {
|
|
G.vd->retopo_view_data->queue_matrix_update= 1;
|
|
retopo_paint_view_update(G.vd);
|
|
}
|
|
|
|
scrarea_do_windraw(curarea);
|
|
screen_swapbuffers();
|
|
}
|
|
else {
|
|
short val;
|
|
unsigned short event;
|
|
/* we need to empty the queue... when you do this very long it overflows */
|
|
while(qtest()) event= extern_qread(&val);
|
|
|
|
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;
|
|
}
|
|
|
|
if(G.vd->depths) G.vd->depths->damaged= 1;
|
|
retopo_queue_updates(G.vd);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
|
|
if(preview3d_event)
|
|
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
|
|
else
|
|
BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
|
|
|
|
}
|
|
|
|
void view_zoom_mouseloc(float dfac, short *mouseloc)
|
|
{
|
|
if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
|
|
short vb[2];
|
|
float dvec[3];
|
|
float tvec[3];
|
|
float tpos[3];
|
|
float new_dist;
|
|
|
|
/* find the current window width and height */
|
|
vb[0] = G.vd->area->winx;
|
|
vb[1] = G.vd->area->winy;
|
|
|
|
tpos[0] = -G.vd->ofs[0];
|
|
tpos[1] = -G.vd->ofs[1];
|
|
tpos[2] = -G.vd->ofs[2];
|
|
|
|
/* Project cursor position into 3D space */
|
|
initgrabz(tpos[0], tpos[1], tpos[2]);
|
|
window_to_3d(dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
|
|
|
|
/* Calculate view target position for dolly */
|
|
tvec[0] = -(tpos[0] + dvec[0]);
|
|
tvec[1] = -(tpos[1] + dvec[1]);
|
|
tvec[2] = -(tpos[2] + dvec[2]);
|
|
|
|
/* Offset to target position and dolly */
|
|
new_dist = G.vd->dist * dfac;
|
|
|
|
VECCOPY(G.vd->ofs, tvec);
|
|
G.vd->dist = new_dist;
|
|
|
|
/* Calculate final offset */
|
|
dvec[0] = tvec[0] + dvec[0] * dfac;
|
|
dvec[1] = tvec[1] + dvec[1] * dfac;
|
|
dvec[2] = tvec[2] + dvec[2] * dfac;
|
|
|
|
VECCOPY(G.vd->ofs, dvec);
|
|
} else {
|
|
G.vd->dist *= dfac;
|
|
}
|
|
}
|
|
|
|
/* Gets the lens and clipping values from a camera of lamp type object */
|
|
void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
|
|
{
|
|
if (!ob) return;
|
|
|
|
if(ob->type==OB_LAMP ) {
|
|
Lamp *la = ob->data;
|
|
if (lens) {
|
|
float x1, fac;
|
|
fac= cos( M_PI*la->spotsize/360.0);
|
|
x1= saacos(fac);
|
|
*lens= 16.0*fac/sin(x1);
|
|
}
|
|
if (clipsta) *clipsta= la->clipsta;
|
|
if (clipend) *clipend= la->clipend;
|
|
}
|
|
else if(ob->type==OB_CAMERA) {
|
|
Camera *cam= ob->data;
|
|
if (lens) *lens= cam->lens;
|
|
if (clipsta) *clipsta= cam->clipsta;
|
|
if (clipend) *clipend= cam->clipend;
|
|
}
|
|
}
|
|
|
|
|
|
int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
|
|
{
|
|
Camera *cam=NULL;
|
|
float lens, fac, x1, y1, x2, y2;
|
|
float winx= (float)winxi, winy= (float)winyi;
|
|
int orth= 0;
|
|
|
|
lens= G.vd->lens;
|
|
|
|
*clipsta= G.vd->near;
|
|
*clipend= G.vd->far;
|
|
|
|
/*
|
|
* Cant use this since we need the fac and x1 values set
|
|
* if(G.vd->persp==2)
|
|
object_view_settings(G.vd->camera, &lens, &(*clipsta), &(*clipend));*/
|
|
|
|
if(G.vd->persp==2) {
|
|
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);
|
|
|
|
*clipsta= la->clipsta;
|
|
*clipend= la->clipend;
|
|
}
|
|
else if(G.vd->camera->type==OB_CAMERA) {
|
|
cam= G.vd->camera->data;
|
|
lens= cam->lens;
|
|
*clipsta= cam->clipsta;
|
|
*clipend= cam->clipend;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
*clipend *= 0.5; // otherwise too extreme low zbuffer quality
|
|
*clipsta= - *clipend;
|
|
orth= 1;
|
|
}
|
|
else {
|
|
/* fac for zoom, also used for camdx */
|
|
if(G.vd->persp==2) {
|
|
fac= (1.41421+( (float)G.vd->camzoom )/50.0);
|
|
fac*= fac;
|
|
}
|
|
else fac= 2.0;
|
|
|
|
/* viewplane size depends... */
|
|
if(cam && cam->type==CAM_ORTHO) {
|
|
/* ortho_scale == 1 means exact 1 to 1 mapping */
|
|
float dfac= 2.0*cam->ortho_scale/fac;
|
|
|
|
if(winx>winy) x1= -dfac;
|
|
else x1= -winx*dfac/winy;
|
|
x2= -x1;
|
|
|
|
if(winx>winy) y1= -winy*dfac/winx;
|
|
else y1= -dfac;
|
|
y2= -y1;
|
|
orth= 1;
|
|
}
|
|
else {
|
|
float dfac;
|
|
|
|
if(winx>winy) dfac= 64.0/(fac*winx*lens);
|
|
else dfac= 64.0/(fac*winy*lens);
|
|
|
|
x1= - *clipsta * winx*dfac;
|
|
x2= -x1;
|
|
y1= - *clipsta * winy*dfac;
|
|
y2= -y1;
|
|
orth= 0;
|
|
}
|
|
/* cam view offset */
|
|
if(cam) {
|
|
float dx= 0.5*fac*G.vd->camdx*(x2-x1);
|
|
float dy= 0.5*fac*G.vd->camdy*(y2-y1);
|
|
x1+= dx;
|
|
x2+= dx;
|
|
y1+= dy;
|
|
y2+= dy;
|
|
}
|
|
}
|
|
|
|
if(pixsize) {
|
|
float viewfac;
|
|
|
|
if(orth) {
|
|
viewfac= (winx >= winy)? winx: winy;
|
|
*pixsize= 1.0f/viewfac;
|
|
}
|
|
else {
|
|
viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
|
|
*pixsize= *clipsta/viewfac;
|
|
}
|
|
}
|
|
|
|
viewplane->xmin= x1;
|
|
viewplane->ymin= y1;
|
|
viewplane->xmax= x2;
|
|
viewplane->ymax= y2;
|
|
|
|
return orth;
|
|
}
|
|
|
|
/* important to not set windows active in here, can be renderwin for example */
|
|
void setwinmatrixview3d(int winx, int winy, rctf *rect) /* rect: for picking */
|
|
{
|
|
rctf viewplane;
|
|
float clipsta, clipend, x1, y1, x2, y2;
|
|
int orth;
|
|
|
|
orth= get_view3d_viewplane(winx, winy, &viewplane, &clipsta, &clipend, NULL);
|
|
// printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
|
|
x1= viewplane.xmin;
|
|
y1= viewplane.ymin;
|
|
x2= viewplane.xmax;
|
|
y2= viewplane.ymax;
|
|
|
|
if(rect) { /* picking */
|
|
rect->xmin/= (float)curarea->winx;
|
|
rect->xmin= x1+rect->xmin*(x2-x1);
|
|
rect->ymin/= (float)curarea->winy;
|
|
rect->ymin= y1+rect->ymin*(y2-y1);
|
|
rect->xmax/= (float)curarea->winx;
|
|
rect->xmax= x1+rect->xmax*(x2-x1);
|
|
rect->ymax/= (float)curarea->winy;
|
|
rect->ymax= y1+rect->ymax*(y2-y1);
|
|
|
|
if(orth) myortho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
|
|
else mywindow(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
|
|
|
|
}
|
|
else {
|
|
if(orth) myortho(x1, x2, y1, y2, clipsta, clipend);
|
|
else mywindow(x1, x2, y1, y2, clipsta, clipend);
|
|
}
|
|
|
|
/* not sure what this was for? (ton) */
|
|
glMatrixMode(GL_PROJECTION);
|
|
mygetmatrix(curarea->winmat);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
}
|
|
|
|
void obmat_to_viewmat(Object *ob, short smooth)
|
|
{
|
|
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);
|
|
if (smooth) {
|
|
float new_quat[4];
|
|
if (G.vd->persp==2 && G.vd->camera) {
|
|
/* were from a camera view */
|
|
|
|
float orig_ofs[3];
|
|
float orig_dist= G.vd->dist;
|
|
float orig_lens= G.vd->lens;
|
|
VECCOPY(orig_ofs, G.vd->ofs);
|
|
|
|
/* Switch from camera view */
|
|
Mat3ToQuat(tmat, new_quat);
|
|
|
|
G.vd->persp=1;
|
|
G.vd->dist= 0.0;
|
|
|
|
view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
|
|
smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
|
|
|
|
G.vd->persp=2; /* just to be polite, not needed */
|
|
|
|
} else {
|
|
Mat3ToQuat(tmat, new_quat);
|
|
smooth_view(G.vd, NULL, new_quat, NULL, NULL);
|
|
}
|
|
} else {
|
|
Mat3ToQuat(tmat, G.vd->viewquat);
|
|
}
|
|
}
|
|
|
|
/* dont set windows active in in here, is used by renderwin too */
|
|
void setviewmatrixview3d()
|
|
{
|
|
if(G.vd->persp>=2) { /* obs/camera */
|
|
if(G.vd->camera) {
|
|
where_is_object(G.vd->camera);
|
|
obmat_to_viewmat(G.vd->camera, 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;
|
|
if(G.vd->ob_centre) {
|
|
Object *ob= G.vd->ob_centre;
|
|
float vec[3];
|
|
|
|
VECCOPY(vec, ob->obmat[3]);
|
|
if(ob->type==OB_ARMATURE && G.vd->ob_centre_bone[0]) {
|
|
bPoseChannel *pchan= get_pose_channel(ob->pose, G.vd->ob_centre_bone);
|
|
if(pchan) {
|
|
VECCOPY(vec, pchan->pose_mat[3]);
|
|
Mat4MulVecfl(ob->obmat, vec);
|
|
}
|
|
}
|
|
i_translate(-vec[0], -vec[1], -vec[2], G.vd->viewmat);
|
|
}
|
|
else i_translate(G.vd->ofs[0], G.vd->ofs[1], G.vd->ofs[2], G.vd->viewmat);
|
|
}
|
|
}
|
|
|
|
void setcameratoview3d(void)
|
|
{
|
|
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*/
|
|
/* Warning: be sure to account for a negative return value
|
|
* This is an error, "Too many objects in select buffer"
|
|
* and no action should be taken (can crash blender) if this happens
|
|
*/
|
|
short view3d_opengl_select(unsigned int *buffer, unsigned int bufsize, short x1, short y1, short x2, short y2)
|
|
{
|
|
rctf rect;
|
|
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(curarea->winx, curarea->winy, &rect);
|
|
Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
|
|
|
|
if(G.vd->drawtype > OB_WIRE) {
|
|
G.vd->zbuf= TRUE;
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
if(G.vd->flag & V3D_CLIPPING)
|
|
view3d_set_clipping(G.vd);
|
|
|
|
glSelectBuffer( bufsize, (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, DRAW_PICKING|DRAW_CONSTCOLOR);
|
|
}
|
|
else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
|
|
draw_object(BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
|
|
}
|
|
else {
|
|
Base *base;
|
|
|
|
G.vd->xray= TRUE; // otherwise it postpones drawing
|
|
for(base= G.scene->base.first; base; base= base->next) {
|
|
if(base->lay & G.vd->lay) {
|
|
|
|
if (base->object->restrictflag & OB_RESTRICT_SELECT)
|
|
base->selcol= 0;
|
|
else {
|
|
base->selcol= code;
|
|
glLoadName(code);
|
|
draw_object(base, DRAW_PICKING|DRAW_CONSTCOLOR);
|
|
|
|
/* we draw group-duplicators for selection too */
|
|
if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
|
|
ListBase *lb;
|
|
DupliObject *dob;
|
|
Base tbase;
|
|
|
|
tbase.flag= OB_FROMDUPLI;
|
|
lb= object_duplilist(G.scene, base->object);
|
|
|
|
for(dob= lb->first; dob; dob= dob->next) {
|
|
tbase.object= dob->ob;
|
|
Mat4CpyMat4(dob->ob->obmat, dob->mat);
|
|
|
|
draw_object(&tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
|
|
|
|
Mat4CpyMat4(dob->ob->obmat, dob->omat);
|
|
}
|
|
free_object_duplilist(lb);
|
|
}
|
|
code++;
|
|
}
|
|
}
|
|
}
|
|
G.vd->xray= FALSE; // restore
|
|
}
|
|
|
|
glPopName(); /* see above (pushname) */
|
|
hits= glRenderMode(GL_RENDER);
|
|
|
|
G.f &= ~G_PICKSEL;
|
|
setwinmatrixview3d(curarea->winx, curarea->winy, NULL);
|
|
Mat4MulMat4(G.vd->persmat, G.vd->viewmat, curarea->winmat);
|
|
|
|
if(G.vd->drawtype > OB_WIRE) {
|
|
G.vd->zbuf= 0;
|
|
glDisable(GL_DEPTH_TEST);
|
|
}
|
|
persp(PERSP_WIN);
|
|
|
|
if(G.vd->flag & V3D_CLIPPING)
|
|
view3d_clr_clipping();
|
|
|
|
if(hits<0) error("Too many objects in select buffer");
|
|
|
|
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;
|
|
|
|
INIT_MINMAX(min, max);
|
|
|
|
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;
|
|
if (G.vd->near> 0.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;
|
|
}
|
|
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
|
|
}
|
|
|
|
void centerview() /* like a localview without local! */
|
|
{
|
|
Object *ob= OBACT;
|
|
float size, min[3], max[3], afm[3];
|
|
int ok=0;
|
|
|
|
/* SMOOTHVIEW */
|
|
float new_ofs[3];
|
|
float new_dist;
|
|
|
|
INIT_MINMAX(min, max);
|
|
|
|
if (G.f & G_WEIGHTPAINT) {
|
|
/* hardcoded exception, we look for the one selected armature */
|
|
/* this is weak code this way, we should make a generic active/selection callback interface once... */
|
|
Base *base;
|
|
for(base=FIRSTBASE; base; base= base->next) {
|
|
if(TESTBASELIB(base)) {
|
|
if(base->object->type==OB_ARMATURE)
|
|
if(base->object->flag & OB_POSEMODE)
|
|
break;
|
|
}
|
|
}
|
|
if(base)
|
|
ob= base->object;
|
|
}
|
|
|
|
|
|
if(G.obedit) {
|
|
ok = minmax_verts(min, max); /* only selected */
|
|
}
|
|
else if(ob && (ob->flag & OB_POSEMODE)) {
|
|
if(ob->pose) {
|
|
bArmature *arm= ob->data;
|
|
bPoseChannel *pchan;
|
|
float vec[3];
|
|
|
|
for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
|
|
if(pchan->bone->flag & BONE_SELECTED) {
|
|
if(pchan->bone->layer & arm->layer) {
|
|
ok= 1;
|
|
VECCOPY(vec, pchan->pose_head);
|
|
Mat4MulVecfl(ob->obmat, vec);
|
|
DO_MINMAX(vec, min, max);
|
|
VECCOPY(vec, pchan->pose_tail);
|
|
Mat4MulVecfl(ob->obmat, vec);
|
|
DO_MINMAX(vec, min, max);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (FACESEL_PAINT_TEST) {
|
|
ok= minmax_tface(min, max);
|
|
}
|
|
else if (G.f & G_PARTICLEEDIT) {
|
|
ok= PE_minmax(min, max);
|
|
}
|
|
else {
|
|
Base *base= FIRSTBASE;
|
|
while(base) {
|
|
if TESTBASE(base) {
|
|
minmax_object(base->object, min, max);
|
|
/* account for duplis */
|
|
minmax_object_duplis(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 <= G.vd->near*1.5) size= G.vd->near*1.5;
|
|
|
|
new_ofs[0]= -(min[0]+max[0])/2.0;
|
|
new_ofs[1]= -(min[1]+max[1])/2.0;
|
|
new_ofs[2]= -(min[2]+max[2])/2.0;
|
|
|
|
new_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;
|
|
new_dist*= size;
|
|
}
|
|
|
|
G.vd->cursor[0]= -new_ofs[0];
|
|
G.vd->cursor[1]= -new_ofs[1];
|
|
G.vd->cursor[2]= -new_ofs[2];
|
|
|
|
if (G.vd->persp==2 && G.vd->camera) {
|
|
float orig_lens= G.vd->lens;
|
|
|
|
G.vd->persp=1;
|
|
G.vd->dist= 0.0;
|
|
view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
|
|
smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
|
|
} else {
|
|
if(G.vd->persp>=2)
|
|
G.vd->persp= 1;
|
|
|
|
smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
|
|
}
|
|
scrarea_queue_winredraw(curarea);
|
|
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
|
|
|
|
}
|
|
|
|
|
|
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->flag |= SELECT;
|
|
}
|
|
base->object->lay= base->lay;
|
|
}
|
|
base= base->next;
|
|
}
|
|
|
|
countall();
|
|
allqueue(REDRAWVIEW3D, 0); /* because of select */
|
|
allqueue(REDRAWOOPS, 0); /* because of select */
|
|
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
|
|
}
|
|
}
|
|
|
|
void view3d_home(int center)
|
|
{
|
|
Base *base;
|
|
float size, min[3], max[3], afm[3];
|
|
int ok= 1, onedone=0;
|
|
|
|
if(center) {
|
|
min[0]= min[1]= min[2]= 0.0;
|
|
max[0]= max[1]= max[2]= 0.0;
|
|
}
|
|
else {
|
|
INIT_MINMAX(min, max);
|
|
}
|
|
|
|
for(base= FIRSTBASE; base; base= base->next) {
|
|
if(base->lay & G.vd->lay) {
|
|
onedone= 1;
|
|
minmax_object(base->object, min, max);
|
|
}
|
|
}
|
|
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) {
|
|
float new_dist;
|
|
float new_ofs[3];
|
|
|
|
new_dist = size;
|
|
new_ofs[0]= -(min[0]+max[0])/2.0;
|
|
new_ofs[1]= -(min[1]+max[1])/2.0;
|
|
new_ofs[2]= -(min[2]+max[2])/2.0;
|
|
|
|
// 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;
|
|
new_dist*= size;
|
|
}
|
|
|
|
if (G.vd->persp==2 && G.vd->camera) {
|
|
/* switch out of camera view */
|
|
float orig_lens= G.vd->lens;
|
|
|
|
G.vd->persp=1;
|
|
G.vd->dist= 0.0;
|
|
view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
|
|
smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
|
|
|
|
} else {
|
|
if(G.vd->persp>=2) G.vd->persp= 1;
|
|
smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
|
|
}
|
|
scrarea_queue_winredraw(curarea);
|
|
}
|
|
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
|
|
|
|
}
|
|
|
|
|
|
void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
|
|
{
|
|
float alignaxis[3] = {0.0, 0.0, 0.0};
|
|
float norm[3], axis[3], angle, new_quat[4];
|
|
|
|
if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
|
|
else alignaxis[-axisidx-1]= -1.0;
|
|
|
|
VECCOPY(norm, vec);
|
|
Normalize(norm);
|
|
|
|
angle= acos(Inpf(alignaxis, norm));
|
|
Crossf(axis, alignaxis, norm);
|
|
VecRotToQuat(axis, -angle, new_quat);
|
|
|
|
v3d->view= 0;
|
|
|
|
if (v3d->persp==2 && v3d->camera) {
|
|
/* switch out of camera view */
|
|
float orig_ofs[3];
|
|
float orig_dist= v3d->dist;
|
|
float orig_lens= v3d->lens;
|
|
|
|
VECCOPY(orig_ofs, v3d->ofs);
|
|
G.vd->persp=1;
|
|
G.vd->dist= 0.0;
|
|
view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
|
|
smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
|
|
} else {
|
|
if (v3d->persp>=2) v3d->persp= 1; /* switch out of camera mode */
|
|
smooth_view(v3d, NULL, new_quat, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* SMOOTHVIEW */
|
|
void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
|
|
{
|
|
/* View Animation enabled */
|
|
if (U.smooth_viewtx) {
|
|
int i;
|
|
char changed = 0;
|
|
float step = 0.0, step_inv;
|
|
float orig_dist;
|
|
float orig_lens;
|
|
float orig_quat[4];
|
|
float orig_ofs[3];
|
|
|
|
double time_allowed, time_current, time_start;
|
|
|
|
/* if there is no difference, return */
|
|
changed = 0; /* zero means no difference */
|
|
if (dist) {
|
|
if ((*dist) != v3d->dist)
|
|
changed = 1;
|
|
}
|
|
|
|
if (lens) {
|
|
if ((*lens) != v3d->lens)
|
|
changed = 1;
|
|
}
|
|
|
|
if (!changed && ofs) {
|
|
if ((ofs[0]!=v3d->ofs[0]) ||
|
|
(ofs[1]!=v3d->ofs[1]) ||
|
|
(ofs[2]!=v3d->ofs[2]) )
|
|
changed = 1;
|
|
}
|
|
|
|
if (!changed && quat ) {
|
|
if ((quat[0]!=v3d->viewquat[0]) ||
|
|
(quat[1]!=v3d->viewquat[1]) ||
|
|
(quat[2]!=v3d->viewquat[2]) ||
|
|
(quat[3]!=v3d->viewquat[3]) )
|
|
changed = 1;
|
|
}
|
|
|
|
/* The new view is different from teh old one
|
|
* so animate the view */
|
|
if (changed) {
|
|
|
|
/* store original values */
|
|
VECCOPY(orig_ofs, v3d->ofs);
|
|
QUATCOPY(orig_quat, v3d->viewquat);
|
|
orig_dist = v3d->dist;
|
|
orig_lens = v3d->lens;
|
|
|
|
time_allowed= (float)U.smooth_viewtx / 1000.0;
|
|
time_current = time_start = PIL_check_seconds_timer();
|
|
|
|
/* if this is view rotation only
|
|
* we can decrease the time allowed by
|
|
* the angle between quats
|
|
* this means small rotations wont lag */
|
|
if (quat && !ofs && !dist) {
|
|
float vec1[3], vec2[3];
|
|
VECCOPY(vec1, quat);
|
|
VECCOPY(vec2, v3d->viewquat);
|
|
Normalize(vec1);
|
|
Normalize(vec2);
|
|
/* scale the time allowed by the rotation */
|
|
time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2);
|
|
}
|
|
|
|
while (time_start + time_allowed > time_current) {
|
|
|
|
step = (float)((time_current-time_start) / time_allowed);
|
|
|
|
/* ease in/out */
|
|
if (step < 0.5) step = pow(step*2, 2)/2;
|
|
else step = 1-(pow(2*(1-step) ,2)/2);
|
|
|
|
step_inv = 1-step;
|
|
|
|
if (ofs)
|
|
for (i=0; i<3; i++)
|
|
v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
|
|
|
|
|
|
if (quat)
|
|
QuatInterpol(v3d->viewquat, orig_quat, quat, step);
|
|
|
|
if (dist)
|
|
v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
|
|
|
|
if (lens)
|
|
v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
|
|
|
|
/*redraw the view*/
|
|
scrarea_do_windraw(curarea);
|
|
screen_swapbuffers();
|
|
|
|
time_current= PIL_check_seconds_timer();
|
|
}
|
|
}
|
|
}
|
|
|
|
/* set these values even if animation is enabled because flaot
|
|
* error will make then not quite accurate */
|
|
if (ofs)
|
|
VECCOPY(v3d->ofs, ofs);
|
|
if (quat)
|
|
QUATCOPY(v3d->viewquat, quat);
|
|
if (dist)
|
|
v3d->dist = *dist;
|
|
if (lens)
|
|
v3d->lens = *lens;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Gets the view trasnformation from a camera
|
|
* currently dosnt take camzoom into account
|
|
*
|
|
* The dist is not modified for this function, if NULL its assimed zero
|
|
* */
|
|
void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
|
|
{
|
|
float bmat[4][4];
|
|
float imat[4][4];
|
|
float tmat[3][3];
|
|
|
|
if (!ob) return;
|
|
|
|
/* Offset */
|
|
if (ofs) {
|
|
where_is_object(ob);
|
|
VECCOPY(ofs, ob->obmat[3]);
|
|
VecMulf(ofs, -1.0f); /*flip the vector*/
|
|
}
|
|
|
|
/* Quat */
|
|
if (quat) {
|
|
Mat4CpyMat4(bmat, ob->obmat);
|
|
Mat4Ortho(bmat);
|
|
Mat4Invert(imat, bmat);
|
|
Mat3CpyMat4(tmat, imat);
|
|
Mat3ToQuat(tmat, quat);
|
|
}
|
|
|
|
if (dist) {
|
|
float vec[3];
|
|
Mat3CpyMat4(tmat, ob->obmat);
|
|
|
|
vec[0]= vec[1] = 0.0;
|
|
vec[2]= -(*dist);
|
|
Mat3MulVecfl(tmat, vec);
|
|
VecSubf(ofs, ofs, vec);
|
|
}
|
|
|
|
/* Lens */
|
|
if (lens)
|
|
object_view_settings(ob, lens, NULL, NULL);
|
|
}
|
|
|
|
/* For use with smooth view
|
|
*
|
|
* the current view is unchanged, blend between the current view and the
|
|
* camera view
|
|
* */
|
|
void smooth_view_to_camera(View3D *v3d)
|
|
{
|
|
if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != 2) {
|
|
return;
|
|
} else {
|
|
Object *ob = v3d->camera;
|
|
|
|
float orig_ofs[3];
|
|
float orig_dist=v3d->dist;
|
|
float orig_lens=v3d->lens;
|
|
float new_dist=0.0;
|
|
float new_lens=35.0;
|
|
float new_quat[4];
|
|
float new_ofs[3];
|
|
|
|
VECCOPY(orig_ofs, v3d->ofs);
|
|
|
|
view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
|
|
|
|
G.vd->persp=1;
|
|
smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
|
|
VECCOPY(v3d->ofs, orig_ofs);
|
|
v3d->lens= orig_lens;
|
|
v3d->dist = orig_dist; /* restore the dist */
|
|
|
|
v3d->camera = ob;
|
|
v3d->persp=2;
|
|
}
|
|
}
|