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