My very first commit (kinda cool ) just to test my commit rights and to go through...
[blender.git] / source / blender / editors / space_view3d / view3d_edit.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_lamp_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_userdef_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_world_types.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
50 #include "BLI_rand.h"
51
52 #include "BKE_action.h"
53 #include "BKE_context.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_object.h"
56 #include "BKE_global.h"
57 #include "BKE_scene.h"
58 #include "BKE_screen.h"
59 #include "BKE_utildefines.h"
60
61 #include "RE_pipeline.h"        // make_stars
62
63 #include "BIF_gl.h"
64 #include "BIF_retopo.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68
69 #include "RNA_access.h"
70 #include "RNA_define.h"
71
72 #include "ED_screen.h"
73 #include "ED_types.h"
74
75 #include "UI_interface.h"
76 #include "UI_resources.h"
77 #include "UI_view2d.h"
78
79 #include "PIL_time.h" /* smoothview */
80
81 #include "view3d_intern.h"      // own include
82
83 /* ********************** view3d_edit: view manipulations ********************* */
84
85 /* ************************** init for view ops **********************************/
86
87 typedef struct ViewOpsData {
88         ARegion *ar;
89         View3D *v3d;
90
91         float oldquat[4];
92         float trackvec[3];
93         float ofs[3], obofs[3];
94         float reverse, dist0;
95
96         int origx, origy, oldx, oldy;
97         int origkey;
98
99 } ViewOpsData;
100
101 #define TRACKBALLSIZE  (1.1)
102
103 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
104 {
105         float x, y, radius, d, z, t;
106
107         radius= TRACKBALLSIZE;
108
109         /* normalize x and y */
110         x= (rect->xmax + rect->xmin)/2 - mx;
111         x/= (float)((rect->xmax - rect->xmin)/4);
112         y= (rect->ymax + rect->ymin)/2 - my;
113         y/= (float)((rect->ymax - rect->ymin)/2);
114
115         d = sqrt(x*x + y*y);
116         if (d < radius*M_SQRT1_2)       /* Inside sphere */
117                 z = sqrt(radius*radius - d*d);
118         else
119         {                       /* On hyperbola */
120                 t = radius / M_SQRT2;
121                 z = t*t / d;
122         }
123
124         vec[0]= x;
125         vec[1]= y;
126         vec[2]= -z;             /* yah yah! */
127 }
128
129
130 static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
131 {
132         ScrArea *sa= CTX_wm_area(C);
133         View3D *v3d= sa->spacedata.first;
134         ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
135
136         /* store data */
137         op->customdata= vod;
138         vod->ar= CTX_wm_region(C);
139         vod->v3d= v3d;
140         vod->dist0= v3d->dist;
141         QUATCOPY(vod->oldquat, v3d->viewquat);
142         vod->origx= vod->oldx= event->x;
143         vod->origy= vod->oldy= event->y;
144         vod->origkey= event->type;
145
146         calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
147
148         initgrabz(v3d, -v3d->ofs[0], -v3d->ofs[1], -v3d->ofs[2]);
149
150         vod->reverse= 1.0f;
151         if (v3d->persmat[2][1] < 0.0f)
152                 vod->reverse= -1.0f;
153
154 }
155
156 /* ************************** viewrotate **********************************/
157
158 static const float thres = 0.93f; //cos(20 deg);
159
160 #define COS45 0.70710678118654746
161 #define SIN45 COS45
162
163 static float snapquats[39][6] = {
164         /*{q0, q1, q3, q4, view, oposite_direction}*/
165 {COS45, -SIN45, 0.0, 0.0, 1, 0},  //front
166 {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back
167 {1.0, 0.0, 0.0, 0.0, 7, 0},       //top
168 {0.0, -1.0, 0.0, 0.0, 7, 1},      //bottom
169 {0.5, -0.5, -0.5, -0.5, 3, 0},    //left
170 {0.5, -0.5, 0.5, 0.5, 3, 1},      //right
171
172         /* some more 45 deg snaps */
173 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
174 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
175 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
176 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
177 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
178 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
179 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
180 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
181 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
182 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
183 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
184 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
185 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
186 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
187 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
188 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
189 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
190 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
191 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
192 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
193 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
194 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
195 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
196 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
197 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
198 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
199 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
200 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
201 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
202 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
203 {-COS45, 0.0, 0.0, SIN45, 0, 0},
204 {COS45, 0.0, 0.0, SIN45, 0, 0},
205 {0.0, 0.0, 0.0, 1.0, 0, 0}
206 };
207
208
209 static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl)
210 {
211         View3D *v3d= vod->v3d;
212         int use_sel= 0; /* XXX */
213
214         v3d->view= 0; /* need to reset everytime because of view snapping */
215
216         if (U.flag & USER_TRACKBALL) {
217                 float phi, si, q1[4], dvec[3], newvec[3];
218
219                 calctrackballvec(&vod->ar->winrct, x, y, newvec);
220
221                 VecSubf(dvec, newvec, vod->trackvec);
222
223                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
224                 si/= (2.0*TRACKBALLSIZE);
225
226                 Crossf(q1+1, vod->trackvec, newvec);
227                 Normalize(q1+1);
228
229                 /* Allow for rotation beyond the interval
230                         * [-pi, pi] */
231                 while (si > 1.0)
232                         si -= 2.0;
233
234                 /* This relation is used instead of
235                         * phi = asin(si) so that the angle
236                         * of rotation is linearly proportional
237                         * to the distance that the mouse is
238                         * dragged. */
239                 phi = si * M_PI / 2.0;
240
241                 si= sin(phi);
242                 q1[0]= cos(phi);
243                 q1[1]*= si;
244                 q1[2]*= si;
245                 q1[3]*= si;
246                 QuatMul(v3d->viewquat, q1, vod->oldquat);
247
248                 if (use_sel) {
249                         /* compute the post multiplication quat, to rotate the offset correctly */
250                         QUATCOPY(q1, vod->oldquat);
251                         QuatConj(q1);
252                         QuatMul(q1, q1, v3d->viewquat);
253
254                         QuatConj(q1); /* conj == inv for unit quat */
255                         VECCOPY(v3d->ofs, vod->ofs);
256                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
257                         QuatMulVecf(q1, v3d->ofs);
258                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
259                 }
260         }
261         else {
262                 /* New turntable view code by John Aughey */
263                 float si, phi, q1[4];
264                 float m[3][3];
265                 float m_inv[3][3];
266                 float xvec[3] = {1,0,0};
267                 /* Sensitivity will control how fast the viewport rotates.  0.0035 was
268                         obtained experimentally by looking at viewport rotation sensitivities
269                         on other modeling programs. */
270                 /* Perhaps this should be a configurable user parameter. */
271                 const float sensitivity = 0.0035;
272
273                 /* Get the 3x3 matrix and its inverse from the quaternion */
274                 QuatToMat3(v3d->viewquat, m);
275                 Mat3Inv(m_inv,m);
276
277                 /* Determine the direction of the x vector (for rotating up and down) */
278                 /* This can likely be compuated directly from the quaternion. */
279                 Mat3MulVecfl(m_inv,xvec);
280
281                 /* Perform the up/down rotation */
282                 phi = sensitivity * -(y - vod->oldy);
283                 si = sin(phi);
284                 q1[0] = cos(phi);
285                 q1[1] = si * xvec[0];
286                 q1[2] = si * xvec[1];
287                 q1[3] = si * xvec[2];
288                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
289
290                 if (use_sel) {
291                         QuatConj(q1); /* conj == inv for unit quat */
292                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
293                         QuatMulVecf(q1, v3d->ofs);
294                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
295                 }
296
297                 /* Perform the orbital rotation */
298                 phi = sensitivity * vod->reverse * (x - vod->oldx);
299                 q1[0] = cos(phi);
300                 q1[1] = q1[2] = 0.0;
301                 q1[3] = sin(phi);
302                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
303
304                 if (use_sel) {
305                         QuatConj(q1);
306                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
307                         QuatMulVecf(q1, v3d->ofs);
308                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
309                 }
310         }
311
312         /* check for view snap */
313         if (ctrl){
314                 int i;
315                 float viewmat[3][3];
316
317
318                 QuatToMat3(v3d->viewquat, viewmat);
319
320                 for (i = 0 ; i < 39; i++){
321                         float snapmat[3][3];
322                         float view = (int)snapquats[i][4];
323                         float oposite_dir = (int)snapquats[i][5];
324
325                         QuatToMat3(snapquats[i], snapmat);
326
327                         if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
328                                 (Inpf(snapmat[1], viewmat[1]) > thres) &&
329                                 (Inpf(snapmat[2], viewmat[2]) > thres)){
330
331                                 QUATCOPY(v3d->viewquat, snapquats[i]);
332
333                                 v3d->view = view;
334                                 if (view){
335                                         if (oposite_dir){
336                                                 v3d->flag2 |= V3D_OPP_DIRECTION_NAME;
337                                         }else{
338                                                 v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME;
339                                         }
340                                 }
341
342                                 break;
343                         }
344                 }
345         }
346         vod->oldx= x;
347         vod->oldy= y;
348
349         ED_region_tag_redraw(vod->ar);
350 }
351
352 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
353 {
354         ViewOpsData *vod= op->customdata;
355
356         /* execute the events */
357         switch(event->type) {
358                 case MOUSEMOVE:
359                         viewrotate_apply(vod, event->x, event->y, event->ctrl);
360                         break;
361
362                 default:
363                         if(event->type==vod->origkey && event->val==0) {
364
365                                 MEM_freeN(vod);
366                                 op->customdata= NULL;
367
368                                 return OPERATOR_FINISHED;
369                         }
370         }
371
372         return OPERATOR_RUNNING_MODAL;
373 }
374
375 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
376 {
377         ViewOpsData *vod;
378
379         /* makes op->customdata */
380         viewops_data(C, op, event);
381         vod= op->customdata;
382
383         /* switch from camera view when: */
384         if(vod->v3d->persp != V3D_PERSP) {
385
386                 if (U.uiflag & USER_AUTOPERSP)
387                         vod->v3d->persp= V3D_PERSP;
388                 else if(vod->v3d->persp==V3D_CAMOB)
389                         vod->v3d->persp= V3D_PERSP;
390                 ED_region_tag_redraw(vod->ar);
391         }
392
393         /* add temp handler */
394         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
395
396         return OPERATOR_RUNNING_MODAL;
397 }
398
399
400 void ED_VIEW3D_OT_viewrotate(wmOperatorType *ot)
401 {
402
403         /* identifiers */
404         ot->name= "Rotate view";
405         ot->idname= "ED_VIEW3D_OT_viewrotate";
406
407         /* api callbacks */
408         ot->invoke= viewrotate_invoke;
409         ot->modal= viewrotate_modal;
410         ot->poll= ED_operator_areaactive;
411 }
412
413 /* ************************ viewmove ******************************** */
414
415 static void viewmove_apply(ViewOpsData *vod, int x, int y)
416 {
417         if(vod->v3d->persp==V3D_CAMOB) {
418                 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
419
420                 vod->v3d->camdx += (vod->oldx - x)/(max);
421                 vod->v3d->camdy += (vod->oldy - y)/(max);
422                 CLAMP(vod->v3d->camdx, -1.0f, 1.0f);
423                 CLAMP(vod->v3d->camdy, -1.0f, 1.0f);
424 // XXX          preview3d_event= 0;
425         }
426         else {
427                 float dvec[3];
428
429                 window_to_3d(vod->ar, vod->v3d, dvec, x-vod->oldx, y-vod->oldy);
430                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, dvec);
431         }
432
433         vod->oldx= x;
434         vod->oldy= y;
435
436         ED_region_tag_redraw(vod->ar);
437 }
438
439
440 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
441 {
442         ViewOpsData *vod= op->customdata;
443
444         /* execute the events */
445         switch(event->type) {
446                 case MOUSEMOVE:
447                         viewmove_apply(vod, event->x, event->y);
448                         break;
449
450                 default:
451                         if(event->type==vod->origkey && event->val==0) {
452
453                                 MEM_freeN(vod);
454                                 op->customdata= NULL;
455
456                                 return OPERATOR_FINISHED;
457                         }
458         }
459
460         return OPERATOR_RUNNING_MODAL;
461 }
462
463 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
464 {
465         /* makes op->customdata */
466         viewops_data(C, op, event);
467
468         /* add temp handler */
469         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
470
471         return OPERATOR_RUNNING_MODAL;
472 }
473
474
475 void ED_VIEW3D_OT_viewmove(wmOperatorType *ot)
476 {
477
478         /* identifiers */
479         ot->name= "Rotate view";
480         ot->idname= "ED_VIEW3D_OT_viewmove";
481
482         /* api callbacks */
483         ot->invoke= viewmove_invoke;
484         ot->modal= viewmove_modal;
485         ot->poll= ED_operator_areaactive;
486 }
487
488 /* ************************ viewzoom ******************************** */
489
490 static void view_zoom_mouseloc(ARegion *ar, View3D *v3d, float dfac, int mx, int my)
491 {
492         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
493                 float dvec[3];
494                 float tvec[3];
495                 float tpos[3];
496                 float new_dist;
497                 short vb[2], mouseloc[2];
498
499                 mouseloc[0]= mx - ar->winrct.xmin;
500                 mouseloc[1]= my - ar->winrct.ymin;
501
502                 /* find the current window width and height */
503                 vb[0] = ar->winx;
504                 vb[1] = ar->winy;
505
506                 tpos[0] = -v3d->ofs[0];
507                 tpos[1] = -v3d->ofs[1];
508                 tpos[2] = -v3d->ofs[2];
509
510                 /* Project cursor position into 3D space */
511                 initgrabz(v3d, tpos[0], tpos[1], tpos[2]);
512                 window_to_3d(ar, v3d, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
513
514                 /* Calculate view target position for dolly */
515                 tvec[0] = -(tpos[0] + dvec[0]);
516                 tvec[1] = -(tpos[1] + dvec[1]);
517                 tvec[2] = -(tpos[2] + dvec[2]);
518
519                 /* Offset to target position and dolly */
520                 new_dist = v3d->dist * dfac;
521
522                 VECCOPY(v3d->ofs, tvec);
523                 v3d->dist = new_dist;
524
525                 /* Calculate final offset */
526                 dvec[0] = tvec[0] + dvec[0] * dfac;
527                 dvec[1] = tvec[1] + dvec[1] * dfac;
528                 dvec[2] = tvec[2] + dvec[2] * dfac;
529
530                 VECCOPY(v3d->ofs, dvec);
531         } else {
532                 v3d->dist *= dfac;
533         }
534 }
535
536
537 static void viewzoom_apply(ViewOpsData *vod, int x, int y)
538 {
539         float zfac=1.0;
540
541         if(U.viewzoom==USER_ZOOM_CONT) {
542                 // oldstyle zoom
543                 zfac = 1.0+(float)(vod->origx - x + vod->origy - y)/1000.0;
544         }
545         else if(U.viewzoom==USER_ZOOM_SCALE) {
546                 int ctr[2], len1, len2;
547                 // method which zooms based on how far you move the mouse
548
549                 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
550                 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
551
552                 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
553                 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
554
555                 zfac = vod->dist0 * ((float)len2/len1) / vod->v3d->dist;
556         }
557         else {  /* USER_ZOOM_DOLLY */
558                 float len1 = (vod->ar->winrct.ymax - y) + 5;
559                 float len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
560                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->v3d->dist;
561         }
562
563         if(zfac != 1.0 && zfac*vod->v3d->dist > 0.001*vod->v3d->grid &&
564                                 zfac*vod->v3d->dist < 10.0*vod->v3d->far)
565                 view_zoom_mouseloc(vod->ar, vod->v3d, zfac, vod->oldx, vod->oldy);
566
567
568         if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->v3d->persp==V3D_PERSP)) {
569                 float upvec[3], mat[3][3];
570
571                 /* Secret apricot feature, translate the view when in continues mode */
572                 upvec[0] = upvec[1] = 0.0f;
573                 upvec[2] = (vod->dist0 - vod->v3d->dist) * vod->v3d->grid;
574                 vod->v3d->dist = vod->dist0;
575                 Mat3CpyMat4(mat, vod->v3d->viewinv);
576                 Mat3MulVecfl(mat, upvec);
577                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, upvec);
578         } else {
579                 /* these limits are in toets.c too */
580                 if(vod->v3d->dist<0.001*vod->v3d->grid) vod->v3d->dist= 0.001*vod->v3d->grid;
581                 if(vod->v3d->dist>10.0*vod->v3d->far) vod->v3d->dist=10.0*vod->v3d->far;
582         }
583
584 // XXX  if(vod->v3d->persp==V3D_ORTHO || vod->v3d->persp==V3D_CAMOB) preview3d_event= 0;
585
586         ED_region_tag_redraw(vod->ar);
587 }
588
589
590 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
591 {
592         ViewOpsData *vod= op->customdata;
593
594         /* execute the events */
595         switch(event->type) {
596                 case MOUSEMOVE:
597                         viewzoom_apply(vod, event->x, event->y);
598                         break;
599
600                 default:
601                         if(event->type==vod->origkey && event->val==0) {
602
603                                 MEM_freeN(vod);
604                                 op->customdata= NULL;
605
606                                 return OPERATOR_FINISHED;
607                         }
608         }
609
610         return OPERATOR_RUNNING_MODAL;
611 }
612
613 static int viewzoom_exec(bContext *C, wmOperator *op)
614 {
615         ScrArea *sa= CTX_wm_area(C);
616         View3D *v3d= sa->spacedata.first;
617         int delta= RNA_int_get(op->ptr, "delta");
618
619         if(delta < 0) {
620                 /* this min and max is also in viewmove() */
621                 if(v3d->persp==V3D_CAMOB) {
622                         v3d->camzoom-= 10;
623                         if(v3d->camzoom<-30) v3d->camzoom= -30;
624                 }
625                 else if(v3d->dist<10.0*v3d->far) v3d->dist*=1.2f;
626         }
627         else {
628                 if(v3d->persp==V3D_CAMOB) {
629                         v3d->camzoom+= 10;
630                         if(v3d->camzoom>300) v3d->camzoom= 300;
631                 }
632                 else if(v3d->dist> 0.001*v3d->grid) v3d->dist*=.83333f;
633         }
634
635         ED_region_tag_redraw(CTX_wm_region(C));
636
637         return OPERATOR_FINISHED;
638 }
639
640 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
641 {
642         int delta= RNA_int_get(op->ptr, "delta");
643
644         if(delta) {
645                 viewzoom_exec(C, op);
646         }
647         else {
648                 /* makes op->customdata */
649                 viewops_data(C, op, event);
650
651                 /* add temp handler */
652                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
653
654                 return OPERATOR_RUNNING_MODAL;
655         }
656         return OPERATOR_FINISHED;
657 }
658
659
660 void ED_VIEW3D_OT_viewzoom(wmOperatorType *ot)
661 {
662
663         /* identifiers */
664         ot->name= "Rotate view";
665         ot->idname= "ED_VIEW3D_OT_viewzoom";
666
667         /* api callbacks */
668         ot->invoke= viewzoom_invoke;
669         ot->exec= viewzoom_exec;
670         ot->modal= viewzoom_modal;
671         ot->poll= ED_operator_areaactive;
672
673         RNA_def_property(ot->srna, "delta", PROP_INT, PROP_NONE);
674 }
675
676 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
677 {
678         ScrArea *sa= CTX_wm_area(C);
679         ARegion *ar= CTX_wm_region(C);
680         View3D *v3d= sa->spacedata.first;
681         Scene *scene= CTX_data_scene(C);
682         Base *base;
683
684         int center= RNA_boolean_get(op->ptr, "center");
685
686         float size, min[3], max[3], afm[3];
687         int ok= 1, onedone=0;
688
689         if(center) {
690                 min[0]= min[1]= min[2]= 0.0f;
691                 max[0]= max[1]= max[2]= 0.0f;
692         }
693         else {
694                 INIT_MINMAX(min, max);
695         }
696
697         for(base= scene->base.first; base; base= base->next) {
698                 if(base->lay & v3d->lay) {
699                         onedone= 1;
700                         minmax_object(base->object, min, max);
701                 }
702         }
703         if(!onedone) return OPERATOR_FINISHED; /* TODO - should this be cancel? */
704
705         afm[0]= (max[0]-min[0]);
706         afm[1]= (max[1]-min[1]);
707         afm[2]= (max[2]-min[2]);
708         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
709         if(size==0.0) ok= 0;
710
711         if(ok) {
712                 float new_dist;
713                 float new_ofs[3];
714
715                 new_dist = size;
716                 new_ofs[0]= -(min[0]+max[0])/2.0f;
717                 new_ofs[1]= -(min[1]+max[1])/2.0f;
718                 new_ofs[2]= -(min[2]+max[2])/2.0f;
719
720                 // correction for window aspect ratio
721                 if(ar->winy>2 && ar->winx>2) {
722                         size= (float)ar->winx/(float)ar->winy;
723                         if(size<1.0) size= 1.0f/size;
724                         new_dist*= size;
725                 }
726
727                 if (v3d->persp==V3D_CAMOB && v3d->camera) {
728                         /* switch out of camera view */
729                         float orig_lens= v3d->lens;
730
731                         v3d->persp= V3D_PERSP;
732                         v3d->dist= 0.0;
733                         view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
734                         smooth_view(v3d, new_ofs, NULL, &new_dist, &orig_lens); /* TODO - this dosnt work yet */
735
736                 } else {
737                         if(v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP;
738                         smooth_view(v3d, new_ofs, NULL, &new_dist, NULL); /* TODO - this dosnt work yet */
739                 }
740         }
741 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
742
743         ED_region_tag_redraw(ar);
744
745         return OPERATOR_FINISHED;
746 }
747
748 void ED_VIEW3D_OT_viewhome(wmOperatorType *ot)
749 {
750
751         /* identifiers */
752         ot->name= "View home";
753         ot->idname= "ED_VIEW3D_OT_viewhome";
754
755         /* api callbacks */
756         ot->exec= viewhome_exec;
757         ot->poll= ED_operator_areaactive;
758
759         RNA_def_property(ot->srna, "center", PROP_BOOLEAN, PROP_NONE);
760 }
761
762 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
763 {
764         ScrArea *sa= CTX_wm_area(C);
765         ARegion *ar= CTX_wm_region(C);
766         View3D *v3d= sa->spacedata.first;
767         Scene *scene= CTX_data_scene(C);
768         Object *ob= OBACT;
769         float size, min[3], max[3], afm[3];
770         int ok=0;
771
772         /* SMOOTHVIEW */
773         float new_ofs[3];
774         float new_dist;
775
776         INIT_MINMAX(min, max);
777
778         if (G.f & G_WEIGHTPAINT) {
779                 /* hardcoded exception, we look for the one selected armature */
780                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
781                 Base *base;
782                 for(base=scene->base.first; base; base= base->next) {
783                         if(TESTBASELIB(v3d, base)) {
784                                 if(base->object->type==OB_ARMATURE)
785                                         if(base->object->flag & OB_POSEMODE)
786                                                 break;
787                         }
788                 }
789                 if(base)
790                         ob= base->object;
791         }
792
793
794         if(G.obedit) {
795 // XXX          ok = minmax_verts(min, max);    /* only selected */
796         }
797         else if(ob && (ob->flag & OB_POSEMODE)) {
798                 if(ob->pose) {
799                         bArmature *arm= ob->data;
800                         bPoseChannel *pchan;
801                         float vec[3];
802
803                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
804                                 if(pchan->bone->flag & BONE_SELECTED) {
805                                         if(pchan->bone->layer & arm->layer) {
806                                                 ok= 1;
807                                                 VECCOPY(vec, pchan->pose_head);
808                                                 Mat4MulVecfl(ob->obmat, vec);
809                                                 DO_MINMAX(vec, min, max);
810                                                 VECCOPY(vec, pchan->pose_tail);
811                                                 Mat4MulVecfl(ob->obmat, vec);
812                                                 DO_MINMAX(vec, min, max);
813                                         }
814                                 }
815                         }
816                 }
817         }
818         else if (FACESEL_PAINT_TEST) {
819 // XXX          ok= minmax_tface(min, max);
820         }
821         else if (G.f & G_PARTICLEEDIT) {
822 // XXX          ok= PE_minmax(min, max);
823         }
824         else {
825                 Base *base= FIRSTBASE;
826                 while(base) {
827                         if(TESTBASE(v3d, base))  {
828                                 minmax_object(base->object, min, max);
829                                 /* account for duplis */
830                                 minmax_object_duplis(base->object, min, max);
831
832                                 ok= 1;
833                         }
834                         base= base->next;
835                 }
836         }
837
838         if(ok==0) return OPERATOR_FINISHED;
839
840         afm[0]= (max[0]-min[0]);
841         afm[1]= (max[1]-min[1]);
842         afm[2]= (max[2]-min[2]);
843         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
844
845         if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
846
847         new_ofs[0]= -(min[0]+max[0])/2.0f;
848         new_ofs[1]= -(min[1]+max[1])/2.0f;
849         new_ofs[2]= -(min[2]+max[2])/2.0f;
850
851         new_dist = size;
852
853         /* correction for window aspect ratio */
854         if(ar->winy>2 && ar->winx>2) {
855                 size= (float)ar->winx/(float)ar->winy;
856                 if(size<1.0f) size= 1.0f/size;
857                 new_dist*= size;
858         }
859
860         v3d->cursor[0]= -new_ofs[0];
861         v3d->cursor[1]= -new_ofs[1];
862         v3d->cursor[2]= -new_ofs[2];
863
864         if (v3d->persp==V3D_CAMOB && v3d->camera) {
865                 float orig_lens= v3d->lens;
866
867                 v3d->persp=V3D_PERSP;
868                 v3d->dist= 0.0f;
869                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
870                 smooth_view(v3d, new_ofs, NULL, &new_dist, &orig_lens);
871         } else {
872                 if(v3d->persp==V3D_CAMOB)
873                         v3d->persp= V3D_PERSP;
874
875                 smooth_view(v3d, new_ofs, NULL, &new_dist, NULL);
876         }
877
878 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
879
880         ED_region_tag_redraw(ar);
881
882         return OPERATOR_FINISHED;
883 }
884 void ED_VIEW3D_OT_viewcenter(wmOperatorType *ot)
885 {
886
887         /* identifiers */
888         ot->name= "View center";
889         ot->idname= "ED_VIEW3D_OT_viewcenter";
890
891         /* api callbacks */
892         ot->exec= viewcenter_exec;
893         ot->poll= ED_operator_areaactive;
894 }
895
896 /* ********************* Changing view operator ****************** */
897
898 static EnumPropertyItem prop_view_items[] = {
899         {V3D_VIEW_FRONT, "FRONT", "Front", "View From the Front"},
900         {V3D_VIEW_BACK, "BACK", "Back", "View From the Back"},
901         {V3D_VIEW_LEFT, "LEFT", "Left", "View From the Left"},
902         {V3D_VIEW_RIGHT, "RIGHT", "Right", "View From the Right"},
903         {V3D_VIEW_TOP, "TOP", "Top", "View From the Top"},
904         {V3D_VIEW_BOTTOM, "BOTTOM", "Bottom", "View From the Bottom"},
905         {V3D_VIEW_PERSPORTHO, "PERSPORTHO", "Persp-Ortho", "Switch between Perspecive and Orthographic View"},
906         {V3D_VIEW_CAMERA, "CAMERA", "Camera", "View From the active amera"},
907         {V3D_VIEW_STEPLEFT, "STEPLEFT", "Step Left", "Step the view around to the Left"},
908         {V3D_VIEW_STEPRIGHT, "STEPRIGHT", "Step Right", "Step the view around to the Right"},
909         {V3D_VIEW_STEPUP, "STEPUP", "Step Up", "Step the view Up"},
910         {V3D_VIEW_STEPDOWN, "STEPDOWN", "Step Down", "Step the view Down"},
911         {V3D_VIEW_PANLEFT, "PANLEFT", "Pan Left", "Pan the view to the Left"},
912         {V3D_VIEW_PANRIGHT, "PANRIGHT", "Pan Right", "Pan the view to the Right"},
913         {V3D_VIEW_PANUP, "PANUP", "Pan Up", "Pan the view Up"},
914         {V3D_VIEW_PANDOWN, "PANDOWN", "Pan Down", "Pan the view Down"},
915         {0, NULL, NULL, NULL}};
916
917 static void axis_set_view(View3D *v3d, float q1, float q2, float q3, float q4, short view, int perspo)
918 {
919         float new_quat[4];
920         new_quat[0]= q1; new_quat[1]= q2;
921         new_quat[2]= q3; new_quat[3]= q4;
922         v3d->view=0;
923
924
925         if (v3d->persp==V3D_CAMOB && v3d->camera) {
926                 /* Is this switching from a camera view ? */
927                 float orig_ofs[3];
928                 float orig_lens= v3d->lens;
929                 VECCOPY(orig_ofs, v3d->ofs);
930                 view_settings_from_ob(v3d->camera, v3d->ofs, v3d->viewquat, &v3d->dist, &v3d->lens);
931
932
933                 if (U.uiflag & USER_AUTOPERSP) v3d->persp= V3D_ORTHO;
934                 else if(v3d->persp==V3D_CAMOB) v3d->persp= perspo;
935
936                 smooth_view(v3d, orig_ofs, new_quat, NULL, &orig_lens);
937         } else {
938
939                 if (U.uiflag & USER_AUTOPERSP) v3d->persp= V3D_ORTHO;
940                 else if(v3d->persp==V3D_CAMOB) v3d->persp= perspo;
941
942                 smooth_view(v3d, NULL, new_quat, NULL, NULL);
943         }
944         v3d->view= view;
945 }
946
947 static int viewnumpad_exec(bContext *C, wmOperator *op)
948 {
949         ScrArea *sa= CTX_wm_area(C);
950         ARegion *ar= CTX_wm_region(C);
951         View3D *v3d= sa->spacedata.first;
952         Scene *scene= CTX_data_scene(C);
953         Object *act_cam_orig=NULL;
954
955         float phi, si, q1[4], vec[3];
956         static int perspo=V3D_PERSP;
957         float orig_ofs[3];
958         int viewnum;
959
960         viewnum = RNA_enum_get(op->ptr, "viewnum");
961
962         /* Use this to test if we started out with a camera */
963
964         if (v3d->persp == V3D_CAMOB)
965                 act_cam_orig = v3d->camera;
966
967         /* Indicate that this view is inverted,
968          * but only if it actually _was_ inverted (jobbe) */
969         if (viewnum == V3D_VIEW_BOTTOM || viewnum == V3D_VIEW_BACK || viewnum == V3D_VIEW_LEFT)
970                 v3d->flag2 |= V3D_OPP_DIRECTION_NAME;
971         else if (viewnum != V3D_VIEW_PERSPORTHO)
972                         v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME;
973
974         switch (viewnum) {
975                 case V3D_VIEW_BOTTOM :
976                         axis_set_view(v3d,0.0, -1.0, 0.0, 0.0, 7, perspo);
977                         break;
978
979                 case V3D_VIEW_BACK:
980                         axis_set_view(v3d,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), 1, perspo);
981                         break;
982
983                 case V3D_VIEW_LEFT:
984                         axis_set_view(v3d,0.5, -0.5, 0.5, 0.5, 3, perspo);
985                         break;
986
987                 case V3D_VIEW_TOP:
988                         axis_set_view(v3d,1.0, 0.0, 0.0, 0.0, 7, perspo);
989                         break;
990
991                 case V3D_VIEW_FRONT:
992                         axis_set_view(v3d,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, 1, perspo);
993                         break;
994
995                 case V3D_VIEW_RIGHT:
996                         axis_set_view(v3d,0.5, -0.5, -0.5, -0.5, 3, perspo);
997                         break;
998
999                 case V3D_VIEW_PERSPORTHO:
1000
1001                         if (U.smooth_viewtx) {
1002                                 if(v3d->persp==V3D_PERSP) { v3d->persp=V3D_ORTHO;
1003                                 } else if (act_cam_orig) {
1004                                         /* were from a camera view */
1005                                         float orig_dist= v3d->dist;
1006                                         float orig_lens= v3d->lens;
1007                                         VECCOPY(orig_ofs, v3d->ofs);
1008                                         v3d->persp=V3D_PERSP;
1009                                         v3d->dist= 0.0;
1010
1011                                         view_settings_from_ob(act_cam_orig, v3d->ofs, NULL, NULL, &v3d->lens);
1012                                         smooth_view(v3d, orig_ofs, NULL, &orig_dist, &orig_lens);
1013                                 } else {
1014                                         v3d->persp=V3D_PERSP;
1015                                 }
1016                         } else {
1017                                 if(v3d->persp==V3D_PERSP) v3d->persp=V3D_ORTHO;
1018                                 else v3d->persp=V3D_PERSP;
1019                         }
1020                         break;
1021
1022                 case V3D_VIEW_CAMERA:
1023                         /* lastview -  */
1024
1025                         if(v3d->persp != V3D_CAMOB) {
1026                                 /* store settings of current view before allowing overwriting with camera view */
1027                                 QUATCOPY(v3d->lviewquat, v3d->viewquat);
1028                                 v3d->lview= v3d->view;
1029                                 v3d->lpersp= v3d->persp;
1030                         }
1031                         else{
1032                                 /* return to settings of last view */
1033
1034                                 axis_set_view(v3d,v3d->lviewquat[0], v3d->lviewquat[1], v3d->lviewquat[2], v3d->lviewquat[3], v3d->lview, v3d->lpersp);
1035                         }
1036 #if 0
1037                         if(G.qual==LR_ALTKEY) {
1038                                 if(oldcamera && is_an_active_object(oldcamera)) {
1039                                         v3d->camera= oldcamera;
1040                                 }
1041                                 handle_view3d_lock();
1042                         }
1043 #endif
1044
1045                         if(BASACT) {
1046                         /* check both G.vd as G.scene cameras */
1047                         if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1048                                 v3d->camera= OBACT;
1049                                 /*handle_view3d_lock();*/
1050                                 }
1051                         }
1052
1053                         if(v3d->camera==0) {
1054                                 v3d->camera= scene_find_camera(scene);
1055                                 /*handle_view3d_lock();*/
1056                         }
1057                         if(v3d->camera && (v3d->camera != act_cam_orig)) {
1058                                 v3d->persp= V3D_CAMOB;
1059                                 v3d->view= 0;
1060
1061                         } else if (U.smooth_viewtx) {
1062                                 /* move 3d view to camera view */
1063                                 float orig_lens = v3d->lens;
1064                                 VECCOPY(orig_ofs, v3d->ofs);
1065
1066                                 if (act_cam_orig)
1067                                         view_settings_from_ob(act_cam_orig, v3d->ofs, v3d->viewquat, &v3d->dist, &v3d->lens);
1068
1069                                 smooth_view_to_camera(v3d);
1070                                 VECCOPY(v3d->ofs, orig_ofs);
1071                                 v3d->lens = orig_lens;
1072                         }
1073                         break;
1074
1075                 case V3D_VIEW_STEPLEFT:
1076                 case V3D_VIEW_STEPRIGHT:
1077                 case V3D_VIEW_STEPUP:
1078                 case V3D_VIEW_STEPDOWN:
1079
1080                         if(v3d->persp != V3D_CAMOB) {
1081                                 if(viewnum == V3D_VIEW_STEPLEFT || viewnum == V3D_VIEW_STEPRIGHT) {
1082                                         /* z-axis */
1083                                         phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1084                                         if(viewnum == V3D_VIEW_STEPRIGHT) phi= -phi;
1085                                         si= (float)sin(phi);
1086                                         q1[0]= (float)cos(phi);
1087                                         q1[1]= q1[2]= 0.0;
1088                                         q1[3]= si;
1089                                         QuatMul(v3d->viewquat, v3d->viewquat, q1);
1090                                         v3d->view= 0;
1091                                 }
1092                                 if(viewnum == V3D_VIEW_STEPDOWN || viewnum == V3D_VIEW_STEPUP) {
1093                                         /* horizontal axis */
1094                                         VECCOPY(q1+1, v3d->viewinv[0]);
1095
1096                                         Normalize(q1+1);
1097                                         phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1098                                         if(viewnum == V3D_VIEW_STEPDOWN) phi= -phi;
1099                                         si= (float)sin(phi);
1100                                         q1[0]= (float)cos(phi);
1101                                         q1[1]*= si;
1102                                         q1[2]*= si;
1103                                         q1[3]*= si;
1104                                         QuatMul(v3d->viewquat, v3d->viewquat, q1);
1105                                         v3d->view= 0;
1106                                 }
1107                         }
1108                         break;
1109
1110                 case V3D_VIEW_PANRIGHT:
1111                 case V3D_VIEW_PANLEFT:
1112                 case V3D_VIEW_PANUP:
1113                 case V3D_VIEW_PANDOWN:
1114
1115                         initgrabz(v3d, 0.0, 0.0, 0.0);
1116
1117                         if(viewnum == V3D_VIEW_PANRIGHT) window_to_3d(ar, v3d, vec, -32, 0);
1118                         else if(viewnum == V3D_VIEW_PANLEFT) window_to_3d(ar, v3d, vec, 32, 0);
1119                         else if(viewnum == V3D_VIEW_PANUP) window_to_3d(ar, v3d, vec, 0, -25);
1120                         else if(viewnum == V3D_VIEW_PANDOWN) window_to_3d(ar, v3d, vec, 0, 25);
1121                         v3d->ofs[0]+= vec[0];
1122                         v3d->ofs[1]+= vec[1];
1123                         v3d->ofs[2]+= vec[2];
1124
1125                         break;
1126
1127                 default :
1128                         break;
1129         }
1130
1131         if(v3d->persp != V3D_CAMOB) perspo= v3d->persp;
1132
1133
1134         WM_event_add_notifier(C, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1135
1136         return OPERATOR_FINISHED;
1137 }
1138
1139
1140 void ED_VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1141 {
1142
1143         PropertyRNA *prop;
1144
1145         /* identifiers */
1146         ot->name= "View numpad";
1147         ot->idname= "ED_VIEW3D_OT_viewnumpad";
1148
1149         /* api callbacks */
1150         ot->exec= viewnumpad_exec;
1151         ot->poll= ED_operator_areaactive;
1152         ot->flag= OPTYPE_REGISTER;
1153
1154         prop = RNA_def_property(ot->srna, "viewnum", PROP_ENUM, PROP_NONE);
1155         RNA_def_property_enum_items(prop, prop_view_items);
1156 }
1157
1158 /* ********************* set clipping operator ****************** */
1159
1160 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1161 {
1162         ScrArea *sa= CTX_wm_area(C);
1163         View3D *v3d= sa->spacedata.first;
1164         rcti rect;
1165         double mvmatrix[16];
1166         double projmatrix[16];
1167         double xs, ys, p[3];
1168         GLint viewport[4];
1169         short val;
1170
1171         rect.xmin= RNA_int_get(op->ptr, "xmin");
1172         rect.ymin= RNA_int_get(op->ptr, "ymin");
1173         rect.xmax= RNA_int_get(op->ptr, "xmax");
1174         rect.ymax= RNA_int_get(op->ptr, "ymax");
1175
1176         v3d->flag |= V3D_CLIPPING;
1177         v3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1178
1179         /* note; otherwise opengl won't work */
1180         view3d_operator_needs_opengl(C);
1181
1182         /* Get the matrices needed for gluUnProject */
1183         glGetIntegerv(GL_VIEWPORT, viewport);
1184         glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
1185         glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
1186
1187         /* near zero floating point values can give issues with gluUnProject
1188                 in side view on some implementations */
1189         if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
1190         if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
1191
1192         /* Set up viewport so that gluUnProject will give correct values */
1193         viewport[0] = 0;
1194         viewport[1] = 0;
1195
1196         /* four clipping planes and bounding volume */
1197         /* first do the bounding volume */
1198         for(val=0; val<4; val++) {
1199
1200                 xs= (val==0||val==3)?rect.xmin:rect.xmax;
1201                 ys= (val==0||val==1)?rect.ymin:rect.ymax;
1202
1203                 gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1204                 VECCOPY(v3d->clipbb->vec[val], p);
1205
1206                 gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1207                 VECCOPY(v3d->clipbb->vec[4+val], p);
1208         }
1209
1210         /* then plane equations */
1211         for(val=0; val<4; val++) {
1212
1213                 CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
1214                                           v3d->clip[val]);
1215
1216                 v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0]
1217                         - v3d->clip[val][1]*v3d->clipbb->vec[val][1]
1218                         - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
1219         }
1220         return OPERATOR_FINISHED;
1221 }
1222
1223 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
1224 {
1225         ScrArea *sa= CTX_wm_area(C);
1226         View3D *v3d= sa->spacedata.first;
1227
1228         if(v3d->flag & V3D_CLIPPING) {
1229                 v3d->flag &= ~V3D_CLIPPING;
1230                 ED_area_tag_redraw(sa);
1231                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
1232                 v3d->clipbb= NULL;
1233                 return OPERATOR_FINISHED;
1234         }
1235         else {
1236                 return WM_border_select_invoke(C, op, event);
1237         }
1238 }
1239
1240 /* toggles */
1241 void ED_VIEW3D_OT_clipping(wmOperatorType *ot)
1242 {
1243
1244         /* identifiers */
1245         ot->name= "Border Select";
1246         ot->idname= "ED_VIEW3D_OT_clipping";
1247
1248         /* api callbacks */
1249         ot->invoke= view3d_clipping_invoke;
1250         ot->exec= view3d_clipping_exec;
1251         ot->modal= WM_border_select_modal;
1252
1253         ot->poll= ED_operator_areaactive;
1254
1255         /* rna */
1256         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1257         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1258         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1259         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1260 }
1261
1262 /* ********************************************************* */
1263
1264 void set_render_border(Scene *scene, ARegion *ar, View3D *v3d)
1265 {
1266         rcti rect;
1267         short val;
1268
1269         val= 0; // XXX get_border(&rect, 3);
1270         if(val) {
1271                 rctf vb;
1272
1273                 calc_viewborder(scene, ar, v3d, &vb);
1274
1275                 scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1276                 scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1277                 scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1278                 scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1279
1280                 CLAMP(scene->r.border.xmin, 0.0, 1.0);
1281                 CLAMP(scene->r.border.ymin, 0.0, 1.0);
1282                 CLAMP(scene->r.border.xmax, 0.0, 1.0);
1283                 CLAMP(scene->r.border.ymax, 0.0, 1.0);
1284
1285                 /* drawing a border surrounding the entire camera view switches off border rendering
1286                         * or the border covers no pixels */
1287                 if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1288                          scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1289                         (scene->r.border.xmin == scene->r.border.xmax ||
1290                          scene->r.border.ymin == scene->r.border.ymax ))
1291                 {
1292                         scene->r.mode &= ~R_BORDER;
1293                 } else {
1294                         scene->r.mode |= R_BORDER;
1295                 }
1296         }
1297 }
1298
1299 void view3d_border_zoom(Scene *scene, ARegion *ar, View3D *v3d)
1300 {
1301
1302         /* Zooms in on a border drawn by the user */
1303         rcti rect;
1304         short val;
1305         float dvec[3], vb[2], xscale, yscale, scale;
1306
1307
1308         /* SMOOTHVIEW */
1309         float new_dist;
1310         float new_ofs[3];
1311
1312         /* ZBuffer depth vars */
1313         bglMats mats;
1314         float depth, depth_close= MAXFLOAT;
1315         int had_depth = 0;
1316         double cent[2],  p[3];
1317         int xs, ys;
1318
1319         /* Get the border input */
1320         val = 0; // XXX get_border(&rect, 3);
1321         if(!val) return;
1322
1323         /* Get Z Depths, needed for perspective, nice for ortho */
1324         bgl_get_mats(&mats);
1325         draw_depth(scene, ar, v3d, NULL);
1326
1327         /* force updating */
1328         if (v3d->depths) {
1329                 had_depth = 1;
1330                 v3d->depths->damaged = 1;
1331         }
1332
1333         view3d_update_depths(ar, v3d);
1334
1335         /* Constrain rect to depth bounds */
1336         if (rect.xmin < 0) rect.xmin = 0;
1337         if (rect.ymin < 0) rect.ymin = 0;
1338         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1339         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;
1340
1341         /* Find the closest Z pixel */
1342         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1343                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1344                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1345                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1346                                 if (depth_close > depth) {
1347                                         depth_close = depth;
1348                                 }
1349                         }
1350                 }
1351         }
1352
1353         if (had_depth==0) {
1354                 MEM_freeN(v3d->depths->depths);
1355                 v3d->depths->depths = NULL;
1356         }
1357         v3d->depths->damaged = 1;
1358
1359         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1360         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1361
1362         if (v3d->persp==V3D_PERSP) {
1363                 double p_corner[3];
1364
1365                 /* no depths to use, we cant do anything! */
1366                 if (depth_close==MAXFLOAT)
1367                         return;
1368
1369                 /* convert border to 3d coordinates */
1370                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1371                         (       !gluUnProject((double)rect.xmin, (double)rect.ymin, depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p_corner[0], &p_corner[1], &p_corner[2])))
1372                         return;
1373
1374                 dvec[0] = p[0]-p_corner[0];
1375                 dvec[1] = p[1]-p_corner[1];
1376                 dvec[2] = p[2]-p_corner[2];
1377
1378                 new_dist = VecLength(dvec);
1379                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1380
1381                 new_ofs[0] = -p[0];
1382                 new_ofs[1] = -p[1];
1383                 new_ofs[2] = -p[2];
1384
1385         } else { /* othographic */
1386                 /* find the current window width and height */
1387                 vb[0] = ar->winx;
1388                 vb[1] = ar->winy;
1389
1390                 new_dist = v3d->dist;
1391
1392                 /* convert the drawn rectangle into 3d space */
1393                 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1394                         new_ofs[0] = -p[0];
1395                         new_ofs[1] = -p[1];
1396                         new_ofs[2] = -p[2];
1397                 } else {
1398                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1399                         new_ofs[0] = v3d->ofs[0];
1400                         new_ofs[1] = v3d->ofs[1];
1401                         new_ofs[2] = v3d->ofs[2];
1402
1403                         initgrabz(v3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1404
1405                         window_to_3d(ar, v3d, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1406                         /* center the view to the center of the rectangle */
1407                         VecSubf(new_ofs, new_ofs, dvec);
1408                 }
1409
1410                 /* work out the ratios, so that everything selected fits when we zoom */
1411                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1412                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1413                 scale = (xscale >= yscale)?xscale:yscale;
1414
1415                 /* zoom in as required, or as far as we can go */
1416                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1417         }
1418
1419         smooth_view(v3d, new_ofs, NULL, &new_dist, NULL);
1420 }
1421
1422
1423
1424 /* ************************* below the line! *********************** */
1425
1426
1427 /* XXX todo Zooms in on a border drawn by the user */
1428 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
1429 {
1430         rcti rect;
1431         /* ZBuffer depth vars */
1432         bglMats mats;
1433         float depth, depth_close= MAXFLOAT;
1434         int had_depth = 0;
1435         double cent[2],  p[3];
1436         int xs, ys;
1437
1438         // XXX          getmouseco_areawin(mval);
1439
1440         // XXX  persp(PERSP_VIEW);
1441
1442         rect.xmax = mval[0] + 4;
1443         rect.ymax = mval[1] + 4;
1444
1445         rect.xmin = mval[0] - 4;
1446         rect.ymin = mval[1] - 4;
1447
1448         /* Get Z Depths, needed for perspective, nice for ortho */
1449         bgl_get_mats(&mats);
1450         draw_depth(scene, ar, v3d, NULL);
1451
1452         /* force updating */
1453         if (v3d->depths) {
1454                 had_depth = 1;
1455                 v3d->depths->damaged = 1;
1456         }
1457
1458         view3d_update_depths(ar, v3d);
1459
1460         /* Constrain rect to depth bounds */
1461         if (rect.xmin < 0) rect.xmin = 0;
1462         if (rect.ymin < 0) rect.ymin = 0;
1463         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1464         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;
1465
1466         /* Find the closest Z pixel */
1467         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1468                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1469                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1470                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1471                                 if (depth_close > depth) {
1472                                         depth_close = depth;
1473                                 }
1474                         }
1475                 }
1476         }
1477
1478         if (depth_close==MAXFLOAT)
1479                 return 0;
1480
1481         if (had_depth==0) {
1482                 MEM_freeN(v3d->depths->depths);
1483                 v3d->depths->depths = NULL;
1484         }
1485         v3d->depths->damaged = 1;
1486
1487         cent[0] = (double)mval[0];
1488         cent[1] = (double)mval[1];
1489
1490         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
1491                 return 0;
1492
1493         mouse_worldloc[0] = (float)p[0];
1494         mouse_worldloc[1] = (float)p[1];
1495         mouse_worldloc[2] = (float)p[2];
1496         return 1;
1497 }
1498
1499
1500
1501 /* ********************* NDOF ************************ */
1502 /* note: this code is confusing and unclear... (ton) */
1503 /* **************************************************** */
1504
1505 // ndof scaling will be moved to user setting.
1506 // In the mean time this is just a place holder.
1507
1508 // Note: scaling in the plugin and ghostwinlay.c
1509 // should be removed. With driver default setting,
1510 // each axis returns approx. +-200 max deflection.
1511
1512 // The values I selected are based on the older
1513 // polling i/f. With event i/f, the sensistivity
1514 // can be increased for improved response from
1515 // small deflections of the device input.
1516
1517
1518 // lukep notes : i disagree on the range.
1519 // the normal 3Dconnection driver give +/-400
1520 // on defaut range in other applications
1521 // and up to +/- 1000 if set to maximum
1522 // because i remove the scaling by delta,
1523 // which was a bad idea as it depend of the system
1524 // speed and os, i changed the scaling values, but
1525 // those are still not ok
1526
1527
1528 float ndof_axis_scale[6] = {
1529         +0.01,  // Tx
1530         +0.01,  // Tz
1531         +0.01,  // Ty
1532         +0.0015,        // Rx
1533         +0.0015,        // Rz
1534         +0.0015 // Ry
1535 };
1536
1537 void filterNDOFvalues(float *sbval)
1538 {
1539         int i=0;
1540         float max  = 0.0;
1541
1542         for (i =0; i<6;i++)
1543                 if (fabs(sbval[i]) > max)
1544                         max = fabs(sbval[i]);
1545         for (i =0; i<6;i++)
1546                 if (fabs(sbval[i]) != max )
1547                         sbval[i]=0.0;
1548 }
1549
1550 // statics for controlling v3d->dist corrections.
1551 // viewmoveNDOF zeros and adjusts v3d->ofs.
1552 // viewmove restores based on dz_flag state.
1553
1554 int dz_flag = 0;
1555 float m_dist;
1556
1557 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
1558 {
1559     int i;
1560     float phi;
1561     float dval[7];
1562         // static fval[6] for low pass filter; device input vector is dval[6]
1563         static float fval[6];
1564     float tvec[3],rvec[3];
1565     float q1[4];
1566         float mat[3][3];
1567         float upvec[3];
1568
1569
1570     /*----------------------------------------------------
1571          * sometimes this routine is called from headerbuttons
1572      * viewmove needs to refresh the screen
1573      */
1574 // XXX  areawinset(ar->win);
1575
1576
1577         // fetch the current state of the ndof device
1578 // XXX  getndof(dval);
1579
1580         if (v3d->ndoffilter)
1581                 filterNDOFvalues(fval);
1582
1583         // Scale input values
1584
1585 //      if(dval[6] == 0) return; // guard against divide by zero
1586
1587         for(i=0;i<6;i++) {
1588
1589                 // user scaling
1590                 dval[i] = dval[i] * ndof_axis_scale[i];
1591         }
1592
1593
1594         // low pass filter with zero crossing reset
1595
1596         for(i=0;i<6;i++) {
1597                 if((dval[i] * fval[i]) >= 0)
1598                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
1599                 else
1600                         fval[i] = 0;
1601         }
1602
1603
1604         // force perspective mode. This is a hack and is
1605         // incomplete. It doesn't actually effect the view
1606         // until the first draw and doesn't update the menu
1607         // to reflect persp mode.
1608
1609         v3d->persp = V3D_PERSP;
1610
1611
1612         // Correct the distance jump if v3d->dist != 0
1613
1614         // This is due to a side effect of the original
1615         // mouse view rotation code. The rotation point is
1616         // set a distance in front of the viewport to
1617         // make rotating with the mouse look better.
1618         // The distance effect is written at a low level
1619         // in the view management instead of the mouse
1620         // view function. This means that all other view
1621         // movement devices must subtract this from their
1622         // view transformations.
1623
1624         if(v3d->dist != 0.0) {
1625                 dz_flag = 1;
1626                 m_dist = v3d->dist;
1627                 upvec[0] = upvec[1] = 0;
1628                 upvec[2] = v3d->dist;
1629                 Mat3CpyMat4(mat, v3d->viewinv);
1630                 Mat3MulVecfl(mat, upvec);
1631                 VecSubf(v3d->ofs, v3d->ofs, upvec);
1632                 v3d->dist = 0.0;
1633         }
1634
1635
1636         // Apply rotation
1637         // Rotations feel relatively faster than translations only in fly mode, so
1638         // we have no choice but to fix that here (not in the plugins)
1639         rvec[0] = -0.5 * dval[3];
1640         rvec[1] = -0.5 * dval[4];
1641         rvec[2] = -0.5 * dval[5];
1642
1643         // rotate device x and y by view z
1644
1645         Mat3CpyMat4(mat, v3d->viewinv);
1646         mat[2][2] = 0.0f;
1647         Mat3MulVecfl(mat, rvec);
1648
1649         // rotate the view
1650
1651         phi = Normalize(rvec);
1652         if(phi != 0) {
1653                 VecRotToQuat(rvec,phi,q1);
1654                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
1655         }
1656
1657
1658         // Apply translation
1659
1660         tvec[0] = dval[0];
1661         tvec[1] = dval[1];
1662         tvec[2] = -dval[2];
1663
1664         // the next three lines rotate the x and y translation coordinates
1665         // by the current z axis angle
1666
1667         Mat3CpyMat4(mat, v3d->viewinv);
1668         mat[2][2] = 0.0f;
1669         Mat3MulVecfl(mat, tvec);
1670
1671         // translate the view
1672
1673         VecSubf(v3d->ofs, v3d->ofs, tvec);
1674
1675
1676         /*----------------------------------------------------
1677      * refresh the screen XXX
1678       */
1679
1680         // update render preview window
1681
1682 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
1683 }
1684
1685 void viewmoveNDOF(Scene *scene, View3D *v3d, int mode)
1686 {
1687     float fval[7];
1688     float dvec[3];
1689     float sbadjust = 1.0f;
1690     float len;
1691         short use_sel = 0;
1692         Object *ob = OBACT;
1693     float m[3][3];
1694     float m_inv[3][3];
1695     float xvec[3] = {1,0,0};
1696     float yvec[3] = {0,-1,0};
1697     float zvec[3] = {0,0,1};
1698         float phi, si;
1699     float q1[4];
1700     float obofs[3];
1701     float reverse;
1702     //float diff[4];
1703     float d, curareaX, curareaY;
1704     float mat[3][3];
1705     float upvec[3];
1706
1707     /* Sensitivity will control how fast the view rotates.  The value was
1708      * obtained experimentally by tweaking until the author didn't get dizzy watching.
1709      * Perhaps this should be a configurable user parameter.
1710      */
1711     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
1712     float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
1713     float zsens = 0.3f;   /* zoom sensitivity */
1714
1715     const float minZoom = -30.0f;
1716     const float maxZoom = 300.0f;
1717
1718         //reset view type
1719         v3d->view = 0;
1720 //printf("passing here \n");
1721 //
1722         if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1723                 use_sel = 1;
1724         }
1725
1726     if((dz_flag)||v3d->dist==0) {
1727                 dz_flag = 0;
1728                 v3d->dist = m_dist;
1729                 upvec[0] = upvec[1] = 0;
1730                 upvec[2] = v3d->dist;
1731                 Mat3CpyMat4(mat, v3d->viewinv);
1732                 Mat3MulVecfl(mat, upvec);
1733                 VecAddf(v3d->ofs, v3d->ofs, upvec);
1734         }
1735
1736     /*----------------------------------------------------
1737          * sometimes this routine is called from headerbuttons
1738      * viewmove needs to refresh the screen
1739      */
1740 // XXX  areawinset(curarea->win);
1741
1742     /*----------------------------------------------------
1743      * record how much time has passed. clamp at 10 Hz
1744      * pretend the previous frame occured at the clamped time
1745      */
1746 //    now = PIL_check_seconds_timer();
1747  //   frametime = (now - prevTime);
1748  //   if (frametime > 0.1f){        /* if more than 1/10s */
1749  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
1750 //    }
1751 //    prevTime = now;
1752  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
1753
1754     /* fetch the current state of the ndof device & enforce dominant mode if selected */
1755 // XXX    getndof(fval);
1756         if (v3d->ndoffilter)
1757                 filterNDOFvalues(fval);
1758
1759
1760     // put scaling back here, was previously in ghostwinlay
1761     fval[0] = fval[0] * (1.0f/600.0f);
1762     fval[1] = fval[1] * (1.0f/600.0f);
1763     fval[2] = fval[2] * (1.0f/1100.0f);
1764     fval[3] = fval[3] * 0.00005f;
1765     fval[4] =-fval[4] * 0.00005f;
1766     fval[5] = fval[5] * 0.00005f;
1767     fval[6] = fval[6] / 1000000.0f;
1768
1769     // scale more if not in perspective mode
1770     if (v3d->persp == V3D_ORTHO) {
1771         fval[0] = fval[0] * 0.05f;
1772         fval[1] = fval[1] * 0.05f;
1773         fval[2] = fval[2] * 0.05f;
1774         fval[3] = fval[3] * 0.9f;
1775         fval[4] = fval[4] * 0.9f;
1776         fval[5] = fval[5] * 0.9f;
1777         zsens *= 8;
1778     }
1779
1780
1781     /* set object offset */
1782         if (ob) {
1783                 obofs[0] = -ob->obmat[3][0];
1784                 obofs[1] = -ob->obmat[3][1];
1785                 obofs[2] = -ob->obmat[3][2];
1786         }
1787         else {
1788                 VECCOPY(obofs, v3d->ofs);
1789         }
1790
1791     /* calc an adjustment based on distance from camera
1792        disabled per patch 14402 */
1793      d = 1.0f;
1794
1795 /*    if (ob) {
1796         VecSubf(diff, obofs, v3d->ofs);
1797         d = VecLength(diff);
1798     }
1799 */
1800
1801     reverse = (v3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1802
1803     /*----------------------------------------------------
1804      * ndof device pan
1805      */
1806     psens *= 1.0f + d;
1807     curareaX = sbadjust * psens * fval[0];
1808     curareaY = sbadjust * psens * fval[1];
1809     dvec[0] = curareaX * v3d->persinv[0][0] + curareaY * v3d->persinv[1][0];
1810     dvec[1] = curareaX * v3d->persinv[0][1] + curareaY * v3d->persinv[1][1];
1811     dvec[2] = curareaX * v3d->persinv[0][2] + curareaY * v3d->persinv[1][2];
1812     VecAddf(v3d->ofs, v3d->ofs, dvec);
1813
1814     /*----------------------------------------------------
1815      * ndof device dolly
1816      */
1817     len = zsens * sbadjust * fval[2];
1818
1819     if (v3d->persp==V3D_CAMOB) {
1820         if(v3d->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1821             v3d->camzoom+= 10.0f * -len;
1822         }
1823         if (v3d->camzoom < minZoom) v3d->camzoom = minZoom;
1824         else if (v3d->camzoom > maxZoom) v3d->camzoom = maxZoom;
1825     }
1826     else if ((v3d->dist> 0.001*v3d->grid) && (v3d->dist<10.0*v3d->far)) {
1827         v3d->dist*=(1.0 + len);
1828     }
1829
1830
1831     /*----------------------------------------------------
1832      * ndof device turntable
1833      * derived from the turntable code in viewmove
1834      */
1835
1836     /* Get the 3x3 matrix and its inverse from the quaternion */
1837     QuatToMat3(v3d->viewquat, m);
1838     Mat3Inv(m_inv,m);
1839
1840     /* Determine the direction of the x vector (for rotating up and down) */
1841     /* This can likely be compuated directly from the quaternion. */
1842     Mat3MulVecfl(m_inv,xvec);
1843     Mat3MulVecfl(m_inv,yvec);
1844     Mat3MulVecfl(m_inv,zvec);
1845
1846     /* Perform the up/down rotation */
1847     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1848     si = sin(phi);
1849     q1[0] = cos(phi);
1850     q1[1] = si * xvec[0];
1851     q1[2] = si * xvec[1];
1852     q1[3] = si * xvec[2];
1853     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1854
1855     if (use_sel) {
1856         QuatConj(q1); /* conj == inv for unit quat */
1857         VecSubf(v3d->ofs, v3d->ofs, obofs);
1858         QuatMulVecf(q1, v3d->ofs);
1859         VecAddf(v3d->ofs, v3d->ofs, obofs);
1860     }
1861
1862     /* Perform the orbital rotation */
1863     /* Perform the orbital rotation
1864        If the seen Up axis is parallel to the zoom axis, rotation should be
1865        achieved with a pure Roll motion (no Spin) on the device. When you start
1866        to tilt, moving from Top to Side view, Spinning will increasingly become
1867        more relevant while the Roll component will decrease. When a full
1868        Side view is reached, rotations around the world's Up axis are achieved
1869        with a pure Spin-only motion.  In other words the control of the spinning
1870        around the world's Up axis should move from the device's Spin axis to the
1871        device's Roll axis depending on the orientation of the world's Up axis
1872        relative to the screen. */
1873     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
1874     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
1875     q1[0] = cos(phi);
1876     q1[1] = q1[2] = 0.0;
1877     q1[3] = sin(phi);
1878     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1879
1880     if (use_sel) {
1881         QuatConj(q1);
1882         VecSubf(v3d->ofs, v3d->ofs, obofs);
1883         QuatMulVecf(q1, v3d->ofs);
1884         VecAddf(v3d->ofs, v3d->ofs, obofs);
1885     }
1886
1887     /*----------------------------------------------------
1888      * refresh the screen
1889      */
1890 // XXX    scrarea_do_windraw(curarea);
1891 }
1892
1893
1894
1895