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