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