542
// ndof scaling will be moved to user setting.
543
// In the mean time this is just a place holder.
545
// Note: scaling in the plugin and ghostwinlay.c
546
// should be removed. With driver default setting,
547
// each axis returns approx. +-200 max deflection.
549
// The values I selected are based on the older
550
// polling i/f. With event i/f, the sensistivity
551
// can be increased for improved response from
552
// small deflections of the device input.
555
// lukep notes : i disagree on the range.
556
// the normal 3Dconnection driver give +/-400
557
// on defaut range in other applications
558
// and up to +/- 1000 if set to maximum
559
// because i remove the scaling by delta,
560
// which was a bad idea as it depend of the system
561
// speed and os, i changed the scaling values, but
562
// those are still not ok
565
float ndof_axis_scale[6] = {
574
// statics for controlling G.vd->dist corrections.
575
// viewmoveNDOF zeros and adjusts G.vd->ofs.
576
// viewmove restores based on dz_flag state.
581
void viewmoveNDOFfly(int mode)
586
// static fval[6] for low pass filter; device input vector is dval[6]
587
static float fval[6];
588
float tvec[3],rvec[3];
594
/*----------------------------------------------------
595
* sometimes this routine is called from headerbuttons
596
* viewmove needs to refresh the screen
598
areawinset(curarea->win);
601
// fetch the current state of the ndof device
604
if (G.vd->ndoffilter)
605
filterNDOFvalues(fval);
607
// for(i=0;i<7;i++) printf("%f ",dval[i]);
611
// Scale input values
613
// if(dval[6] == 0) return; // guard against divide by zero
618
dval[i] = dval[i] * ndof_axis_scale[i];
620
// non-linear scaling
622
dval[i] = -1.0f * dval[i] * dval[i];
624
dval[i] = dval[i] * dval[i];
628
// low pass filter with zero crossing reset
631
if((dval[i] * fval[i]) >= 0)
632
dval[i] = (fval[i] * 15 + dval[i]) / 16;
638
// force perspective mode. This is a hack and is
639
// incomplete. It doesn't actually effect the view
640
// until the first draw and doesn't update the menu
641
// to reflect persp mode.
643
G.vd->persp = V3D_PERSP;
646
// Correct the distance jump if G.vd->dist != 0
648
// This is due to a side effect of the original
649
// mouse view rotation code. The rotation point is
650
// set a distance in front of the viewport to
651
// make rotating with the mouse look better.
652
// The distance effect is written at a low level
653
// in the view management instead of the mouse
654
// view function. This means that all other view
655
// movement devices must subtract this from their
656
// view transformations.
658
if(G.vd->dist != 0.0) {
661
upvec[0] = upvec[1] = 0;
662
upvec[2] = G.vd->dist;
663
Mat3CpyMat4(mat, G.vd->viewinv);
664
Mat3MulVecfl(mat, upvec);
665
VecSubf(G.vd->ofs, G.vd->ofs, upvec);
676
// rotate device x and y by view z
678
Mat3CpyMat4(mat, G.vd->viewinv);
680
Mat3MulVecfl(mat, rvec);
684
phi = Normalize(rvec);
686
VecRotToQuat(rvec,phi,q1);
687
QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
697
// the next three lines rotate the x and y translation coordinates
698
// by the current z axis angle
700
Mat3CpyMat4(mat, G.vd->viewinv);
702
Mat3MulVecfl(mat, tvec);
704
// translate the view
706
VecSubf(G.vd->ofs, G.vd->ofs, tvec);
709
/*----------------------------------------------------
712
scrarea_do_windraw(curarea);
713
screen_swapbuffers();
715
// update render preview window
717
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
528
720
void viewmove(int mode)
722
static float lastofs[3] = {0,0,0};
530
723
Object *ob = OBACT;
531
724
float firstvec[3], newvec[3], dvec[3];
532
725
float reverse, oldquat[4], q1[4], si, phi, dist0;
533
float ofs[3], obofs[3];
726
float ofs[3], obofs[3]= {0.0f, 0.0f, 0.0f};
535
short mvalball[2], mval[2], mvalo[2];
728
short mvalball[2], mval[2], mvalo[2], mval_area[2], mvali[2];
536
729
short use_sel = 0;
537
730
short preview3d_event= 1;
539
/* 3D window may not be defined */
732
// locals for dist correction
736
/* 3D window may not be defined */
541
738
fprintf( stderr, "G.vd == NULL in viewmove()\n" );
742
// dist correction from other movement devices
744
if((dz_flag)||G.vd->dist==0) {
747
upvec[0] = upvec[1] = 0;
748
upvec[2] = G.vd->dist;
749
Mat3CpyMat4(mat, G.vd->viewinv);
750
Mat3MulVecfl(mat, upvec);
751
VecAddf(G.vd->ofs, G.vd->ofs, upvec);
545
756
/* sometimes this routine is called from headerbuttons */
547
758
areawinset(curarea->win);
777
1008
if( !(get_mbut() & (L_MOUSE|M_MOUSE))) break;
1011
if(G.vd->depths) G.vd->depths->damaged= 1;
1012
retopo_queue_updates(G.vd);
1013
allqueue(REDRAWVIEW3D, 0);
780
1015
if(preview3d_event)
781
1016
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
783
1018
BIF_view3d_previewrender_signal(curarea, PR_PROJECTED);
787
int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend)
1022
void view_zoom_mouseloc(float dfac, short *mouseloc)
1024
if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
1031
/* find the current window width and height */
1032
vb[0] = G.vd->area->winx;
1033
vb[1] = G.vd->area->winy;
1035
tpos[0] = -G.vd->ofs[0];
1036
tpos[1] = -G.vd->ofs[1];
1037
tpos[2] = -G.vd->ofs[2];
1039
/* Project cursor position into 3D space */
1040
initgrabz(tpos[0], tpos[1], tpos[2]);
1041
window_to_3d(dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
1043
/* Calculate view target position for dolly */
1044
tvec[0] = -(tpos[0] + dvec[0]);
1045
tvec[1] = -(tpos[1] + dvec[1]);
1046
tvec[2] = -(tpos[2] + dvec[2]);
1048
/* Offset to target position and dolly */
1049
new_dist = G.vd->dist * dfac;
1051
VECCOPY(G.vd->ofs, tvec);
1052
G.vd->dist = new_dist;
1054
/* Calculate final offset */
1055
dvec[0] = tvec[0] + dvec[0] * dfac;
1056
dvec[1] = tvec[1] + dvec[1] * dfac;
1057
dvec[2] = tvec[2] + dvec[2] * dfac;
1059
VECCOPY(G.vd->ofs, dvec);
1065
void viewmoveNDOF(int mode)
1069
float sbadjust = 1.0f;
1075
float xvec[3] = {1,0,0};
1076
float yvec[3] = {0,-1,0};
1077
float zvec[3] = {0,0,1};
1083
float d, curareaX, curareaY;
1085
/* Sensitivity will control how fast the view rotates. The value was
1086
* obtained experimentally by tweaking until the author didn't get dizzy watching.
1087
* Perhaps this should be a configurable user parameter.
1089
float psens = 0.005f * (float) U.ndof_pan; /* pan sensitivity */
1090
float rsens = 0.005f * (float) U.ndof_rotate; /* rotate sensitivity */
1091
float zsens = 0.3f; /* zoom sensitivity */
1093
const float minZoom = -30.0f;
1094
const float maxZoom = 300.0f;
1098
//printf("passing here \n");
1100
if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1104
/*----------------------------------------------------
1105
* sometimes this routine is called from headerbuttons
1106
* viewmove needs to refresh the screen
1108
areawinset(curarea->win);
1110
/*----------------------------------------------------
1111
* record how much time has passed. clamp at 10 Hz
1112
* pretend the previous frame occured at the clamped time
1114
// now = PIL_check_seconds_timer();
1115
// frametime = (now - prevTime);
1116
// if (frametime > 0.1f){ /* if more than 1/10s */
1117
// frametime = 1.0f/60.0; /* clamp at 1/60s so no jumps when starting to move */
1120
// sbadjust *= 60 * frametime; /* normalize ndof device adjustments to 100Hz for framerate independence */
1122
/* fetch the current state of the ndof device */
1124
// printf(" motion command %f %f %f %f %f %f %f \n", fval[0], fval[1], fval[2],
1125
// fval[3], fval[4], fval[5], fval[6]);
1126
if (G.vd->ndoffilter)
1127
filterNDOFvalues(fval);
1130
// put scaling back here, was previously in ghostwinlay
1131
fval[0] = fval[0] * (1.0f/800.0f);
1132
fval[1] = fval[1] * (1.0f/800.0f);
1133
fval[2] = fval[2] * (1.0f/800.0f);
1134
fval[3] = fval[3] * 0.00005f;
1135
fval[4] = fval[4] * 0.00005f;
1136
fval[5] = fval[5] * 0.00005f;
1137
fval[6] = fval[6] / 1000000.0f;
1139
// scale more if not in perspective mode
1140
if (G.vd->persp == V3D_ORTHO) {
1141
fval[0] = fval[0] * 0.05f;
1142
fval[1] = fval[1] * 0.05f;
1143
fval[2] = fval[2] * 0.05f;
1144
fval[3] = fval[3] * 0.9f;
1145
fval[4] = fval[4] * 0.9f;
1146
fval[5] = fval[5] * 0.9f;
1151
/* set object offset */
1153
obofs[0] = -ob->obmat[3][0];
1154
obofs[1] = -ob->obmat[3][1];
1155
obofs[2] = -ob->obmat[3][2];
1158
VECCOPY(obofs, G.vd->ofs);
1161
/* calc an adjustment based on distance from camera */
1163
VecSubf(diff, obofs, G.vd->ofs);
1164
d = VecLength(diff);
1169
reverse = (G.vd->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1171
/*----------------------------------------------------
1175
curareaX = sbadjust * psens * fval[0];
1176
curareaY = sbadjust * psens * fval[1];
1177
dvec[0] = curareaX * G.vd->persinv[0][0] + curareaY * G.vd->persinv[1][0];
1178
dvec[1] = curareaX * G.vd->persinv[0][1] + curareaY * G.vd->persinv[1][1];
1179
dvec[2] = curareaX * G.vd->persinv[0][2] + curareaY * G.vd->persinv[1][2];
1180
VecAddf(G.vd->ofs, G.vd->ofs, dvec);
1182
/*----------------------------------------------------
1185
len = zsens * sbadjust * fval[2];
1187
if (G.vd->persp==V3D_CAMOB) {
1188
if(G.vd->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1189
G.vd->camzoom+= 10.0f * -len;
1191
if (G.vd->camzoom < minZoom) G.vd->camzoom = minZoom;
1192
else if (G.vd->camzoom > maxZoom) G.vd->camzoom = maxZoom;
1194
else if ((G.vd->dist> 0.001*G.vd->grid) && (G.vd->dist<10.0*G.vd->far)) {
1195
G.vd->dist*=(1.0 + len);
1199
/*----------------------------------------------------
1200
* ndof device turntable
1201
* derived from the turntable code in viewmove
1204
/* Get the 3x3 matrix and its inverse from the quaternion */
1205
QuatToMat3(G.vd->viewquat, m);
1208
/* Determine the direction of the x vector (for rotating up and down) */
1209
/* This can likely be compuated directly from the quaternion. */
1210
Mat3MulVecfl(m_inv,xvec);
1211
Mat3MulVecfl(m_inv,yvec);
1212
Mat3MulVecfl(m_inv,zvec);
1214
/* Perform the up/down rotation */
1215
phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1218
q1[1] = si * xvec[0];
1219
q1[2] = si * xvec[1];
1220
q1[3] = si * xvec[2];
1221
QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1224
QuatConj(q1); /* conj == inv for unit quat */
1225
VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1226
QuatMulVecf(q1, G.vd->ofs);
1227
VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1230
/* Perform the orbital rotation */
1231
/* Perform the orbital rotation
1232
If the seen Up axis is parallel to the zoom axis, rotation should be
1233
achieved with a pure Roll motion (no Spin) on the device. When you start
1234
to tilt, moving from Top to Side view, Spinning will increasingly become
1235
more relevant while the Roll component will decrease. When a full
1236
Side view is reached, rotations around the world's Up axis are achieved
1237
with a pure Spin-only motion. In other words the control of the spinning
1238
around the world's Up axis should move from the device's Spin axis to the
1239
device's Roll axis depending on the orientation of the world's Up axis
1240
relative to the screen. */
1241
//phi = sbadjust * rsens * reverse * fval[4]; /* spin the knob, y axis */
1242
phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
1244
q1[1] = q1[2] = 0.0;
1246
QuatMul(G.vd->viewquat, G.vd->viewquat, q1);
1250
VecSubf(G.vd->ofs, G.vd->ofs, obofs);
1251
QuatMulVecf(q1, G.vd->ofs);
1252
VecAddf(G.vd->ofs, G.vd->ofs, obofs);
1255
/*----------------------------------------------------
1256
* refresh the screen
1258
scrarea_do_windraw(curarea);
1259
screen_swapbuffers();
1263
/* Gets the lens and clipping values from a camera of lamp type object */
1264
void object_view_settings(Object *ob, float *lens, float *clipsta, float *clipend)
1268
if(ob->type==OB_LAMP ) {
1269
Lamp *la = ob->data;
1272
fac= cos( M_PI*la->spotsize/360.0);
1274
*lens= 16.0*fac/sin(x1);
1276
if (clipsta) *clipsta= la->clipsta;
1277
if (clipend) *clipend= la->clipend;
1279
else if(ob->type==OB_CAMERA) {
1280
Camera *cam= ob->data;
1281
if (lens) *lens= cam->lens;
1282
if (clipsta) *clipsta= cam->clipsta;
1283
if (clipend) *clipend= cam->clipend;
1288
int get_view3d_viewplane(int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
789
1290
Camera *cam=NULL;
790
1291
float lens, fac, x1, y1, x2, y2;
937
1455
/* view quat calculation, needed for add object */
938
1456
Mat3CpyMat4(tmat, G.vd->viewmat);
939
Mat3ToQuat(tmat, G.vd->viewquat);
1459
if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
1460
/* were from a camera view */
1463
float orig_dist= G.vd->dist;
1464
float orig_lens= G.vd->lens;
1465
VECCOPY(orig_ofs, G.vd->ofs);
1467
/* Switch from camera view */
1468
Mat3ToQuat(tmat, new_quat);
1470
G.vd->persp=V3D_PERSP;
1473
view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1474
smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
1476
G.vd->persp=V3D_CAMOB; /* just to be polite, not needed */
1479
Mat3ToQuat(tmat, new_quat);
1480
smooth_view(G.vd, NULL, new_quat, NULL, NULL);
1483
Mat3ToQuat(tmat, G.vd->viewquat);
942
1487
/* dont set windows active in in here, is used by renderwin too */
943
1488
void setviewmatrixview3d()
947
if(G.vd->persp>=2) { /* obs/camera */
1490
if(G.vd->persp==V3D_CAMOB) { /* obs/camera */
948
1491
if(G.vd->camera) {
950
1492
where_is_object(G.vd->camera);
951
obmat_to_viewmat(G.vd->camera);
953
if(G.vd->camera->type==OB_CAMERA) {
954
cam= G.vd->camera->data;
955
//if(cam->type==CAM_ORTHO) G.vd->viewmat[3][2]*= 100.0;
1493
obmat_to_viewmat(G.vd->camera, 0);
959
1496
QuatToMat4(G.vd->viewquat, G.vd->viewmat);
1305
1870
afm[2]= (max[2]-min[2]);
1306
1871
size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1308
if(size<=0.01) size= 0.01;
1310
G.vd->ofs[0]= -(min[0]+max[0])/2.0;
1311
G.vd->ofs[1]= -(min[1]+max[1])/2.0;
1312
G.vd->ofs[2]= -(min[2]+max[2])/2.0;
1316
// correction for window aspect ratio
1873
if(size <= G.vd->near*1.5) size= G.vd->near*1.5;
1875
new_ofs[0]= -(min[0]+max[0])/2.0;
1876
new_ofs[1]= -(min[1]+max[1])/2.0;
1877
new_ofs[2]= -(min[2]+max[2])/2.0;
1881
/* correction for window aspect ratio */
1317
1882
if(curarea->winy>2 && curarea->winx>2) {
1318
1883
size= (float)curarea->winx/(float)curarea->winy;
1319
1884
if(size<1.0) size= 1.0/size;
1327
G.vd->cursor[0]= -G.vd->ofs[0];
1328
G.vd->cursor[1]= -G.vd->ofs[1];
1329
G.vd->cursor[2]= -G.vd->ofs[2];
1888
G.vd->cursor[0]= -new_ofs[0];
1889
G.vd->cursor[1]= -new_ofs[1];
1890
G.vd->cursor[2]= -new_ofs[2];
1892
if (G.vd->persp==V3D_CAMOB && G.vd->camera) {
1893
float orig_lens= G.vd->lens;
1895
G.vd->persp=V3D_PERSP;
1897
view_settings_from_ob(G.vd->camera, G.vd->ofs, NULL, NULL, &G.vd->lens);
1898
smooth_view(G.vd, new_ofs, NULL, &new_dist, &orig_lens);
1900
if(G.vd->persp==V3D_CAMOB)
1901
G.vd->persp= V3D_PERSP;
1903
smooth_view(G.vd, new_ofs, NULL, &new_dist, NULL);
1331
1905
scrarea_queue_winredraw(curarea);
1332
1906
BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1454
2036
void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1457
float norm[3], axis[3], angle;
1459
alignaxis[0]= alignaxis[1]= alignaxis[2]= 0.0;
1460
alignaxis[axisidx]= 1.0;
1462
norm[0]= vec[0], norm[1]= vec[1], norm[2]= vec[2];
2038
float alignaxis[3] = {0.0, 0.0, 0.0};
2039
float norm[3], axis[3], angle, new_quat[4];
2041
if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
2042
else alignaxis[-axisidx-1]= -1.0;
1465
2047
angle= acos(Inpf(alignaxis, norm));
1466
2048
Crossf(axis, alignaxis, norm);
1467
VecRotToQuat(axis, -angle, v3d->viewquat);
2049
VecRotToQuat(axis, -angle, new_quat);
1470
if (v3d->persp>=2) v3d->persp= 0; /* switch out of camera mode */
2053
if (v3d->persp==V3D_CAMOB && v3d->camera) {
2054
/* switch out of camera view */
2056
float orig_dist= v3d->dist;
2057
float orig_lens= v3d->lens;
2059
VECCOPY(orig_ofs, v3d->ofs);
2060
G.vd->persp= V3D_PERSP;
2062
view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
2063
smooth_view(G.vd, orig_ofs, new_quat, &orig_dist, &orig_lens);
2065
if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; /* switch out of camera mode */
2066
smooth_view(v3d, NULL, new_quat, NULL, NULL);
2073
void smooth_view(View3D *v3d, float *ofs, float *quat, float *dist, float *lens)
2075
/* View Animation enabled */
2076
if (U.smooth_viewtx) {
2079
float step = 0.0, step_inv;
2085
double time_allowed, time_current, time_start;
2087
/* if there is no difference, return */
2088
changed = 0; /* zero means no difference */
2090
if ((*dist) != v3d->dist)
2095
if ((*lens) != v3d->lens)
2099
if (!changed && ofs) {
2100
if ((ofs[0]!=v3d->ofs[0]) ||
2101
(ofs[1]!=v3d->ofs[1]) ||
2102
(ofs[2]!=v3d->ofs[2]) )
2106
if (!changed && quat ) {
2107
if ((quat[0]!=v3d->viewquat[0]) ||
2108
(quat[1]!=v3d->viewquat[1]) ||
2109
(quat[2]!=v3d->viewquat[2]) ||
2110
(quat[3]!=v3d->viewquat[3]) )
2114
/* The new view is different from the old one
2115
* so animate the view */
2118
/* store original values */
2119
VECCOPY(orig_ofs, v3d->ofs);
2120
QUATCOPY(orig_quat, v3d->viewquat);
2121
orig_dist = v3d->dist;
2122
orig_lens = v3d->lens;
2124
time_allowed= (float)U.smooth_viewtx / 1000.0;
2125
time_current = time_start = PIL_check_seconds_timer();
2127
/* if this is view rotation only
2128
* we can decrease the time allowed by
2129
* the angle between quats
2130
* this means small rotations wont lag */
2131
if (quat && !ofs && !dist) {
2132
float vec1[3], vec2[3];
2133
VECCOPY(vec1, quat);
2134
VECCOPY(vec2, v3d->viewquat);
2137
/* scale the time allowed by the rotation */
2138
time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2);
2141
while (time_start + time_allowed > time_current) {
2143
step = (float)((time_current-time_start) / time_allowed);
2146
if (step < 0.5) step = pow(step*2, 2)/2;
2147
else step = 1-(pow(2*(1-step) ,2)/2);
2153
v3d->ofs[i] = ofs[i]*step + orig_ofs[i]*step_inv;
2157
QuatInterpol(v3d->viewquat, orig_quat, quat, step);
2160
v3d->dist = ((*dist)*step) + (orig_dist*step_inv);
2163
v3d->lens = ((*lens)*step) + (orig_lens*step_inv);
2166
scrarea_do_windraw(curarea);
2167
screen_swapbuffers();
2169
time_current= PIL_check_seconds_timer();
2174
/* set these values even if animation is enabled because flaot
2175
* error will make then not quite accurate */
2177
VECCOPY(v3d->ofs, ofs);
2179
QUATCOPY(v3d->viewquat, quat);
2189
/* Gets the view trasnformation from a camera
2190
* currently dosnt take camzoom into account
2192
* The dist is not modified for this function, if NULL its assimed zero
2194
void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
2204
where_is_object(ob);
2205
VECCOPY(ofs, ob->obmat[3]);
2206
VecMulf(ofs, -1.0f); /*flip the vector*/
2211
Mat4CpyMat4(bmat, ob->obmat);
2213
Mat4Invert(imat, bmat);
2214
Mat3CpyMat4(tmat, imat);
2215
Mat3ToQuat(tmat, quat);
2220
Mat3CpyMat4(tmat, ob->obmat);
2222
vec[0]= vec[1] = 0.0;
2224
Mat3MulVecfl(tmat, vec);
2225
VecSubf(ofs, ofs, vec);
2230
object_view_settings(ob, lens, NULL, NULL);
2233
/* For use with smooth view
2235
* the current view is unchanged, blend between the current view and the
2238
void smooth_view_to_camera(View3D *v3d)
2240
if (!U.smooth_viewtx || !v3d->camera || G.vd->persp != V3D_CAMOB) {
2243
Object *ob = v3d->camera;
2246
float orig_dist=v3d->dist;
2247
float orig_lens=v3d->lens;
2249
float new_lens=35.0;
2253
VECCOPY(orig_ofs, v3d->ofs);
2255
view_settings_from_ob(ob, new_ofs, new_quat, NULL, &new_lens);
2257
G.vd->persp= V3D_PERSP;
2258
smooth_view(v3d, new_ofs, new_quat, &new_dist, &new_lens);
2259
VECCOPY(v3d->ofs, orig_ofs);
2260
v3d->lens= orig_lens;
2261
v3d->dist = orig_dist; /* restore the dist */
2264
v3d->persp= V3D_CAMOB;