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_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 VIEW3D_OT_viewrotate(wmOperatorType *ot)
401 {
402
403         /* identifiers */
404         ot->name= "Rotate view";
405         ot->idname= "VIEW3D_OT_viewrotate";
406
407         /* api callbacks */
408         ot->invoke= viewrotate_invoke;
409         ot->modal= viewrotate_modal;
410         ot->poll= ED_operator_view3d_active;
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 VIEW3D_OT_viewmove(wmOperatorType *ot)
476 {
477
478         /* identifiers */
479         ot->name= "Rotate view";
480         ot->idname= "VIEW3D_OT_viewmove";
481
482         /* api callbacks */
483         ot->invoke= viewmove_invoke;
484         ot->modal= viewmove_modal;
485         ot->poll= ED_operator_view3d_active;
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 VIEW3D_OT_viewzoom(wmOperatorType *ot)
661 {
662
663         /* identifiers */
664         ot->name= "Rotate view";
665         ot->idname= "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_view3d_active;
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) {
728                         v3d->persp= V3D_PERSP;
729                         smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL); 
730                 }
731         }
732 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
733
734         return OPERATOR_FINISHED;
735 }
736
737 void VIEW3D_OT_viewhome(wmOperatorType *ot)
738 {
739
740         /* identifiers */
741         ot->name= "View home";
742         ot->idname= "VIEW3D_OT_viewhome";
743
744         /* api callbacks */
745         ot->exec= viewhome_exec;
746         ot->poll= ED_operator_view3d_active;
747
748         RNA_def_property(ot->srna, "center", PROP_BOOLEAN, PROP_NONE);
749 }
750
751 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
752 {
753         ScrArea *sa= CTX_wm_area(C);
754         ARegion *ar= CTX_wm_region(C);
755         View3D *v3d= sa->spacedata.first;
756         Scene *scene= CTX_data_scene(C);
757         Object *ob= OBACT;
758         Object *obedit= CTX_data_edit_object(C);
759         float size, min[3], max[3], afm[3];
760         int ok=0;
761
762         /* SMOOTHVIEW */
763         float new_ofs[3];
764         float new_dist;
765
766         INIT_MINMAX(min, max);
767
768         if (G.f & G_WEIGHTPAINT) {
769                 /* hardcoded exception, we look for the one selected armature */
770                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
771                 Base *base;
772                 for(base=scene->base.first; base; base= base->next) {
773                         if(TESTBASELIB(v3d, base)) {
774                                 if(base->object->type==OB_ARMATURE)
775                                         if(base->object->flag & OB_POSEMODE)
776                                                 break;
777                         }
778                 }
779                 if(base)
780                         ob= base->object;
781         }
782
783
784         if(obedit) {
785 // XXX          ok = minmax_verts(min, max);    /* only selected */
786         }
787         else if(ob && (ob->flag & OB_POSEMODE)) {
788                 if(ob->pose) {
789                         bArmature *arm= ob->data;
790                         bPoseChannel *pchan;
791                         float vec[3];
792
793                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
794                                 if(pchan->bone->flag & BONE_SELECTED) {
795                                         if(pchan->bone->layer & arm->layer) {
796                                                 ok= 1;
797                                                 VECCOPY(vec, pchan->pose_head);
798                                                 Mat4MulVecfl(ob->obmat, vec);
799                                                 DO_MINMAX(vec, min, max);
800                                                 VECCOPY(vec, pchan->pose_tail);
801                                                 Mat4MulVecfl(ob->obmat, vec);
802                                                 DO_MINMAX(vec, min, max);
803                                         }
804                                 }
805                         }
806                 }
807         }
808         else if (FACESEL_PAINT_TEST) {
809 // XXX          ok= minmax_tface(min, max);
810         }
811         else if (G.f & G_PARTICLEEDIT) {
812 // XXX          ok= PE_minmax(min, max);
813         }
814         else {
815                 Base *base= FIRSTBASE;
816                 while(base) {
817                         if(TESTBASE(v3d, base))  {
818                                 minmax_object(base->object, min, max);
819                                 /* account for duplis */
820                                 minmax_object_duplis(scene, base->object, min, max);
821
822                                 ok= 1;
823                         }
824                         base= base->next;
825                 }
826         }
827
828         if(ok==0) return OPERATOR_FINISHED;
829
830         afm[0]= (max[0]-min[0]);
831         afm[1]= (max[1]-min[1]);
832         afm[2]= (max[2]-min[2]);
833         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
834
835         if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
836
837         new_ofs[0]= -(min[0]+max[0])/2.0f;
838         new_ofs[1]= -(min[1]+max[1])/2.0f;
839         new_ofs[2]= -(min[2]+max[2])/2.0f;
840
841         new_dist = size;
842
843         /* correction for window aspect ratio */
844         if(ar->winy>2 && ar->winx>2) {
845                 size= (float)ar->winx/(float)ar->winy;
846                 if(size<1.0f) size= 1.0f/size;
847                 new_dist*= size;
848         }
849
850         v3d->cursor[0]= -new_ofs[0];
851         v3d->cursor[1]= -new_ofs[1];
852         v3d->cursor[2]= -new_ofs[2];
853
854         if (v3d->persp==V3D_CAMOB) {
855                 v3d->persp= V3D_PERSP;
856                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
857         } 
858         else {
859                 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
860         }
861
862 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
863
864         return OPERATOR_FINISHED;
865 }
866 void VIEW3D_OT_viewcenter(wmOperatorType *ot)
867 {
868
869         /* identifiers */
870         ot->name= "View center";
871         ot->idname= "VIEW3D_OT_viewcenter";
872
873         /* api callbacks */
874         ot->exec= viewcenter_exec;
875         ot->poll= ED_operator_view3d_active;
876 }
877
878 /* ********************* Set render border operator ****************** */
879
880 static int render_border_exec(bContext *C, wmOperator *op)
881 {
882         ScrArea *sa= CTX_wm_area(C);
883         ARegion *ar= CTX_wm_region(C);
884         View3D *v3d= sa->spacedata.first;
885         Scene *scene= CTX_data_scene(C);
886         
887         rcti rect;
888         rctf vb;
889         
890         /* get border select values using rna */
891         rect.xmin= RNA_int_get(op->ptr, "xmin");
892         rect.ymin= RNA_int_get(op->ptr, "ymin");
893         rect.xmax= RNA_int_get(op->ptr, "xmax");
894         rect.ymax= RNA_int_get(op->ptr, "ymax");
895         
896         /* calculate range */
897         calc_viewborder(scene, ar, v3d, &vb);
898
899         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
900         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
901         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
902         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
903         
904         /* actually set border */       
905         CLAMP(scene->r.border.xmin, 0.0, 1.0);
906         CLAMP(scene->r.border.ymin, 0.0, 1.0);
907         CLAMP(scene->r.border.xmax, 0.0, 1.0);
908         CLAMP(scene->r.border.ymax, 0.0, 1.0);
909                 
910         /* drawing a border surrounding the entire camera view switches off border rendering
911          * or the border covers no pixels */
912         if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
913                 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
914            (scene->r.border.xmin == scene->r.border.xmax ||
915                 scene->r.border.ymin == scene->r.border.ymax ))
916         {
917                 scene->r.mode &= ~R_BORDER;
918         } else {
919                 scene->r.mode |= R_BORDER;
920         }
921         
922         return OPERATOR_FINISHED;
923
924 }
925
926 static int view3d_render_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
927 {
928         ScrArea *sa= CTX_wm_area(C);
929         View3D *v3d= sa->spacedata.first;
930         
931         /* if not in camera view do not exec the operator*/
932         if (v3d->persp == V3D_CAMOB) return WM_border_select_invoke(C, op, event);      
933         else return OPERATOR_PASS_THROUGH;
934 }
935
936 void VIEW3D_OT_render_border(wmOperatorType *ot)
937 {
938         
939         /* identifiers */
940         ot->name= "Set Render Border";
941         ot->idname= "VIEW3D_OT_render_border";
942
943         /* api callbacks */
944         ot->invoke= view3d_render_border_invoke;
945         ot->exec= render_border_exec;
946         ot->modal= WM_border_select_modal;
947         
948         ot->poll= ED_operator_view3d_active;
949         
950         /* rna */
951         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
952         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
953         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
954         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
955
956 }
957 /* ********************* Changing view operator ****************** */
958
959 static EnumPropertyItem prop_view_items[] = {
960         {V3D_VIEW_FRONT, "FRONT", "Front", "View From the Front"},
961         {V3D_VIEW_BACK, "BACK", "Back", "View From the Back"},
962         {V3D_VIEW_LEFT, "LEFT", "Left", "View From the Left"},
963         {V3D_VIEW_RIGHT, "RIGHT", "Right", "View From the Right"},
964         {V3D_VIEW_TOP, "TOP", "Top", "View From the Top"},
965         {V3D_VIEW_BOTTOM, "BOTTOM", "Bottom", "View From the Bottom"},
966         {V3D_VIEW_PERSPORTHO, "PERSPORTHO", "Persp-Ortho", "Switch between Perspecive and Orthographic View"},
967         {V3D_VIEW_CAMERA, "CAMERA", "Camera", "View From the active amera"},
968         {V3D_VIEW_STEPLEFT, "STEPLEFT", "Step Left", "Step the view around to the Left"},
969         {V3D_VIEW_STEPRIGHT, "STEPRIGHT", "Step Right", "Step the view around to the Right"},
970         {V3D_VIEW_STEPUP, "STEPUP", "Step Up", "Step the view Up"},
971         {V3D_VIEW_STEPDOWN, "STEPDOWN", "Step Down", "Step the view Down"},
972         {V3D_VIEW_PANLEFT, "PANLEFT", "Pan Left", "Pan the view to the Left"},
973         {V3D_VIEW_PANRIGHT, "PANRIGHT", "Pan Right", "Pan the view to the Right"},
974         {V3D_VIEW_PANUP, "PANUP", "Pan Up", "Pan the view Up"},
975         {V3D_VIEW_PANDOWN, "PANDOWN", "Pan Down", "Pan the view Down"},
976         {0, NULL, NULL, NULL}};
977
978 static void axis_set_view(bContext *C, View3D *v3d, float q1, float q2, float q3, float q4, short view, int perspo)
979 {
980         float new_quat[4];
981         new_quat[0]= q1; new_quat[1]= q2;
982         new_quat[2]= q3; new_quat[3]= q4;
983         v3d->view=0;
984
985         v3d->view= view;
986         
987         if (v3d->persp==V3D_CAMOB && v3d->camera) {
988
989                 if (U.uiflag & USER_AUTOPERSP) v3d->persp= V3D_ORTHO;
990                 else if(v3d->persp==V3D_CAMOB) v3d->persp= perspo;
991
992                 smooth_view(C, v3d->camera, NULL, v3d->ofs, new_quat, NULL, NULL); 
993         } 
994         else {
995
996                 if (U.uiflag & USER_AUTOPERSP) v3d->persp= V3D_ORTHO;
997                 else if(v3d->persp==V3D_CAMOB) v3d->persp= perspo;
998
999                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1000         }
1001
1002 }
1003
1004
1005 static int viewnumpad_exec(bContext *C, wmOperator *op)
1006 {
1007         ScrArea *sa= CTX_wm_area(C);
1008         ARegion *ar= CTX_wm_region(C);
1009         View3D *v3d= sa->spacedata.first;
1010         Scene *scene= CTX_data_scene(C);
1011         float phi, si, q1[4], vec[3];
1012         static int perspo=V3D_PERSP;
1013         int viewnum;
1014
1015         viewnum = RNA_enum_get(op->ptr, "viewnum");
1016
1017         /* Use this to test if we started out with a camera */
1018
1019         /* Indicate that this view is inverted,
1020          * but only if it actually _was_ inverted (jobbe) */
1021         if (viewnum == V3D_VIEW_BOTTOM || viewnum == V3D_VIEW_BACK || viewnum == V3D_VIEW_LEFT)
1022                 v3d->flag2 |= V3D_OPP_DIRECTION_NAME;
1023         else if (viewnum != V3D_VIEW_PERSPORTHO)
1024                         v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME;
1025
1026         switch (viewnum) {
1027                 case V3D_VIEW_BOTTOM :
1028                         axis_set_view(C, v3d, 0.0, -1.0, 0.0, 0.0, 7, perspo);
1029                         break;
1030
1031                 case V3D_VIEW_BACK:
1032                         axis_set_view(C, v3d, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), 1, perspo);
1033                         break;
1034
1035                 case V3D_VIEW_LEFT:
1036                         axis_set_view(C, v3d, 0.5, -0.5, 0.5, 0.5, 3, perspo);
1037                         break;
1038
1039                 case V3D_VIEW_TOP:
1040                         axis_set_view(C, v3d, 1.0, 0.0, 0.0, 0.0, 7, perspo);
1041                         break;
1042
1043                 case V3D_VIEW_FRONT:
1044                         axis_set_view(C, v3d, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, 1, perspo);
1045                         break;
1046
1047                 case V3D_VIEW_RIGHT:
1048                         axis_set_view(C, v3d, 0.5, -0.5, -0.5, -0.5, 3, perspo);
1049                         break;
1050
1051                 case V3D_VIEW_PERSPORTHO:
1052
1053                         if(v3d->persp!=V3D_ORTHO) 
1054                                 v3d->persp=V3D_ORTHO;
1055                         else v3d->persp=V3D_PERSP;
1056
1057                         ED_region_tag_redraw(ar);
1058                         break;
1059
1060                 case V3D_VIEW_CAMERA:
1061                         /* lastview -  */
1062
1063                         if(v3d->persp != V3D_CAMOB) {
1064                                 /* store settings of current view before allowing overwriting with camera view */
1065                                 QUATCOPY(v3d->lviewquat, v3d->viewquat);
1066                                 v3d->lview= v3d->view;
1067                                 v3d->lpersp= v3d->persp;
1068                                 
1069 #if 0
1070                                 if(G.qual==LR_ALTKEY) {
1071                                         if(oldcamera && is_an_active_object(oldcamera)) {
1072                                                 v3d->camera= oldcamera;
1073                                         }
1074                                         handle_view3d_lock();
1075                                 }
1076 #endif
1077                                 
1078                                 if(BASACT) {
1079                                         /* check both G.vd as G.scene cameras */
1080                                         if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1081                                                 v3d->camera= OBACT;
1082                                                 /*handle_view3d_lock();*/
1083                                         }
1084                                 }
1085                                 
1086                                 if(v3d->camera==NULL) {
1087                                         v3d->camera= scene_find_camera(scene);
1088                                         /*handle_view3d_lock();*/
1089                                 }
1090                                 v3d->persp= V3D_CAMOB;
1091                                 smooth_view(C, NULL, v3d->camera, v3d->ofs, v3d->viewquat, &v3d->dist, &v3d->lens);
1092                                 
1093                         }
1094                         else{
1095                                 /* return to settings of last view */
1096                                 /* does smooth_view too */
1097                                 axis_set_view(C, v3d, v3d->lviewquat[0], v3d->lviewquat[1], v3d->lviewquat[2], v3d->lviewquat[3], v3d->lview, v3d->lpersp);
1098                         }
1099                         break;
1100
1101                 case V3D_VIEW_STEPLEFT:
1102                 case V3D_VIEW_STEPRIGHT:
1103                 case V3D_VIEW_STEPUP:
1104                 case V3D_VIEW_STEPDOWN:
1105
1106                         if(v3d->persp != V3D_CAMOB) {
1107                                 if(viewnum == V3D_VIEW_STEPLEFT || viewnum == V3D_VIEW_STEPRIGHT) {
1108                                         /* z-axis */
1109                                         phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1110                                         if(viewnum == V3D_VIEW_STEPRIGHT) phi= -phi;
1111                                         si= (float)sin(phi);
1112                                         q1[0]= (float)cos(phi);
1113                                         q1[1]= q1[2]= 0.0;
1114                                         q1[3]= si;
1115                                         QuatMul(v3d->viewquat, v3d->viewquat, q1);
1116                                         v3d->view= 0;
1117                                 }
1118                                 if(viewnum == V3D_VIEW_STEPDOWN || viewnum == V3D_VIEW_STEPUP) {
1119                                         /* horizontal axis */
1120                                         VECCOPY(q1+1, v3d->viewinv[0]);
1121
1122                                         Normalize(q1+1);
1123                                         phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1124                                         if(viewnum == V3D_VIEW_STEPDOWN) phi= -phi;
1125                                         si= (float)sin(phi);
1126                                         q1[0]= (float)cos(phi);
1127                                         q1[1]*= si;
1128                                         q1[2]*= si;
1129                                         q1[3]*= si;
1130                                         QuatMul(v3d->viewquat, v3d->viewquat, q1);
1131                                         v3d->view= 0;
1132                                 }
1133                                 ED_region_tag_redraw(ar);
1134                         }
1135                         break;
1136
1137                 case V3D_VIEW_PANRIGHT:
1138                 case V3D_VIEW_PANLEFT:
1139                 case V3D_VIEW_PANUP:
1140                 case V3D_VIEW_PANDOWN:
1141
1142                         initgrabz(v3d, 0.0, 0.0, 0.0);
1143
1144                         if(viewnum == V3D_VIEW_PANRIGHT) window_to_3d(ar, v3d, vec, -32, 0);
1145                         else if(viewnum == V3D_VIEW_PANLEFT) window_to_3d(ar, v3d, vec, 32, 0);
1146                         else if(viewnum == V3D_VIEW_PANUP) window_to_3d(ar, v3d, vec, 0, -25);
1147                         else if(viewnum == V3D_VIEW_PANDOWN) window_to_3d(ar, v3d, vec, 0, 25);
1148                         v3d->ofs[0]+= vec[0];
1149                         v3d->ofs[1]+= vec[1];
1150                         v3d->ofs[2]+= vec[2];
1151
1152                         ED_region_tag_redraw(ar);
1153                         break;
1154
1155                 default :
1156                         break;
1157         }
1158
1159         if(v3d->persp != V3D_CAMOB) perspo= v3d->persp;
1160
1161         return OPERATOR_FINISHED;
1162 }
1163
1164
1165 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1166 {
1167
1168         PropertyRNA *prop;
1169
1170         /* identifiers */
1171         ot->name= "View numpad";
1172         ot->idname= "VIEW3D_OT_viewnumpad";
1173
1174         /* api callbacks */
1175         ot->exec= viewnumpad_exec;
1176         ot->poll= ED_operator_view3d_active;
1177         ot->flag= OPTYPE_REGISTER;
1178
1179         prop = RNA_def_property(ot->srna, "viewnum", PROP_ENUM, PROP_NONE);
1180         RNA_def_property_enum_items(prop, prop_view_items);
1181 }
1182
1183 /* ********************* set clipping operator ****************** */
1184
1185 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1186 {
1187         ScrArea *sa= CTX_wm_area(C);
1188         View3D *v3d= sa->spacedata.first;
1189         rcti rect;
1190         double mvmatrix[16];
1191         double projmatrix[16];
1192         double xs, ys, p[3];
1193         GLint viewport[4];
1194         short val;
1195
1196         rect.xmin= RNA_int_get(op->ptr, "xmin");
1197         rect.ymin= RNA_int_get(op->ptr, "ymin");
1198         rect.xmax= RNA_int_get(op->ptr, "xmax");
1199         rect.ymax= RNA_int_get(op->ptr, "ymax");
1200
1201         v3d->flag |= V3D_CLIPPING;
1202         v3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1203
1204         /* note; otherwise opengl won't work */
1205         view3d_operator_needs_opengl(C);
1206
1207         /* Get the matrices needed for gluUnProject */
1208         glGetIntegerv(GL_VIEWPORT, viewport);
1209         glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
1210         glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
1211
1212         /* near zero floating point values can give issues with gluUnProject
1213                 in side view on some implementations */
1214         if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
1215         if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
1216
1217         /* Set up viewport so that gluUnProject will give correct values */
1218         viewport[0] = 0;
1219         viewport[1] = 0;
1220
1221         /* four clipping planes and bounding volume */
1222         /* first do the bounding volume */
1223         for(val=0; val<4; val++) {
1224
1225                 xs= (val==0||val==3)?rect.xmin:rect.xmax;
1226                 ys= (val==0||val==1)?rect.ymin:rect.ymax;
1227
1228                 gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1229                 VECCOPY(v3d->clipbb->vec[val], p);
1230
1231                 gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1232                 VECCOPY(v3d->clipbb->vec[4+val], p);
1233         }
1234
1235         /* then plane equations */
1236         for(val=0; val<4; val++) {
1237
1238                 CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
1239                                           v3d->clip[val]);
1240
1241                 v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0]
1242                         - v3d->clip[val][1]*v3d->clipbb->vec[val][1]
1243                         - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
1244         }
1245         return OPERATOR_FINISHED;
1246 }
1247
1248 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
1249 {
1250         ScrArea *sa= CTX_wm_area(C);
1251         View3D *v3d= sa->spacedata.first;
1252
1253         if(v3d->flag & V3D_CLIPPING) {
1254                 v3d->flag &= ~V3D_CLIPPING;
1255                 ED_area_tag_redraw(sa);
1256                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
1257                 v3d->clipbb= NULL;
1258                 return OPERATOR_FINISHED;
1259         }
1260         else {
1261                 return WM_border_select_invoke(C, op, event);
1262         }
1263 }
1264
1265 /* toggles */
1266 void VIEW3D_OT_clipping(wmOperatorType *ot)
1267 {
1268
1269         /* identifiers */
1270         ot->name= "Border Select";
1271         ot->idname= "VIEW3D_OT_clipping";
1272
1273         /* api callbacks */
1274         ot->invoke= view3d_clipping_invoke;
1275         ot->exec= view3d_clipping_exec;
1276         ot->modal= WM_border_select_modal;
1277
1278         ot->poll= ED_operator_view3d_active;
1279
1280         /* rna */
1281         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1282         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1283         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1284         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1285 }
1286
1287 /* ********************* draw type operator ****************** */
1288
1289 static int view3d_drawtype_exec(bContext *C, wmOperator *op)
1290 {
1291         ScrArea *sa= CTX_wm_area(C);
1292         View3D *v3d= sa->spacedata.first;
1293         int dt, dt_alt;
1294
1295         dt  = RNA_int_get(op->ptr, "drawtype");
1296         dt_alt = RNA_int_get(op->ptr, "drawtype_alt");
1297         
1298         if (dt_alt != -1)
1299         {
1300                 if (v3d->drawtype == dt)
1301                 {
1302                         v3d->drawtype = dt_alt;
1303                 }
1304                 else
1305                 {
1306                         v3d->drawtype = dt;
1307                 }
1308         }
1309         else
1310         {
1311                 v3d->drawtype = dt;
1312         }
1313
1314         ED_area_tag_redraw(sa);
1315         
1316         return OPERATOR_FINISHED;
1317 }
1318
1319 static int view3d_drawtype_invoke(bContext *C, wmOperator *op, wmEvent *event)
1320 {
1321         return view3d_drawtype_exec(C, op);
1322 }
1323
1324 /* toggles */
1325 void VIEW3D_OT_drawtype(wmOperatorType *ot)
1326 {
1327         PropertyRNA *prop;
1328
1329         /* identifiers */
1330         ot->name= "Change draw type";
1331         ot->idname= "VIEW3D_OT_drawtype";
1332
1333         /* api callbacks */
1334         ot->invoke= view3d_drawtype_invoke;
1335         ot->exec= view3d_drawtype_exec;
1336
1337         ot->poll= ED_operator_view3d_active;
1338
1339         /* rna */
1340         RNA_def_property(ot->srna, "drawtype", PROP_INT, PROP_NONE);
1341         prop = RNA_def_property(ot->srna, "drawtype_alt", PROP_INT, PROP_NONE);
1342         RNA_def_property_int_default(prop, -1);
1343 }
1344
1345 /* ********************************************************* */
1346
1347 void view3d_border_zoom(Scene *scene, ARegion *ar, View3D *v3d)
1348 {
1349
1350         /* Zooms in on a border drawn by the user */
1351         rcti rect;
1352         short val;
1353         float dvec[3], vb[2], xscale, yscale, scale;
1354
1355
1356         /* SMOOTHVIEW */
1357         float new_dist;
1358         float new_ofs[3];
1359
1360         /* ZBuffer depth vars */
1361         bglMats mats;
1362         float depth, depth_close= MAXFLOAT;
1363         int had_depth = 0;
1364         double cent[2],  p[3];
1365         int xs, ys;
1366
1367         /* Get the border input */
1368         val = 0; // XXX get_border(&rect, 3);
1369         if(!val) return;
1370
1371         /* Get Z Depths, needed for perspective, nice for ortho */
1372         bgl_get_mats(&mats);
1373         draw_depth(scene, ar, v3d, NULL);
1374
1375         /* force updating */
1376         if (v3d->depths) {
1377                 had_depth = 1;
1378                 v3d->depths->damaged = 1;
1379         }
1380
1381         view3d_update_depths(ar, v3d);
1382
1383         /* Constrain rect to depth bounds */
1384         if (rect.xmin < 0) rect.xmin = 0;
1385         if (rect.ymin < 0) rect.ymin = 0;
1386         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1387         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;
1388
1389         /* Find the closest Z pixel */
1390         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1391                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1392                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1393                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1394                                 if (depth_close > depth) {
1395                                         depth_close = depth;
1396                                 }
1397                         }
1398                 }
1399         }
1400
1401         if (had_depth==0) {
1402                 MEM_freeN(v3d->depths->depths);
1403                 v3d->depths->depths = NULL;
1404         }
1405         v3d->depths->damaged = 1;
1406
1407         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1408         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1409
1410         if (v3d->persp==V3D_PERSP) {
1411                 double p_corner[3];
1412
1413                 /* no depths to use, we cant do anything! */
1414                 if (depth_close==MAXFLOAT)
1415                         return;
1416
1417                 /* convert border to 3d coordinates */
1418                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1419                         (       !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])))
1420                         return;
1421
1422                 dvec[0] = p[0]-p_corner[0];
1423                 dvec[1] = p[1]-p_corner[1];
1424                 dvec[2] = p[2]-p_corner[2];
1425
1426                 new_dist = VecLength(dvec);
1427                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1428
1429                 new_ofs[0] = -p[0];
1430                 new_ofs[1] = -p[1];
1431                 new_ofs[2] = -p[2];
1432
1433         } else { /* othographic */
1434                 /* find the current window width and height */
1435                 vb[0] = ar->winx;
1436                 vb[1] = ar->winy;
1437
1438                 new_dist = v3d->dist;
1439
1440                 /* convert the drawn rectangle into 3d space */
1441                 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1442                         new_ofs[0] = -p[0];
1443                         new_ofs[1] = -p[1];
1444                         new_ofs[2] = -p[2];
1445                 } else {
1446                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1447                         new_ofs[0] = v3d->ofs[0];
1448                         new_ofs[1] = v3d->ofs[1];
1449                         new_ofs[2] = v3d->ofs[2];
1450
1451                         initgrabz(v3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1452
1453                         window_to_3d(ar, v3d, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1454                         /* center the view to the center of the rectangle */
1455                         VecSubf(new_ofs, new_ofs, dvec);
1456                 }
1457
1458                 /* work out the ratios, so that everything selected fits when we zoom */
1459                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1460                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1461                 scale = (xscale >= yscale)?xscale:yscale;
1462
1463                 /* zoom in as required, or as far as we can go */
1464                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1465         }
1466
1467         smooth_view(NULL, NULL, NULL, new_ofs, NULL, &new_dist, NULL); // XXX
1468 }
1469
1470 /* ***************** 3d cursor cursor op ******************* */
1471
1472 /* mx my in region coords */
1473 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
1474 {
1475         Scene *scene= CTX_data_scene(C);
1476         ARegion *ar= CTX_wm_region(C);
1477         View3D *v3d= (View3D *)CTX_wm_space_data(C);
1478         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
1479         short mx, my, mval[2];
1480 //      short ctrl= 0; // XXX
1481         
1482         fp= give_cursor(scene, v3d);
1483         
1484 //      if(obedit && ctrl) lr_click= 1;
1485         VECCOPY(oldcurs, fp);
1486         
1487         mx= event->x - ar->winrct.xmin;
1488         my= event->y - ar->winrct.ymin;
1489         project_short_noclip(ar, v3d, fp, mval);
1490         
1491         initgrabz(v3d, fp[0], fp[1], fp[2]);
1492         
1493         if(mval[0]!=IS_CLIPPED) {
1494                 
1495                 window_to_3d(ar, v3d, dvec, mval[0]-mx, mval[1]-my);
1496                 VecSubf(fp, fp, dvec);
1497         }
1498         else {
1499                 
1500                 dx= ((float)(mx-(ar->winx/2)))*v3d->zfac/(ar->winx/2);
1501                 dy= ((float)(my-(ar->winy/2)))*v3d->zfac/(ar->winy/2);
1502                 
1503                 fz= v3d->persmat[0][3]*fp[0]+ v3d->persmat[1][3]*fp[1]+ v3d->persmat[2][3]*fp[2]+ v3d->persmat[3][3];
1504                 fz= fz/v3d->zfac;
1505                 
1506                 fp[0]= (v3d->persinv[0][0]*dx + v3d->persinv[1][0]*dy+ v3d->persinv[2][0]*fz)-v3d->ofs[0];
1507                 fp[1]= (v3d->persinv[0][1]*dx + v3d->persinv[1][1]*dy+ v3d->persinv[2][1]*fz)-v3d->ofs[1];
1508                 fp[2]= (v3d->persinv[0][2]*dx + v3d->persinv[1][2]*dy+ v3d->persinv[2][2]*fz)-v3d->ofs[2];
1509         }
1510         
1511 //      if(lr_click) {
1512                 // XXX          if(obedit->type==OB_MESH) add_click_mesh();
1513                 //              else if ELEM(obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
1514                 //              else if (obedit->type==OB_ARMATURE) addvert_armature();
1515 //              VECCOPY(fp, oldcurs);
1516 //      }
1517         // XXX notifier for scene */
1518         ED_region_tag_redraw(ar);
1519         
1520         /* prevent other mouse ops to fail */
1521         return OPERATOR_PASS_THROUGH;
1522 }
1523
1524 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
1525 {
1526         
1527         /* identifiers */
1528         ot->name= "Set 3D Cursor";
1529         ot->idname= "VIEW3D_OT_cursor3d";
1530         
1531         /* api callbacks */
1532         ot->invoke= set_3dcursor_invoke;
1533         
1534         ot->poll= ED_operator_view3d_active;
1535         
1536         /* rna later */
1537
1538 }
1539
1540
1541 /* ************************* below the line! *********************** */
1542
1543
1544 /* XXX todo Zooms in on a border drawn by the user */
1545 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
1546 {
1547         rcti rect;
1548         /* ZBuffer depth vars */
1549         bglMats mats;
1550         float depth, depth_close= MAXFLOAT;
1551         int had_depth = 0;
1552         double cent[2],  p[3];
1553         int xs, ys;
1554
1555         // XXX          getmouseco_areawin(mval);
1556
1557         // XXX  persp(PERSP_VIEW);
1558
1559         rect.xmax = mval[0] + 4;
1560         rect.ymax = mval[1] + 4;
1561
1562         rect.xmin = mval[0] - 4;
1563         rect.ymin = mval[1] - 4;
1564
1565         /* Get Z Depths, needed for perspective, nice for ortho */
1566         bgl_get_mats(&mats);
1567         draw_depth(scene, ar, v3d, NULL);
1568
1569         /* force updating */
1570         if (v3d->depths) {
1571                 had_depth = 1;
1572                 v3d->depths->damaged = 1;
1573         }
1574
1575         view3d_update_depths(ar, v3d);
1576
1577         /* Constrain rect to depth bounds */
1578         if (rect.xmin < 0) rect.xmin = 0;
1579         if (rect.ymin < 0) rect.ymin = 0;
1580         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1581         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;
1582
1583         /* Find the closest Z pixel */
1584         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1585                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1586                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1587                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1588                                 if (depth_close > depth) {
1589                                         depth_close = depth;
1590                                 }
1591                         }
1592                 }
1593         }
1594
1595         if (depth_close==MAXFLOAT)
1596                 return 0;
1597
1598         if (had_depth==0) {
1599                 MEM_freeN(v3d->depths->depths);
1600                 v3d->depths->depths = NULL;
1601         }
1602         v3d->depths->damaged = 1;
1603
1604         cent[0] = (double)mval[0];
1605         cent[1] = (double)mval[1];
1606
1607         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
1608                 return 0;
1609
1610         mouse_worldloc[0] = (float)p[0];
1611         mouse_worldloc[1] = (float)p[1];
1612         mouse_worldloc[2] = (float)p[2];
1613         return 1;
1614 }
1615
1616
1617
1618 /* ********************* NDOF ************************ */
1619 /* note: this code is confusing and unclear... (ton) */
1620 /* **************************************************** */
1621
1622 // ndof scaling will be moved to user setting.
1623 // In the mean time this is just a place holder.
1624
1625 // Note: scaling in the plugin and ghostwinlay.c
1626 // should be removed. With driver default setting,
1627 // each axis returns approx. +-200 max deflection.
1628
1629 // The values I selected are based on the older
1630 // polling i/f. With event i/f, the sensistivity
1631 // can be increased for improved response from
1632 // small deflections of the device input.
1633
1634
1635 // lukep notes : i disagree on the range.
1636 // the normal 3Dconnection driver give +/-400
1637 // on defaut range in other applications
1638 // and up to +/- 1000 if set to maximum
1639 // because i remove the scaling by delta,
1640 // which was a bad idea as it depend of the system
1641 // speed and os, i changed the scaling values, but
1642 // those are still not ok
1643
1644
1645 float ndof_axis_scale[6] = {
1646         +0.01,  // Tx
1647         +0.01,  // Tz
1648         +0.01,  // Ty
1649         +0.0015,        // Rx
1650         +0.0015,        // Rz
1651         +0.0015 // Ry
1652 };
1653
1654 void filterNDOFvalues(float *sbval)
1655 {
1656         int i=0;
1657         float max  = 0.0;
1658
1659         for (i =0; i<6;i++)
1660                 if (fabs(sbval[i]) > max)
1661                         max = fabs(sbval[i]);
1662         for (i =0; i<6;i++)
1663                 if (fabs(sbval[i]) != max )
1664                         sbval[i]=0.0;
1665 }
1666
1667 // statics for controlling v3d->dist corrections.
1668 // viewmoveNDOF zeros and adjusts v3d->ofs.
1669 // viewmove restores based on dz_flag state.
1670
1671 int dz_flag = 0;
1672 float m_dist;
1673
1674 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
1675 {
1676     int i;
1677     float phi;
1678     float dval[7];
1679         // static fval[6] for low pass filter; device input vector is dval[6]
1680         static float fval[6];
1681     float tvec[3],rvec[3];
1682     float q1[4];
1683         float mat[3][3];
1684         float upvec[3];
1685
1686
1687     /*----------------------------------------------------
1688          * sometimes this routine is called from headerbuttons
1689      * viewmove needs to refresh the screen
1690      */
1691 // XXX  areawinset(ar->win);
1692
1693
1694         // fetch the current state of the ndof device
1695 // XXX  getndof(dval);
1696
1697         if (v3d->ndoffilter)
1698                 filterNDOFvalues(fval);
1699
1700         // Scale input values
1701
1702 //      if(dval[6] == 0) return; // guard against divide by zero
1703
1704         for(i=0;i<6;i++) {
1705
1706                 // user scaling
1707                 dval[i] = dval[i] * ndof_axis_scale[i];
1708         }
1709
1710
1711         // low pass filter with zero crossing reset
1712
1713         for(i=0;i<6;i++) {
1714                 if((dval[i] * fval[i]) >= 0)
1715                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
1716                 else
1717                         fval[i] = 0;
1718         }
1719
1720
1721         // force perspective mode. This is a hack and is
1722         // incomplete. It doesn't actually effect the view
1723         // until the first draw and doesn't update the menu
1724         // to reflect persp mode.
1725
1726         v3d->persp = V3D_PERSP;
1727
1728
1729         // Correct the distance jump if v3d->dist != 0
1730
1731         // This is due to a side effect of the original
1732         // mouse view rotation code. The rotation point is
1733         // set a distance in front of the viewport to
1734         // make rotating with the mouse look better.
1735         // The distance effect is written at a low level
1736         // in the view management instead of the mouse
1737         // view function. This means that all other view
1738         // movement devices must subtract this from their
1739         // view transformations.
1740
1741         if(v3d->dist != 0.0) {
1742                 dz_flag = 1;
1743                 m_dist = v3d->dist;
1744                 upvec[0] = upvec[1] = 0;
1745                 upvec[2] = v3d->dist;
1746                 Mat3CpyMat4(mat, v3d->viewinv);
1747                 Mat3MulVecfl(mat, upvec);
1748                 VecSubf(v3d->ofs, v3d->ofs, upvec);
1749                 v3d->dist = 0.0;
1750         }
1751
1752
1753         // Apply rotation
1754         // Rotations feel relatively faster than translations only in fly mode, so
1755         // we have no choice but to fix that here (not in the plugins)
1756         rvec[0] = -0.5 * dval[3];
1757         rvec[1] = -0.5 * dval[4];
1758         rvec[2] = -0.5 * dval[5];
1759
1760         // rotate device x and y by view z
1761
1762         Mat3CpyMat4(mat, v3d->viewinv);
1763         mat[2][2] = 0.0f;
1764         Mat3MulVecfl(mat, rvec);
1765
1766         // rotate the view
1767
1768         phi = Normalize(rvec);
1769         if(phi != 0) {
1770                 VecRotToQuat(rvec,phi,q1);
1771                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
1772         }
1773
1774
1775         // Apply translation
1776
1777         tvec[0] = dval[0];
1778         tvec[1] = dval[1];
1779         tvec[2] = -dval[2];
1780
1781         // the next three lines rotate the x and y translation coordinates
1782         // by the current z axis angle
1783
1784         Mat3CpyMat4(mat, v3d->viewinv);
1785         mat[2][2] = 0.0f;
1786         Mat3MulVecfl(mat, tvec);
1787
1788         // translate the view
1789
1790         VecSubf(v3d->ofs, v3d->ofs, tvec);
1791
1792
1793         /*----------------------------------------------------
1794      * refresh the screen XXX
1795       */
1796
1797         // update render preview window
1798
1799 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
1800 }
1801
1802 void viewmoveNDOF(Scene *scene, View3D *v3d, int mode)
1803 {
1804     float fval[7];
1805     float dvec[3];
1806     float sbadjust = 1.0f;
1807     float len;
1808         short use_sel = 0;
1809         Object *ob = OBACT;
1810     float m[3][3];
1811     float m_inv[3][3];
1812     float xvec[3] = {1,0,0};
1813     float yvec[3] = {0,-1,0};
1814     float zvec[3] = {0,0,1};
1815         float phi, si;
1816     float q1[4];
1817     float obofs[3];
1818     float reverse;
1819     //float diff[4];
1820     float d, curareaX, curareaY;
1821     float mat[3][3];
1822     float upvec[3];
1823
1824     /* Sensitivity will control how fast the view rotates.  The value was
1825      * obtained experimentally by tweaking until the author didn't get dizzy watching.
1826      * Perhaps this should be a configurable user parameter.
1827      */
1828     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
1829     float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
1830     float zsens = 0.3f;   /* zoom sensitivity */
1831
1832     const float minZoom = -30.0f;
1833     const float maxZoom = 300.0f;
1834
1835         //reset view type
1836         v3d->view = 0;
1837 //printf("passing here \n");
1838 //
1839         if (scene->obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1840                 use_sel = 1;
1841         }
1842
1843     if((dz_flag)||v3d->dist==0) {
1844                 dz_flag = 0;
1845                 v3d->dist = m_dist;
1846                 upvec[0] = upvec[1] = 0;
1847                 upvec[2] = v3d->dist;
1848                 Mat3CpyMat4(mat, v3d->viewinv);
1849                 Mat3MulVecfl(mat, upvec);
1850                 VecAddf(v3d->ofs, v3d->ofs, upvec);
1851         }
1852
1853     /*----------------------------------------------------
1854          * sometimes this routine is called from headerbuttons
1855      * viewmove needs to refresh the screen
1856      */
1857 // XXX  areawinset(curarea->win);
1858
1859     /*----------------------------------------------------
1860      * record how much time has passed. clamp at 10 Hz
1861      * pretend the previous frame occured at the clamped time
1862      */
1863 //    now = PIL_check_seconds_timer();
1864  //   frametime = (now - prevTime);
1865  //   if (frametime > 0.1f){        /* if more than 1/10s */
1866  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
1867 //    }
1868 //    prevTime = now;
1869  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
1870
1871     /* fetch the current state of the ndof device & enforce dominant mode if selected */
1872 // XXX    getndof(fval);
1873         if (v3d->ndoffilter)
1874                 filterNDOFvalues(fval);
1875
1876
1877     // put scaling back here, was previously in ghostwinlay
1878     fval[0] = fval[0] * (1.0f/600.0f);
1879     fval[1] = fval[1] * (1.0f/600.0f);
1880     fval[2] = fval[2] * (1.0f/1100.0f);
1881     fval[3] = fval[3] * 0.00005f;
1882     fval[4] =-fval[4] * 0.00005f;
1883     fval[5] = fval[5] * 0.00005f;
1884     fval[6] = fval[6] / 1000000.0f;
1885
1886     // scale more if not in perspective mode
1887     if (v3d->persp == V3D_ORTHO) {
1888         fval[0] = fval[0] * 0.05f;
1889         fval[1] = fval[1] * 0.05f;
1890         fval[2] = fval[2] * 0.05f;
1891         fval[3] = fval[3] * 0.9f;
1892         fval[4] = fval[4] * 0.9f;
1893         fval[5] = fval[5] * 0.9f;
1894         zsens *= 8;
1895     }
1896
1897
1898     /* set object offset */
1899         if (ob) {
1900                 obofs[0] = -ob->obmat[3][0];
1901                 obofs[1] = -ob->obmat[3][1];
1902                 obofs[2] = -ob->obmat[3][2];
1903         }
1904         else {
1905                 VECCOPY(obofs, v3d->ofs);
1906         }
1907
1908     /* calc an adjustment based on distance from camera
1909        disabled per patch 14402 */
1910      d = 1.0f;
1911
1912 /*    if (ob) {
1913         VecSubf(diff, obofs, v3d->ofs);
1914         d = VecLength(diff);
1915     }
1916 */
1917
1918     reverse = (v3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1919
1920     /*----------------------------------------------------
1921      * ndof device pan
1922      */
1923     psens *= 1.0f + d;
1924     curareaX = sbadjust * psens * fval[0];
1925     curareaY = sbadjust * psens * fval[1];
1926     dvec[0] = curareaX * v3d->persinv[0][0] + curareaY * v3d->persinv[1][0];
1927     dvec[1] = curareaX * v3d->persinv[0][1] + curareaY * v3d->persinv[1][1];
1928     dvec[2] = curareaX * v3d->persinv[0][2] + curareaY * v3d->persinv[1][2];
1929     VecAddf(v3d->ofs, v3d->ofs, dvec);
1930
1931     /*----------------------------------------------------
1932      * ndof device dolly
1933      */
1934     len = zsens * sbadjust * fval[2];
1935
1936     if (v3d->persp==V3D_CAMOB) {
1937         if(v3d->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1938             v3d->camzoom+= 10.0f * -len;
1939         }
1940         if (v3d->camzoom < minZoom) v3d->camzoom = minZoom;
1941         else if (v3d->camzoom > maxZoom) v3d->camzoom = maxZoom;
1942     }
1943     else if ((v3d->dist> 0.001*v3d->grid) && (v3d->dist<10.0*v3d->far)) {
1944         v3d->dist*=(1.0 + len);
1945     }
1946
1947
1948     /*----------------------------------------------------
1949      * ndof device turntable
1950      * derived from the turntable code in viewmove
1951      */
1952
1953     /* Get the 3x3 matrix and its inverse from the quaternion */
1954     QuatToMat3(v3d->viewquat, m);
1955     Mat3Inv(m_inv,m);
1956
1957     /* Determine the direction of the x vector (for rotating up and down) */
1958     /* This can likely be compuated directly from the quaternion. */
1959     Mat3MulVecfl(m_inv,xvec);
1960     Mat3MulVecfl(m_inv,yvec);
1961     Mat3MulVecfl(m_inv,zvec);
1962
1963     /* Perform the up/down rotation */
1964     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1965     si = sin(phi);
1966     q1[0] = cos(phi);
1967     q1[1] = si * xvec[0];
1968     q1[2] = si * xvec[1];
1969     q1[3] = si * xvec[2];
1970     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1971
1972     if (use_sel) {
1973         QuatConj(q1); /* conj == inv for unit quat */
1974         VecSubf(v3d->ofs, v3d->ofs, obofs);
1975         QuatMulVecf(q1, v3d->ofs);
1976         VecAddf(v3d->ofs, v3d->ofs, obofs);
1977     }
1978
1979     /* Perform the orbital rotation */
1980     /* Perform the orbital rotation
1981        If the seen Up axis is parallel to the zoom axis, rotation should be
1982        achieved with a pure Roll motion (no Spin) on the device. When you start
1983        to tilt, moving from Top to Side view, Spinning will increasingly become
1984        more relevant while the Roll component will decrease. When a full
1985        Side view is reached, rotations around the world's Up axis are achieved
1986        with a pure Spin-only motion.  In other words the control of the spinning
1987        around the world's Up axis should move from the device's Spin axis to the
1988        device's Roll axis depending on the orientation of the world's Up axis
1989        relative to the screen. */
1990     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
1991     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
1992     q1[0] = cos(phi);
1993     q1[1] = q1[2] = 0.0;
1994     q1[3] = sin(phi);
1995     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1996
1997     if (use_sel) {
1998         QuatConj(q1);
1999         VecSubf(v3d->ofs, v3d->ofs, obofs);
2000         QuatMulVecf(q1, v3d->ofs);
2001         VecAddf(v3d->ofs, v3d->ofs, obofs);
2002     }
2003
2004     /*----------------------------------------------------
2005      * refresh the screen
2006      */
2007 // XXX    scrarea_do_windraw(curarea);
2008 }
2009
2010
2011
2012