A few new mouse navigation config options to help transitioning users
[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_math.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] = {0.0f, 0.0f, 0.0f};
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, RV3D_VIEW_TOP, RV3D_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, RV3D_VIEW_FRONT, RV3D_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         normal_tri_v3( clip[0],bb->vec[0], bb->vec[1], bb->vec[4]);
145         normal_tri_v3( clip[1],bb->vec[1], bb->vec[2], bb->vec[5]);
146         normal_tri_v3( clip[2],bb->vec[2], bb->vec[3], bb->vec[6]);
147         normal_tri_v3( clip[3],bb->vec[3], bb->vec[0], bb->vec[7]);
148         normal_tri_v3( clip[4],bb->vec[4], bb->vec[5], bb->vec[6]);
149         normal_tri_v3( clip[5],bb->vec[0], bb->vec[2], bb->vec[1]);
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, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ) {
185                                         if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
186                                                 rv3dtest->ofs[0]= rv3d->ofs[0];
187                                         else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
188                                                 rv3dtest->ofs[1]= rv3d->ofs[1];
189                                 }
190                                 else if( ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK) ) {
191                                         if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
192                                                 rv3dtest->ofs[0]= rv3d->ofs[0];
193                                         else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
194                                                 rv3dtest->ofs[2]= rv3d->ofs[2];
195                                 }
196                                 else if( ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ) {
197                                         if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
198                                                 rv3dtest->ofs[1]= rv3d->ofs[1];
199                                         if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_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                 mul_v3_fl(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, RV3D_VIEW_FRONT, 0},  //front
329 {0.0, 0.0, -SIN45, -SIN45, RV3D_VIEW_BACK, 0}, //back
330 {1.0, 0.0, 0.0, 0.0, RV3D_VIEW_TOP, 0},       //top
331 {0.0, -1.0, 0.0, 0.0, RV3D_VIEW_BOTTOM, 0},      //bottom
332 {0.5, -0.5, -0.5, -0.5, RV3D_VIEW_LEFT, 0},    //left
333 {0.5, -0.5, 0.5, 0.5, RV3D_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                 sub_v3_v3v3(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                 cross_v3_v3v3(q1+1, vod->trackvec, newvec);
431                 normalize_v3(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                 mul_qt_qtqt(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                         conjugate_qt(q1);
456                         mul_qt_qtqt(q1, q1, rv3d->viewquat);
457
458                         conjugate_qt(q1); /* conj == inv for unit quat */
459                         VECCOPY(rv3d->ofs, vod->ofs);
460                         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->obofs);
461                         mul_qt_v3(q1, rv3d->ofs);
462                         add_v3_v3v3(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                 quat_to_mat3( m,rv3d->viewquat);
479                 invert_m3_m3(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                 mul_m3_v3(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                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
493
494                 if (use_sel) {
495                         conjugate_qt(q1); /* conj == inv for unit quat */
496                         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->obofs);
497                         mul_qt_v3(q1, rv3d->ofs);
498                         add_v3_v3v3(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                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
507
508                 if (use_sel) {
509                         conjugate_qt(q1);
510                         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->obofs);
511                         mul_qt_v3(q1, rv3d->ofs);
512                         add_v3_v3v3(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                 quat_to_mat3( viewmat,rv3d->viewquat);
523
524                 for (i = 0 ; i < 39; i++){
525                         float snapmat[3][3];
526                         float view = (int)snapquats[i][4];
527
528                         quat_to_mat3( snapmat,snapquats[i]);
529
530                         if ((dot_v3v3(snapmat[0], viewmat[0]) > thres) &&
531                                 (dot_v3v3(snapmat[1], viewmat[1]) > thres) &&
532                                 (dot_v3v3(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 != RV3D_PERSP) {
605
606                 if (U.uiflag & USER_AUTOPERSP)
607                         vod->rv3d->persp= RV3D_PERSP;
608                 else if(vod->rv3d->persp==RV3D_CAMOB)
609                         vod->rv3d->persp= RV3D_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==RV3D_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                 add_v3_v3v3(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, len2;
855                 
856                 if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
857                         len1 = (vod->ar->winrct.xmax - x) + 5;
858                         len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
859                 }
860                 else {
861                         len1 = (vod->ar->winrct.ymax - y) + 5;
862                         len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
863                 }
864                 if (U.uiflag & USER_ZOOM_INVERT)
865                         SWAP(float, len1, len2);
866                 
867                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->rv3d->dist;
868         }
869
870         if(zfac != 1.0 && zfac*vod->rv3d->dist > 0.001*vod->grid &&
871                                 zfac*vod->rv3d->dist < 10.0*vod->far)
872                 view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
873
874
875         if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
876                 float upvec[3], mat[3][3];
877
878                 /* Secret apricot feature, translate the view when in continues mode */
879                 upvec[0] = upvec[1] = 0.0f;
880                 upvec[2] = (vod->dist0 - vod->rv3d->dist) * vod->grid;
881                 vod->rv3d->dist = vod->dist0;
882                 copy_m3_m4(mat, vod->rv3d->viewinv);
883                 mul_m3_v3(mat, upvec);
884                 add_v3_v3v3(vod->rv3d->ofs, vod->rv3d->ofs, upvec);
885         } else {
886                 /* these limits were in old code too */
887                 if(vod->rv3d->dist<0.001*vod->grid) vod->rv3d->dist= 0.001*vod->grid;
888                 if(vod->rv3d->dist>10.0*vod->far) vod->rv3d->dist=10.0*vod->far;
889         }
890
891 // XXX  if(vod->rv3d->persp==RV3D_ORTHO || vod->rv3d->persp==RV3D_CAMOB) preview3d_event= 0;
892
893         if(vod->rv3d->viewlock & RV3D_BOXVIEW)
894                 view3d_boxview_sync(vod->sa, vod->ar);
895
896         ED_region_tag_redraw(vod->ar);
897 }
898
899
900 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
901 {
902         ViewOpsData *vod= op->customdata;
903         short event_code= VIEW_PASS;
904
905         /* execute the events */
906         if(event->type==MOUSEMOVE) {
907                 event_code= VIEW_APPLY;
908         }
909         else if(event->type==EVT_MODAL_MAP) {
910                 switch (event->val) {
911                         case VIEW_MODAL_CONFIRM:
912                                 event_code= VIEW_CONFIRM;
913                                 break;
914                 }
915         }
916         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
917                 event_code= VIEW_CONFIRM;
918         }
919
920         if(event_code==VIEW_APPLY) {
921                 viewzoom_apply(vod, event->x, event->y);
922         }
923         else if (event_code==VIEW_CONFIRM) {
924                 request_depth_update(CTX_wm_region_view3d(C));
925
926                 MEM_freeN(vod);
927                 op->customdata= NULL;
928
929                 return OPERATOR_FINISHED;
930         }
931
932         return OPERATOR_RUNNING_MODAL;
933 }
934
935 static int viewzoom_exec(bContext *C, wmOperator *op)
936 {
937         View3D *v3d = CTX_wm_view3d(C);
938         RegionView3D *rv3d= CTX_wm_region_view3d(C);
939         int delta= RNA_int_get(op->ptr, "delta");
940         int mx = RNA_int_get(op->ptr, "mx");
941         int my = RNA_int_get(op->ptr, "my");
942
943         if(delta < 0) {
944                 /* this min and max is also in viewmove() */
945                 if(rv3d->persp==RV3D_CAMOB) {
946                         rv3d->camzoom-= 10;
947                         if(rv3d->camzoom<-30) rv3d->camzoom= -30;
948                 }
949                 else if(rv3d->dist<10.0*v3d->far) {
950                         view_zoom_mouseloc(CTX_wm_region(C), 1.2f, mx, my);
951                 }
952         }
953         else {
954                 if(rv3d->persp==RV3D_CAMOB) {
955                         rv3d->camzoom+= 10;
956                         if(rv3d->camzoom>300) rv3d->camzoom= 300;
957                 }
958                 else if(rv3d->dist> 0.001*v3d->grid) {
959                         view_zoom_mouseloc(CTX_wm_region(C), .83333f, mx, my);
960                 }
961         }
962
963         if(rv3d->viewlock & RV3D_BOXVIEW)
964                 view3d_boxview_sync(CTX_wm_area(C), CTX_wm_region(C));
965
966         request_depth_update(CTX_wm_region_view3d(C));
967         ED_region_tag_redraw(CTX_wm_region(C));
968
969         return OPERATOR_FINISHED;
970 }
971
972 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
973 {
974         int delta= RNA_int_get(op->ptr, "delta");
975         
976         /* if one or the other zoom position aren't set, set from event */
977         if (!RNA_property_is_set(op->ptr, "mx") || !RNA_property_is_set(op->ptr, "my"))
978         {
979                 RNA_int_set(op->ptr, "mx", event->x);
980                 RNA_int_set(op->ptr, "my", event->y);
981         }
982
983         if(delta) {
984                 viewzoom_exec(C, op);
985         }
986         else {
987                 /* makes op->customdata */
988                 viewops_data(C, op, event);
989
990                 /* add temp handler */
991                 WM_event_add_modal_handler(C, op);
992
993                 return OPERATOR_RUNNING_MODAL;
994         }
995         return OPERATOR_FINISHED;
996 }
997
998
999 void VIEW3D_OT_zoom(wmOperatorType *ot)
1000 {
1001         /* identifiers */
1002         ot->name= "Zoom view";
1003         ot->description = "Zoom in/out in the view.";
1004         ot->idname= "VIEW3D_OT_zoom";
1005
1006         /* api callbacks */
1007         ot->invoke= viewzoom_invoke;
1008         ot->exec= viewzoom_exec;
1009         ot->modal= viewzoom_modal;
1010         ot->poll= ED_operator_view3d_active;
1011
1012         /* flags */
1013         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1014
1015         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1016         RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
1017         RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
1018 }
1019
1020 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1021 {
1022         ARegion *ar= CTX_wm_region(C);
1023         View3D *v3d = CTX_wm_view3d(C);
1024         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1025         Scene *scene= CTX_data_scene(C);
1026         Base *base;
1027         float *curs;
1028
1029         int center= RNA_boolean_get(op->ptr, "center");
1030
1031         float size, min[3], max[3], afm[3];
1032         int ok= 1, onedone=0;
1033
1034         if(center) {
1035                 min[0]= min[1]= min[2]= 0.0f;
1036                 max[0]= max[1]= max[2]= 0.0f;
1037
1038                 /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
1039                 curs= give_cursor(scene, v3d);
1040                 curs[0]= curs[1]= curs[2]= 0.0;
1041         }
1042         else {
1043                 INIT_MINMAX(min, max);
1044         }
1045
1046         for(base= scene->base.first; base; base= base->next) {
1047                 if(base->lay & v3d->lay) {
1048                         onedone= 1;
1049                         minmax_object(base->object, min, max);
1050                 }
1051         }
1052         if(!onedone) return OPERATOR_FINISHED; /* TODO - should this be cancel? */
1053
1054         afm[0]= (max[0]-min[0]);
1055         afm[1]= (max[1]-min[1]);
1056         afm[2]= (max[2]-min[2]);
1057         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
1058         if(size==0.0) ok= 0;
1059
1060         if(ok) {
1061                 float new_dist;
1062                 float new_ofs[3];
1063
1064                 new_dist = size;
1065                 new_ofs[0]= -(min[0]+max[0])/2.0f;
1066                 new_ofs[1]= -(min[1]+max[1])/2.0f;
1067                 new_ofs[2]= -(min[2]+max[2])/2.0f;
1068
1069                 // correction for window aspect ratio
1070                 if(ar->winy>2 && ar->winx>2) {
1071                         size= (float)ar->winx/(float)ar->winy;
1072                         if(size<1.0) size= 1.0f/size;
1073                         new_dist*= size;
1074                 }
1075
1076                 if (rv3d->persp==RV3D_CAMOB) {
1077                         rv3d->persp= RV3D_PERSP;
1078                         smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL);
1079                 }
1080         else {
1081             smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1082         }
1083         }
1084 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1085
1086         if(rv3d->viewlock & RV3D_BOXVIEW)
1087                 view3d_boxview_copy(CTX_wm_area(C), ar);
1088
1089         return OPERATOR_FINISHED;
1090 }
1091
1092 void VIEW3D_OT_view_all(wmOperatorType *ot)
1093 {
1094         /* identifiers */
1095         ot->name= "View All";
1096         ot->description = "View all objects in scene.";
1097         ot->idname= "VIEW3D_OT_view_all";
1098
1099         /* api callbacks */
1100         ot->exec= viewhome_exec;
1101         ot->poll= ED_operator_view3d_active;
1102
1103         /* flags */
1104         ot->flag= 0;
1105
1106         RNA_def_boolean(ot->srna, "center", 0, "Center", "");
1107 }
1108
1109 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
1110 {
1111         ARegion *ar= CTX_wm_region(C);
1112         View3D *v3d = CTX_wm_view3d(C);
1113         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1114         Scene *scene= CTX_data_scene(C);
1115         Object *ob= OBACT;
1116         Object *obedit= CTX_data_edit_object(C);
1117         float size, min[3], max[3], afm[3];
1118         int ok=0;
1119
1120         /* SMOOTHVIEW */
1121         float new_ofs[3];
1122         float new_dist;
1123
1124         INIT_MINMAX(min, max);
1125
1126         if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
1127                 /* hardcoded exception, we look for the one selected armature */
1128                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1129                 Base *base;
1130                 for(base=scene->base.first; base; base= base->next) {
1131                         if(TESTBASELIB(v3d, base)) {
1132                                 if(base->object->type==OB_ARMATURE)
1133                                         if(base->object->mode & OB_MODE_POSE)
1134                                                 break;
1135                         }
1136                 }
1137                 if(base)
1138                         ob= base->object;
1139         }
1140
1141
1142         if(obedit) {
1143                 ok = minmax_verts(obedit, min, max);    /* only selected */
1144         }
1145         else if(ob && (ob->mode & OB_MODE_POSE)) {
1146                 if(ob->pose) {
1147                         bArmature *arm= ob->data;
1148                         bPoseChannel *pchan;
1149                         float vec[3];
1150
1151                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1152                                 if(pchan->bone->flag & BONE_SELECTED) {
1153                                         if(pchan->bone->layer & arm->layer) {
1154                                                 ok= 1;
1155                                                 VECCOPY(vec, pchan->pose_head);
1156                                                 mul_m4_v3(ob->obmat, vec);
1157                                                 DO_MINMAX(vec, min, max);
1158                                                 VECCOPY(vec, pchan->pose_tail);
1159                                                 mul_m4_v3(ob->obmat, vec);
1160                                                 DO_MINMAX(vec, min, max);
1161                                         }
1162                                 }
1163                         }
1164                 }
1165         }
1166         else if (paint_facesel_test(ob)) {
1167 // XXX          ok= minmax_tface(min, max);
1168         }
1169         else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1170                 ok= PE_minmax(scene, min, max);
1171         }
1172         else {
1173                 Base *base= FIRSTBASE;
1174                 while(base) {
1175                         if(TESTBASE(v3d, base))  {
1176                                 minmax_object(base->object, min, max);
1177                                 /* account for duplis */
1178                                 minmax_object_duplis(scene, base->object, min, max);
1179
1180                                 ok= 1;
1181                         }
1182                         base= base->next;
1183                 }
1184         }
1185
1186         if(ok==0) return OPERATOR_FINISHED;
1187
1188         afm[0]= (max[0]-min[0]);
1189         afm[1]= (max[1]-min[1]);
1190         afm[2]= (max[2]-min[2]);
1191         size= MAX3(afm[0], afm[1], afm[2]);
1192         /* perspective should be a bit farther away to look nice */
1193         if(rv3d->persp==RV3D_ORTHO)
1194                 size*= 0.7;
1195
1196         if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
1197
1198         new_ofs[0]= -(min[0]+max[0])/2.0f;
1199         new_ofs[1]= -(min[1]+max[1])/2.0f;
1200         new_ofs[2]= -(min[2]+max[2])/2.0f;
1201
1202         new_dist = size;
1203
1204         /* correction for window aspect ratio */
1205         if(ar->winy>2 && ar->winx>2) {
1206                 size= (float)ar->winx/(float)ar->winy;
1207                 if(size<1.0f) size= 1.0f/size;
1208                 new_dist*= size;
1209         }
1210
1211         v3d->cursor[0]= -new_ofs[0];
1212         v3d->cursor[1]= -new_ofs[1];
1213         v3d->cursor[2]= -new_ofs[2];
1214
1215         if (rv3d->persp==RV3D_CAMOB) {
1216                 rv3d->persp= RV3D_PERSP;
1217                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1218         }
1219         else {
1220                 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1221         }
1222
1223 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1224         if(rv3d->viewlock & RV3D_BOXVIEW)
1225                 view3d_boxview_copy(CTX_wm_area(C), ar);
1226
1227         return OPERATOR_FINISHED;
1228 }
1229
1230 void VIEW3D_OT_view_center(wmOperatorType *ot)
1231 {
1232
1233         /* identifiers */
1234         ot->name= "View Selected";
1235         ot->description = "Move the view to the selection center.";
1236         ot->idname= "VIEW3D_OT_view_center";
1237
1238         /* api callbacks */
1239         ot->exec= viewcenter_exec;
1240         ot->poll= ED_operator_view3d_active;
1241
1242         /* flags */
1243         ot->flag= 0;
1244 }
1245
1246 static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
1247 {
1248         View3D *v3d = CTX_wm_view3d(C);
1249         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1250         Scene *scene= CTX_data_scene(C);
1251         
1252         if (rv3d) {
1253                 if (rv3d->persp==RV3D_CAMOB) {
1254                         /* center the camera offset */
1255                         rv3d->camdx= rv3d->camdy= 0.0;
1256                 }
1257                 else {
1258                         /* non camera center */
1259                         float *curs= give_cursor(scene, v3d);
1260                         float new_ofs[3];
1261                         
1262                         new_ofs[0]= -curs[0];
1263                         new_ofs[1]= -curs[1];
1264                         new_ofs[2]= -curs[2];
1265                         
1266                         smooth_view(C, NULL, NULL, new_ofs, NULL, NULL, NULL);
1267                 }
1268                 
1269                 if (rv3d->viewlock & RV3D_BOXVIEW)
1270                         view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
1271         }
1272         
1273         return OPERATOR_FINISHED;
1274 }
1275
1276 void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
1277 {
1278         /* identifiers */
1279         ot->name= "Center View to Cursor";
1280         ot->description= "Centers the view so that the cursor is in the middle of the view.";
1281         ot->idname= "VIEW3D_OT_view_center_cursor";
1282         
1283         /* api callbacks */
1284         ot->exec= viewcenter_cursor_exec;
1285         ot->poll= ED_operator_view3d_active;
1286         
1287         /* flags */
1288         ot->flag= 0;
1289 }
1290
1291 /* ********************* Set render border operator ****************** */
1292
1293 static int render_border_exec(bContext *C, wmOperator *op)
1294 {
1295         View3D *v3d = CTX_wm_view3d(C);
1296         ARegion *ar= CTX_wm_region(C);
1297         Scene *scene= CTX_data_scene(C);
1298
1299         rcti rect;
1300         rctf vb;
1301
1302         /* get border select values using rna */
1303         rect.xmin= RNA_int_get(op->ptr, "xmin");
1304         rect.ymin= RNA_int_get(op->ptr, "ymin");
1305         rect.xmax= RNA_int_get(op->ptr, "xmax");
1306         rect.ymax= RNA_int_get(op->ptr, "ymax");
1307
1308         /* calculate range */
1309         calc_viewborder(scene, ar, v3d, &vb);
1310
1311         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1312         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1313         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1314         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1315
1316         /* actually set border */
1317         CLAMP(scene->r.border.xmin, 0.0, 1.0);
1318         CLAMP(scene->r.border.ymin, 0.0, 1.0);
1319         CLAMP(scene->r.border.xmax, 0.0, 1.0);
1320         CLAMP(scene->r.border.ymax, 0.0, 1.0);
1321
1322         /* drawing a border surrounding the entire camera view switches off border rendering
1323          * or the border covers no pixels */
1324         if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1325                 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1326            (scene->r.border.xmin == scene->r.border.xmax ||
1327                 scene->r.border.ymin == scene->r.border.ymax ))
1328         {
1329                 scene->r.mode &= ~R_BORDER;
1330         } else {
1331                 scene->r.mode |= R_BORDER;
1332         }
1333
1334         return OPERATOR_FINISHED;
1335
1336 }
1337
1338 static int view3d_render_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1339 {
1340         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1341
1342         /* if not in camera view do not exec the operator*/
1343         if (rv3d->persp == RV3D_CAMOB) return WM_border_select_invoke(C, op, event);
1344         else return OPERATOR_PASS_THROUGH;
1345 }
1346
1347 void VIEW3D_OT_render_border(wmOperatorType *ot)
1348 {
1349         /* identifiers */
1350         ot->name= "Set Render Border";
1351         ot->description = "Set the boundries of the border render and enables border render .";
1352         ot->idname= "VIEW3D_OT_render_border";
1353
1354         /* api callbacks */
1355         ot->invoke= view3d_render_border_invoke;
1356         ot->exec= render_border_exec;
1357         ot->modal= WM_border_select_modal;
1358
1359         ot->poll= ED_operator_view3d_active;
1360
1361         /* flags */
1362         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1363
1364         /* rna */
1365         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1366         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1367         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1368         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1369
1370 }
1371 /* ********************* Border Zoom operator ****************** */
1372
1373 static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
1374 {
1375         ARegion *ar= CTX_wm_region(C);
1376         View3D *v3d = CTX_wm_view3d(C);
1377         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1378         Scene *scene= CTX_data_scene(C);
1379
1380         /* Zooms in on a border drawn by the user */
1381         rcti rect;
1382         float dvec[3], vb[2], xscale, yscale, scale;
1383
1384         /* SMOOTHVIEW */
1385         float new_dist;
1386         float new_ofs[3];
1387
1388         /* ZBuffer depth vars */
1389         bglMats mats;
1390         float depth, depth_close= MAXFLOAT;
1391         int had_depth = 0;
1392         double cent[2],  p[3];
1393         int xs, ys;
1394
1395         /* note; otherwise opengl won't work */
1396         view3d_operator_needs_opengl(C);
1397
1398         /* get border select values using rna */
1399         rect.xmin= RNA_int_get(op->ptr, "xmin");
1400         rect.ymin= RNA_int_get(op->ptr, "ymin");
1401         rect.xmax= RNA_int_get(op->ptr, "xmax");
1402         rect.ymax= RNA_int_get(op->ptr, "ymax");
1403
1404         /* Get Z Depths, needed for perspective, nice for ortho */
1405         bgl_get_mats(&mats);
1406         draw_depth(scene, ar, v3d, NULL);
1407
1408         /* force updating */
1409         if (rv3d->depths) {
1410                 had_depth = 1;
1411                 rv3d->depths->damaged = 1;
1412         }
1413
1414         view3d_update_depths(ar, v3d);
1415
1416         /* Constrain rect to depth bounds */
1417         if (rect.xmin < 0) rect.xmin = 0;
1418         if (rect.ymin < 0) rect.ymin = 0;
1419         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1420         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1421
1422         /* Find the closest Z pixel */
1423         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1424                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1425                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1426                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1427                                 if (depth_close > depth) {
1428                                         depth_close = depth;
1429                                 }
1430                         }
1431                 }
1432         }
1433
1434         if (had_depth==0) {
1435                 MEM_freeN(rv3d->depths->depths);
1436                 rv3d->depths->depths = NULL;
1437         }
1438         rv3d->depths->damaged = 1;
1439
1440         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1441         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1442
1443         if (rv3d->persp==RV3D_PERSP) {
1444                 double p_corner[3];
1445
1446                 /* no depths to use, we cant do anything! */
1447                 if (depth_close==MAXFLOAT){
1448                         BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1449                         return OPERATOR_CANCELLED;
1450                 }
1451                 /* convert border to 3d coordinates */
1452                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1453                         (       !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])))
1454                         return OPERATOR_CANCELLED;
1455
1456                 dvec[0] = p[0]-p_corner[0];
1457                 dvec[1] = p[1]-p_corner[1];
1458                 dvec[2] = p[2]-p_corner[2];
1459
1460                 new_dist = len_v3(dvec);
1461                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1462
1463                 new_ofs[0] = -p[0];
1464                 new_ofs[1] = -p[1];
1465                 new_ofs[2] = -p[2];
1466
1467         } else { /* othographic */
1468                 /* find the current window width and height */
1469                 vb[0] = ar->winx;
1470                 vb[1] = ar->winy;
1471
1472                 new_dist = rv3d->dist;
1473
1474                 /* convert the drawn rectangle into 3d space */
1475                 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1476                         new_ofs[0] = -p[0];
1477                         new_ofs[1] = -p[1];
1478                         new_ofs[2] = -p[2];
1479                 } else {
1480                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1481                         new_ofs[0] = rv3d->ofs[0];
1482                         new_ofs[1] = rv3d->ofs[1];
1483                         new_ofs[2] = rv3d->ofs[2];
1484
1485                         initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1486
1487                         window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1488                         /* center the view to the center of the rectangle */
1489                         sub_v3_v3v3(new_ofs, new_ofs, dvec);
1490                 }
1491
1492                 /* work out the ratios, so that everything selected fits when we zoom */
1493                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1494                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1495                 scale = (xscale >= yscale)?xscale:yscale;
1496
1497                 /* zoom in as required, or as far as we can go */
1498                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1499         }
1500
1501         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1502
1503         if(rv3d->viewlock & RV3D_BOXVIEW)
1504                 view3d_boxview_sync(CTX_wm_area(C), ar);
1505
1506         return OPERATOR_FINISHED;
1507 }
1508
1509 static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1510 {
1511         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1512
1513         /* if in camera view do not exec the operator so we do not conflict with set render border*/
1514         if (rv3d->persp != RV3D_CAMOB)
1515                 return WM_border_select_invoke(C, op, event);
1516         else
1517                 return OPERATOR_PASS_THROUGH;
1518 }
1519
1520 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1521 {
1522
1523         /* identifiers */
1524         ot->name= "Border Zoom";
1525         ot->description = "Zoom in the view to the nearest object contained in the border.";
1526         ot->idname= "VIEW3D_OT_zoom_border";
1527
1528         /* api callbacks */
1529         ot->invoke= view3d_zoom_border_invoke;
1530         ot->exec= view3d_zoom_border_exec;
1531         ot->modal= WM_border_select_modal;
1532
1533         ot->poll= ED_operator_view3d_active;
1534
1535         /* flags */
1536         ot->flag= 0;
1537
1538         /* rna */
1539         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1540         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1541         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1542         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1543
1544 }
1545 /* ********************* Changing view operator ****************** */
1546
1547 static EnumPropertyItem prop_view_items[] = {
1548         {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1549         {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1550         {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1551         {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1552         {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1553         {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1554         {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1555         {0, NULL, 0, NULL, NULL}};
1556
1557
1558 /* would like to make this a generic function - outside of transform */
1559
1560 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo, int align_active)
1561 {
1562         View3D *v3d = CTX_wm_view3d(C);
1563         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1564         float new_quat[4];
1565
1566         new_quat[0]= q1; new_quat[1]= q2;
1567         new_quat[2]= q3; new_quat[3]= q4;
1568
1569         if(align_active) {
1570                 /* align to active object */
1571                 Object *obact= CTX_data_active_object(C);
1572                 if (obact==NULL) {
1573                         /* no active object, ignore this option */
1574                         align_active= FALSE;
1575                 }
1576                 else {
1577                         float obact_quat[4];
1578                         float twmat[3][3];
1579
1580                         /* same as transform manipulator when normal is set */
1581                         ED_getTransformOrientationMatrix(C, twmat, TRUE);
1582
1583                         mat3_to_quat( obact_quat,twmat);
1584                         invert_qt(obact_quat);
1585                         mul_qt_qtqt(new_quat, new_quat, obact_quat);
1586
1587                         rv3d->view= view= 0;
1588                 }
1589         }
1590
1591         if(align_active==FALSE) {
1592                 /* normal operation */
1593                 if(rv3d->viewlock) {
1594                         /* only pass on if */
1595                         if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
1596                         else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
1597                         else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
1598                         else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
1599                         else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
1600                         else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
1601                         else return;
1602                 }
1603
1604                 rv3d->view= view;
1605         }
1606
1607         if(rv3d->viewlock) {
1608                 ED_region_tag_redraw(CTX_wm_region(C));
1609                 return;
1610         }
1611
1612         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1613
1614                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1615                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1616
1617                 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1618         }
1619         else {
1620
1621                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1622                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1623
1624                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1625         }
1626
1627 }
1628
1629 static int viewnumpad_exec(bContext *C, wmOperator *op)
1630 {
1631         View3D *v3d = CTX_wm_view3d(C);
1632         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1633         Scene *scene= CTX_data_scene(C);
1634         static int perspo=RV3D_PERSP;
1635         int viewnum, align_active;
1636
1637         viewnum = RNA_enum_get(op->ptr, "type");
1638         align_active = RNA_boolean_get(op->ptr, "align_active");
1639
1640         /* Use this to test if we started out with a camera */
1641
1642         switch (viewnum) {
1643                 case RV3D_VIEW_BOTTOM :
1644                         axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, perspo, align_active);
1645                         break;
1646
1647                 case RV3D_VIEW_BACK:
1648                         axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, perspo, align_active);
1649                         break;
1650
1651                 case RV3D_VIEW_LEFT:
1652                         axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, perspo, align_active);
1653                         break;
1654
1655                 case RV3D_VIEW_TOP:
1656                         axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, perspo, align_active);
1657                         break;
1658
1659                 case RV3D_VIEW_FRONT:
1660                         axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, perspo, align_active);
1661                         break;
1662
1663                 case RV3D_VIEW_RIGHT:
1664                         axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, perspo, align_active);
1665                         break;
1666
1667                 case RV3D_VIEW_CAMERA:
1668                         if(rv3d->viewlock==0) {
1669                                 /* lastview -  */
1670
1671                                 if(rv3d->persp != RV3D_CAMOB) {
1672                                         /* store settings of current view before allowing overwriting with camera view */
1673                                         QUATCOPY(rv3d->lviewquat, rv3d->viewquat);
1674                                         rv3d->lview= rv3d->view;
1675                                         rv3d->lpersp= rv3d->persp;
1676
1677         #if 0
1678                                         if(G.qual==LR_ALTKEY) {
1679                                                 if(oldcamera && is_an_active_object(oldcamera)) {
1680                                                         v3d->camera= oldcamera;
1681                                                 }
1682                                                 handle_view3d_lock();
1683                                         }
1684         #endif
1685
1686                                         if(BASACT) {
1687                                                 /* check both G.vd as G.scene cameras */
1688                                                 if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1689                                                         v3d->camera= OBACT;
1690                                                         /*handle_view3d_lock();*/
1691                                                 }
1692                                         }
1693
1694                                         if(v3d->camera==NULL) {
1695                                                 v3d->camera= scene_find_camera(scene);
1696                                                 /*handle_view3d_lock();*/
1697                                         }
1698                                         rv3d->persp= RV3D_CAMOB;
1699                                         smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
1700
1701                                 }
1702                                 else{
1703                                         /* return to settings of last view */
1704                                         /* does smooth_view too */
1705                                         axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
1706                                 }
1707                         }
1708                         break;
1709
1710                 default :
1711                         break;
1712         }
1713
1714         if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
1715
1716         return OPERATOR_FINISHED;
1717 }
1718 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1719 {
1720         /* identifiers */
1721         ot->name= "View numpad";
1722         ot->description = "Set the view.";
1723         ot->idname= "VIEW3D_OT_viewnumpad";
1724
1725         /* api callbacks */
1726         ot->exec= viewnumpad_exec;
1727         ot->poll= ED_operator_view3d_active;
1728
1729         /* flags */
1730         ot->flag= 0;
1731
1732         RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
1733         RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
1734 }
1735
1736 static EnumPropertyItem prop_view_orbit_items[] = {
1737         {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
1738         {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
1739         {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
1740         {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
1741         {0, NULL, 0, NULL, NULL}};
1742
1743 static int vieworbit_exec(bContext *C, wmOperator *op)
1744 {
1745         ARegion *ar= CTX_wm_region(C);
1746         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1747         float phi, si, q1[4];
1748         int orbitdir;
1749
1750         orbitdir = RNA_enum_get(op->ptr, "type");
1751
1752         if(rv3d->viewlock==0) {
1753
1754                 if(rv3d->persp != RV3D_CAMOB) {
1755                         if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
1756                                 /* z-axis */
1757                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1758                                 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
1759                                 si= (float)sin(phi);
1760                                 q1[0]= (float)cos(phi);
1761                                 q1[1]= q1[2]= 0.0;
1762                                 q1[3]= si;
1763                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
1764                                 rv3d->view= 0;
1765                         }
1766                         if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
1767                                 /* horizontal axis */
1768                                 VECCOPY(q1+1, rv3d->viewinv[0]);
1769
1770                                 normalize_v3(q1+1);
1771                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1772                                 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
1773                                 si= (float)sin(phi);
1774                                 q1[0]= (float)cos(phi);
1775                                 q1[1]*= si;
1776                                 q1[2]*= si;
1777                                 q1[3]*= si;
1778                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
1779                                 rv3d->view= 0;
1780                         }
1781                         ED_region_tag_redraw(ar);
1782                 }
1783         }
1784
1785         return OPERATOR_FINISHED;
1786 }
1787
1788 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
1789 {
1790         /* identifiers */
1791         ot->name= "View Orbit";
1792         ot->description = "Orbit the view.";
1793         ot->idname= "VIEW3D_OT_view_orbit";
1794
1795         /* api callbacks */
1796         ot->exec= vieworbit_exec;
1797         ot->poll= ED_operator_view3d_active;
1798
1799         /* flags */
1800         ot->flag= 0;
1801         RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
1802 }
1803
1804 static EnumPropertyItem prop_view_pan_items[] = {
1805         {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
1806         {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
1807         {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
1808         {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
1809         {0, NULL, 0, NULL, NULL}};
1810
1811 static int viewpan_exec(bContext *C, wmOperator *op)
1812 {
1813         ARegion *ar= CTX_wm_region(C);
1814         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1815         float vec[3];
1816         int pandir;
1817
1818         pandir = RNA_enum_get(op->ptr, "type");
1819
1820         initgrabz(rv3d, 0.0, 0.0, 0.0);
1821
1822         if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
1823         else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
1824         else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
1825         else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
1826         rv3d->ofs[0]+= vec[0];
1827         rv3d->ofs[1]+= vec[1];
1828         rv3d->ofs[2]+= vec[2];
1829
1830         if(rv3d->viewlock & RV3D_BOXVIEW)
1831                 view3d_boxview_sync(CTX_wm_area(C), ar);
1832
1833         ED_region_tag_redraw(ar);
1834
1835         return OPERATOR_FINISHED;
1836 }
1837
1838 void VIEW3D_OT_view_pan(wmOperatorType *ot)
1839 {
1840         /* identifiers */
1841         ot->name= "View Pan";
1842         ot->description = "Pan the view.";
1843         ot->idname= "VIEW3D_OT_view_pan";
1844
1845         /* api callbacks */
1846         ot->exec= viewpan_exec;
1847         ot->poll= ED_operator_view3d_active;
1848
1849         /* flags */
1850         ot->flag= 0;
1851         RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
1852 }
1853
1854 static int viewpersportho_exec(bContext *C, wmOperator *op)
1855 {
1856         ARegion *ar= CTX_wm_region(C);
1857         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1858
1859         if(rv3d->viewlock==0) {
1860                 if(rv3d->persp!=RV3D_ORTHO)
1861                         rv3d->persp=RV3D_ORTHO;
1862                 else rv3d->persp=RV3D_PERSP;
1863                 ED_region_tag_redraw(ar);
1864         }
1865
1866         return OPERATOR_FINISHED;
1867
1868 }
1869
1870 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
1871 {
1872         /* identifiers */
1873         ot->name= "View Persp/Ortho";
1874         ot->description = "Switch the current view from perspective/orthographic.";
1875         ot->idname= "VIEW3D_OT_view_persportho";
1876
1877         /* api callbacks */
1878         ot->exec= viewpersportho_exec;
1879         ot->poll= ED_operator_view3d_active;
1880
1881         /* flags */
1882         ot->flag= 0;
1883 }
1884
1885
1886 /* ********************* set clipping operator ****************** */
1887
1888 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
1889 {
1890         int val;
1891
1892         for(val=0; val<4; val++) {
1893
1894                 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
1895
1896                 clip[val][3]=
1897                         - clip[val][0]*clipbb->vec[val][0]
1898                         - clip[val][1]*clipbb->vec[val][1]
1899                         - clip[val][2]*clipbb->vec[val][2];
1900         }
1901 }
1902
1903 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
1904 {
1905         BoundBox clipbb_local;
1906         float imat[4][4];
1907         int i;
1908
1909         invert_m4_m4(imat, mat);
1910
1911         for(i=0; i<8; i++) {
1912                 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
1913         }
1914
1915         calc_clipping_plane(clip_local, &clipbb_local);
1916 }
1917
1918 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
1919 {
1920         if(rv3d->rflag & RV3D_CLIPPING)
1921                 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
1922 }
1923
1924 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1925 {
1926         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1927         rcti rect;
1928         double mvmatrix[16];
1929         double projmatrix[16];
1930         double xs, ys, p[3];
1931         GLint viewport[4];
1932         short val;
1933
1934         rect.xmin= RNA_int_get(op->ptr, "xmin");
1935         rect.ymin= RNA_int_get(op->ptr, "ymin");
1936         rect.xmax= RNA_int_get(op->ptr, "xmax");
1937         rect.ymax= RNA_int_get(op->ptr, "ymax");
1938
1939         rv3d->rflag |= RV3D_CLIPPING;
1940         rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1941
1942         /* note; otherwise opengl won't work */
1943         view3d_operator_needs_opengl(C);
1944
1945         /* Get the matrices needed for gluUnProject */
1946         glGetIntegerv(GL_VIEWPORT, viewport);
1947         glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
1948         glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
1949
1950         /* near zero floating point values can give issues with gluUnProject
1951                 in side view on some implementations */
1952         if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
1953         if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
1954
1955         /* Set up viewport so that gluUnProject will give correct values */
1956         viewport[0] = 0;
1957         viewport[1] = 0;
1958
1959         /* four clipping planes and bounding volume */
1960         /* first do the bounding volume */
1961         for(val=0; val<4; val++) {
1962
1963                 xs= (val==0||val==3)?rect.xmin:rect.xmax;
1964                 ys= (val==0||val==1)?rect.ymin:rect.ymax;
1965
1966                 gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1967                 VECCOPY(rv3d->clipbb->vec[val], p);
1968
1969                 gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1970                 VECCOPY(rv3d->clipbb->vec[4+val], p);
1971         }
1972
1973         /* then plane equations */
1974         calc_clipping_plane(rv3d->clip, rv3d->clipbb);
1975
1976         return OPERATOR_FINISHED;
1977 }
1978
1979 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
1980 {
1981         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1982         ARegion *ar= CTX_wm_region(C);
1983
1984         if(rv3d->rflag & RV3D_CLIPPING) {
1985                 rv3d->rflag &= ~RV3D_CLIPPING;
1986                 ED_region_tag_redraw(ar);
1987                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
1988                 rv3d->clipbb= NULL;
1989                 return OPERATOR_FINISHED;
1990         }
1991         else {
1992                 return WM_border_select_invoke(C, op, event);
1993         }
1994 }
1995
1996 /* toggles */
1997 void VIEW3D_OT_clip_border(wmOperatorType *ot)
1998 {
1999
2000         /* identifiers */
2001         ot->name= "Clipping Border";
2002         ot->description = "Set the view clipping border.";
2003         ot->idname= "VIEW3D_OT_clip_border";
2004
2005         /* api callbacks */
2006         ot->invoke= view3d_clipping_invoke;
2007         ot->exec= view3d_clipping_exec;
2008         ot->modal= WM_border_select_modal;
2009
2010         ot->poll= ED_operator_view3d_active;
2011
2012         /* flags */
2013         ot->flag= 0;
2014
2015         /* rna */
2016         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2017         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2018         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2019         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2020 }
2021
2022 /* ***************** 3d cursor cursor op ******************* */
2023
2024 /* mx my in region coords */
2025 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
2026 {
2027         Scene *scene= CTX_data_scene(C);
2028         ARegion *ar= CTX_wm_region(C);
2029         View3D *v3d = CTX_wm_view3d(C);
2030         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2031         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2032         short mx, my, mval[2];
2033 //      short ctrl= 0; // XXX
2034
2035         fp= give_cursor(scene, v3d);
2036
2037 //      if(obedit && ctrl) lr_click= 1;
2038         VECCOPY(oldcurs, fp);
2039
2040         mx= event->x - ar->winrct.xmin;
2041         my= event->y - ar->winrct.ymin;
2042         project_short_noclip(ar, fp, mval);
2043
2044         initgrabz(rv3d, fp[0], fp[1], fp[2]);
2045
2046         if(mval[0]!=IS_CLIPPED) {
2047
2048                 window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2049                 sub_v3_v3v3(fp, fp, dvec);
2050         }
2051         else {
2052
2053                 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2054                 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2055
2056                 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2057                 fz= fz/rv3d->zfac;
2058
2059                 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2060                 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2061                 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2062         }
2063
2064 //      if(lr_click) {
2065                 // XXX          if(obedit->type==OB_MESH) add_click_mesh();
2066                 //              else if ELEM(obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
2067                 //              else if (obedit->type==OB_ARMATURE) addvert_armature();
2068 //              VECCOPY(fp, oldcurs);
2069 //      }
2070         // XXX notifier for scene */
2071         ED_area_tag_redraw(CTX_wm_area(C));
2072
2073         return OPERATOR_FINISHED;
2074 }
2075
2076 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2077 {
2078
2079         /* identifiers */
2080         ot->name= "Set 3D Cursor";
2081         ot->description = "Set the location of the 3D cursor.";
2082         ot->idname= "VIEW3D_OT_cursor3d";
2083
2084         /* api callbacks */
2085         ot->invoke= set_3dcursor_invoke;
2086
2087         ot->poll= ED_operator_view3d_active;
2088     
2089         /* flags */
2090         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2091     
2092         /* rna later */
2093
2094 }
2095
2096 /* ***************** manipulator op ******************* */
2097
2098
2099 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2100 {
2101         View3D *v3d = CTX_wm_view3d(C);
2102
2103         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2104         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2105
2106         /* only no modifier or shift */
2107         if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2108
2109         /* note; otherwise opengl won't work */
2110         view3d_operator_needs_opengl(C);
2111
2112         if(0==BIF_do_manipulator(C, event, op))
2113                 return OPERATOR_PASS_THROUGH;
2114
2115         return OPERATOR_FINISHED;
2116 }
2117
2118 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2119 {
2120
2121         /* identifiers */
2122         ot->name= "3D Manipulator";
2123         ot->description = "Manipulate selected item by axis.";
2124         ot->idname= "VIEW3D_OT_manipulator";
2125
2126         /* api callbacks */
2127         ot->invoke= manipulator_invoke;
2128
2129         ot->poll= ED_operator_view3d_active;
2130
2131         /* rna later */
2132         RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
2133 }
2134
2135
2136
2137 /* ************************* below the line! *********************** */
2138
2139
2140 /* XXX todo Zooms in on a border drawn by the user */
2141 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2142 {
2143         RegionView3D *rv3d= ar->regiondata;
2144         bglMats mats; /* ZBuffer depth vars */
2145         rcti rect;
2146         float depth, depth_close= MAXFLOAT;
2147         int had_depth = 0;
2148         double cent[2],  p[3];
2149         int xs, ys;
2150
2151         rect.xmax = mval[0] + 4;
2152         rect.ymax = mval[1] + 4;
2153
2154         rect.xmin = mval[0] - 4;
2155         rect.ymin = mval[1] - 4;
2156
2157         /* Get Z Depths, needed for perspective, nice for ortho */
2158         bgl_get_mats(&mats);
2159         draw_depth(scene, ar, v3d, NULL);
2160
2161         /* force updating */
2162         if (rv3d->depths) {
2163                 had_depth = 1;
2164                 rv3d->depths->damaged = 1;
2165         }
2166
2167         view3d_update_depths(ar, v3d);
2168
2169         /* Constrain rect to depth bounds */
2170         if (rect.xmin < 0) rect.xmin = 0;
2171         if (rect.ymin < 0) rect.ymin = 0;
2172         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
2173         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
2174
2175         /* Find the closest Z pixel */
2176         for (xs=rect.xmin; xs < rect.xmax; xs++) {
2177                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
2178                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
2179                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
2180                                 if (depth_close > depth) {
2181                                         depth_close = depth;
2182                                 }
2183                         }
2184                 }
2185         }
2186
2187         if (depth_close==MAXFLOAT)
2188                 return 0;
2189
2190         if (had_depth==0) {
2191                 MEM_freeN(rv3d->depths->depths);
2192                 rv3d->depths->depths = NULL;
2193         }
2194         rv3d->depths->damaged = 1;
2195
2196         cent[0] = (double)mval[0];
2197         cent[1] = (double)mval[1];
2198
2199         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2200                 return 0;
2201
2202         mouse_worldloc[0] = (float)p[0];
2203         mouse_worldloc[1] = (float)p[1];
2204         mouse_worldloc[2] = (float)p[2];
2205         return 1;
2206 }
2207
2208
2209
2210 /* ********************* NDOF ************************ */
2211 /* note: this code is confusing and unclear... (ton) */
2212 /* **************************************************** */
2213
2214 // ndof scaling will be moved to user setting.
2215 // In the mean time this is just a place holder.
2216
2217 // Note: scaling in the plugin and ghostwinlay.c
2218 // should be removed. With driver default setting,
2219 // each axis returns approx. +-200 max deflection.
2220
2221 // The values I selected are based on the older
2222 // polling i/f. With event i/f, the sensistivity
2223 // can be increased for improved response from
2224 // small deflections of the device input.
2225
2226
2227 // lukep notes : i disagree on the range.
2228 // the normal 3Dconnection driver give +/-400
2229 // on defaut range in other applications
2230 // and up to +/- 1000 if set to maximum
2231 // because i remove the scaling by delta,
2232 // which was a bad idea as it depend of the system
2233 // speed and os, i changed the scaling values, but
2234 // those are still not ok
2235
2236
2237 float ndof_axis_scale[6] = {
2238         +0.01,  // Tx
2239         +0.01,  // Tz
2240         +0.01,  // Ty
2241         +0.0015,        // Rx
2242         +0.0015,        // Rz
2243         +0.0015 // Ry
2244 };
2245
2246 void filterNDOFvalues(float *sbval)
2247 {
2248         int i=0;
2249         float max  = 0.0;
2250
2251         for (i =0; i<6;i++)
2252                 if (fabs(sbval[i]) > max)
2253                         max = fabs(sbval[i]);
2254         for (i =0; i<6;i++)
2255                 if (fabs(sbval[i]) != max )
2256                         sbval[i]=0.0;
2257 }
2258
2259 // statics for controlling rv3d->dist corrections.
2260 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2261 // viewmove restores based on dz_flag state.
2262
2263 int dz_flag = 0;
2264 float m_dist;
2265
2266 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2267 {
2268         RegionView3D *rv3d= ar->regiondata;
2269     int i;
2270     float phi;
2271     float dval[7];
2272         // static fval[6] for low pass filter; device input vector is dval[6]
2273         static float fval[6];
2274     float tvec[3],rvec[3];
2275     float q1[4];
2276         float mat[3][3];
2277         float upvec[3];
2278
2279
2280     /*----------------------------------------------------
2281          * sometimes this routine is called from headerbuttons
2282      * viewmove needs to refresh the screen
2283      */
2284 // XXX  areawinset(ar->win);
2285
2286
2287         // fetch the current state of the ndof device
2288 // XXX  getndof(dval);
2289
2290         if (v3d->ndoffilter)
2291                 filterNDOFvalues(fval);
2292
2293         // Scale input values
2294
2295 //      if(dval[6] == 0) return; // guard against divide by zero
2296
2297         for(i=0;i<6;i++) {
2298
2299                 // user scaling
2300                 dval[i] = dval[i] * ndof_axis_scale[i];
2301         }
2302
2303
2304         // low pass filter with zero crossing reset
2305
2306         for(i=0;i<6;i++) {
2307                 if((dval[i] * fval[i]) >= 0)
2308                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
2309                 else
2310                         fval[i] = 0;
2311         }
2312
2313
2314         // force perspective mode. This is a hack and is
2315         // incomplete. It doesn't actually effect the view
2316         // until the first draw and doesn't update the menu
2317         // to reflect persp mode.
2318
2319         rv3d->persp = RV3D_PERSP;
2320
2321
2322         // Correct the distance jump if rv3d->dist != 0
2323
2324         // This is due to a side effect of the original
2325         // mouse view rotation code. The rotation point is
2326         // set a distance in front of the viewport to
2327         // make rotating with the mouse look better.
2328         // The distance effect is written at a low level
2329         // in the view management instead of the mouse
2330         // view function. This means that all other view
2331         // movement devices must subtract this from their
2332         // view transformations.
2333
2334         if(rv3d->dist != 0.0) {
2335                 dz_flag = 1;
2336                 m_dist = rv3d->dist;
2337                 upvec[0] = upvec[1] = 0;
2338                 upvec[2] = rv3d->dist;
2339                 copy_m3_m4(mat, rv3d->viewinv);
2340                 mul_m3_v3(mat, upvec);
2341                 sub_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2342                 rv3d->dist = 0.0;
2343         }
2344
2345
2346         // Apply rotation
2347         // Rotations feel relatively faster than translations only in fly mode, so
2348         // we have no choice but to fix that here (not in the plugins)
2349         rvec[0] = -0.5 * dval[3];
2350         rvec[1] = -0.5 * dval[4];
2351         rvec[2] = -0.5 * dval[5];
2352
2353         // rotate device x and y by view z
2354
2355         copy_m3_m4(mat, rv3d->viewinv);
2356         mat[2][2] = 0.0f;
2357         mul_m3_v3(mat, rvec);
2358
2359         // rotate the view
2360
2361         phi = normalize_v3(rvec);
2362         if(phi != 0) {
2363                 axis_angle_to_quat(q1,rvec,phi);
2364                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2365         }
2366
2367
2368         // Apply translation
2369
2370         tvec[0] = dval[0];
2371         tvec[1] = dval[1];
2372         tvec[2] = -dval[2];
2373
2374         // the next three lines rotate the x and y translation coordinates
2375         // by the current z axis angle
2376
2377         copy_m3_m4(mat, rv3d->viewinv);
2378         mat[2][2] = 0.0f;
2379         mul_m3_v3(mat, tvec);
2380
2381         // translate the view
2382
2383         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, tvec);
2384
2385
2386         /*----------------------------------------------------
2387      * refresh the screen XXX
2388       */
2389
2390         // update render preview window
2391
2392 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2393 }
2394
2395 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2396 {
2397         RegionView3D *rv3d= ar->regiondata;
2398         float fval[7];
2399         float dvec[3];
2400         float sbadjust = 1.0f;
2401         float len;
2402         short use_sel = 0;
2403         Object *ob = OBACT;
2404         float m[3][3];
2405         float m_inv[3][3];
2406         float xvec[3] = {1,0,0};
2407         float yvec[3] = {0,-1,0};
2408         float zvec[3] = {0,0,1};
2409         float phi, si;
2410         float q1[4];
2411         float obofs[3];
2412         float reverse;
2413         //float diff[4];
2414         float d, curareaX, curareaY;
2415         float mat[3][3];
2416         float upvec[3];
2417
2418     /* Sensitivity will control how fast the view rotates.  The value was
2419      * obtained experimentally by tweaking until the author didn't get dizzy watching.
2420      * Perhaps this should be a configurable user parameter.
2421      */
2422         float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
2423         float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
2424         float zsens = 0.3f;   /* zoom sensitivity */
2425
2426         const float minZoom = -30.0f;
2427         const float maxZoom = 300.0f;
2428
2429         //reset view type
2430         rv3d->view = 0;
2431 //printf("passing here \n");
2432 //
2433         if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
2434                 use_sel = 1;
2435         }
2436
2437         if((dz_flag)||rv3d->dist==0) {
2438                 dz_flag = 0;
2439                 rv3d->dist = m_dist;
2440                 upvec[0] = upvec[1] = 0;
2441                 upvec[2] = rv3d->dist;
2442                 copy_m3_m4(mat, rv3d->viewinv);
2443                 mul_m3_v3(mat, upvec);
2444                 add_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2445         }
2446
2447     /*----------------------------------------------------
2448          * sometimes this routine is called from headerbuttons
2449      * viewmove needs to refresh the screen
2450      */
2451 // XXX  areawinset(curarea->win);
2452
2453     /*----------------------------------------------------
2454      * record how much time has passed. clamp at 10 Hz
2455      * pretend the previous frame occured at the clamped time
2456      */
2457 //    now = PIL_check_seconds_timer();
2458  //   frametime = (now - prevTime);
2459  //   if (frametime > 0.1f){        /* if more than 1/10s */
2460  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
2461 //    }
2462 //    prevTime = now;
2463  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
2464
2465     /* fetch the current state of the ndof device & enforce dominant mode if selected */
2466 // XXX    getndof(fval);
2467         if (v3d->ndoffilter)
2468                 filterNDOFvalues(fval);
2469
2470
2471     // put scaling back here, was previously in ghostwinlay
2472         fval[0] = fval[0] * (1.0f/600.0f);
2473         fval[1] = fval[1] * (1.0f/600.0f);
2474         fval[2] = fval[2] * (1.0f/1100.0f);
2475         fval[3] = fval[3] * 0.00005f;
2476         fval[4] =-fval[4] * 0.00005f;
2477         fval[5] = fval[5] * 0.00005f;
2478         fval[6] = fval[6] / 1000000.0f;
2479
2480     // scale more if not in perspective mode
2481         if (rv3d->persp == RV3D_ORTHO) {
2482                 fval[0] = fval[0] * 0.05f;
2483                 fval[1] = fval[1] * 0.05f;
2484                 fval[2] = fval[2] * 0.05f;
2485                 fval[3] = fval[3] * 0.9f;
2486                 fval[4] = fval[4] * 0.9f;
2487                 fval[5] = fval[5] * 0.9f;
2488                 zsens *= 8;
2489         }
2490
2491     /* set object offset */
2492         if (ob) {
2493                 obofs[0] = -ob->obmat[3][0];
2494                 obofs[1] = -ob->obmat[3][1];
2495                 obofs[2] = -ob->obmat[3][2];
2496         }
2497         else {
2498                 VECCOPY(obofs, rv3d->ofs);
2499         }
2500
2501     /* calc an adjustment based on distance from camera
2502        disabled per patch 14402 */
2503      d = 1.0f;
2504
2505 /*    if (ob) {
2506         sub_v3_v3v3(diff, obofs, rv3d->ofs);
2507         d = len_v3(diff);
2508     }
2509 */
2510
2511     reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
2512
2513     /*----------------------------------------------------
2514      * ndof device pan
2515      */
2516     psens *= 1.0f + d;
2517     curareaX = sbadjust * psens * fval[0];
2518     curareaY = sbadjust * psens * fval[1];
2519     dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
2520     dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
2521     dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
2522     add_v3_v3v3(rv3d->ofs, rv3d->ofs, dvec);
2523
2524     /*----------------------------------------------------
2525      * ndof device dolly
2526      */
2527     len = zsens * sbadjust * fval[2];
2528
2529     if (rv3d->persp==RV3D_CAMOB) {
2530         if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
2531             rv3d->camzoom+= 10.0f * -len;
2532         }
2533         if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
2534         else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
2535     }
2536     else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
2537         rv3d->dist*=(1.0 + len);
2538     }
2539
2540
2541     /*----------------------------------------------------
2542      * ndof device turntable
2543      * derived from the turntable code in viewmove
2544      */
2545
2546     /* Get the 3x3 matrix and its inverse from the quaternion */
2547     quat_to_mat3( m,rv3d->viewquat);
2548     invert_m3_m3(m_inv,m);
2549
2550     /* Determine the direction of the x vector (for rotating up and down) */
2551     /* This can likely be compuated directly from the quaternion. */
2552     mul_m3_v3(m_inv,xvec);
2553     mul_m3_v3(m_inv,yvec);
2554     mul_m3_v3(m_inv,zvec);
2555
2556     /* Perform the up/down rotation */
2557     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
2558     si = sin(phi);
2559     q1[0] = cos(phi);
2560     q1[1] = si * xvec[0];
2561     q1[2] = si * xvec[1];
2562     q1[3] = si * xvec[2];
2563     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2564
2565     if (use_sel) {
2566         conjugate_qt(q1); /* conj == inv for unit quat */
2567         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2568         mul_qt_v3(q1, rv3d->ofs);
2569         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2570     }
2571
2572     /* Perform the orbital rotation */
2573     /* Perform the orbital rotation
2574        If the seen Up axis is parallel to the zoom axis, rotation should be
2575        achieved with a pure Roll motion (no Spin) on the device. When you start
2576        to tilt, moving from Top to Side view, Spinning will increasingly become
2577        more relevant while the Roll component will decrease. When a full
2578        Side view is reached, rotations around the world's Up axis are achieved
2579        with a pure Spin-only motion.  In other words the control of the spinning
2580        around the world's Up axis should move from the device's Spin axis to the
2581        device's Roll axis depending on the orientation of the world's Up axis
2582        relative to the screen. */
2583     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
2584     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
2585     q1[0] = cos(phi);
2586     q1[1] = q1[2] = 0.0;
2587     q1[3] = sin(phi);
2588     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2589
2590     if (use_sel) {
2591         conjugate_qt(q1);
2592         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2593         mul_qt_v3(q1, rv3d->ofs);
2594         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2595     }
2596
2597     /*----------------------------------------------------
2598      * refresh the screen
2599      */
2600 // XXX    scrarea_do_windraw(curarea);
2601 }
2602
2603
2604
2605