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