98742bd0c7ce86af3c8304f305ff20954c510b7d
[blender-staging.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 /** \file blender/editors/space_view3d/view3d_edit.c
30  *  \ingroup spview3d
31  */
32
33
34 #include <string.h>
35 #include <stdio.h>
36 #include <math.h>
37 #include <float.h>
38
39 #include "DNA_armature_types.h"
40 #include "DNA_object_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_camera_types.h"
43
44 #include "MEM_guardedalloc.h"
45
46 #include "BLI_blenlib.h"
47 #include "BLI_math.h"
48 #include "BLI_rand.h"
49 #include "BLI_utildefines.h"
50
51 #include "BKE_context.h"
52 #include "BKE_image.h"
53 #include "BKE_library.h"
54 #include "BKE_object.h"
55 #include "BKE_paint.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58
59
60 #include "BIF_gl.h"
61 #include "BIF_glutil.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65
66 #include "RNA_access.h"
67 #include "RNA_define.h"
68
69 #include "ED_particle.h"
70 #include "ED_screen.h"
71 #include "ED_transform.h"
72 #include "ED_mesh.h"
73 #include "ED_view3d.h"
74
75
76 #include "PIL_time.h" /* smoothview */
77
78 #include "view3d_intern.h"      // own include
79
80 /* ********************** view3d_edit: view manipulations ********************* */
81
82 /* ********************* box view support ***************** */
83
84 static void view3d_boxview_clip(ScrArea *sa)
85 {
86         ARegion *ar;
87         BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
88         float clip[6][4];
89         float x1= 0.0f, y1= 0.0f, z1= 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
90         int val;
91
92         /* create bounding box */
93         for(ar= sa->regionbase.first; ar; ar= ar->next) {
94                 if(ar->regiontype==RGN_TYPE_WINDOW) {
95                         RegionView3D *rv3d= ar->regiondata;
96
97                         if(rv3d->viewlock & RV3D_BOXCLIP) {
98                                 if(ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
99                                         if(ar->winx>ar->winy) x1= rv3d->dist;
100                                         else x1= ar->winx*rv3d->dist/ar->winy;
101
102                                         if(ar->winx>ar->winy) y1= ar->winy*rv3d->dist/ar->winx;
103                                         else y1= rv3d->dist;
104                                         copy_v2_v2(ofs, rv3d->ofs);
105                                 }
106                                 else if(ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
107                                         ofs[2]= rv3d->ofs[2];
108
109                                         if(ar->winx>ar->winy) z1= ar->winy*rv3d->dist/ar->winx;
110                                         else z1= rv3d->dist;
111                                 }
112                         }
113                 }
114         }
115
116         for(val=0; val<8; val++) {
117                 if(ELEM4(val, 0, 3, 4, 7))
118                         bb->vec[val][0]= -x1 - ofs[0];
119                 else
120                         bb->vec[val][0]=  x1 - ofs[0];
121
122                 if(ELEM4(val, 0, 1, 4, 5))
123                         bb->vec[val][1]= -y1 - ofs[1];
124                 else
125                         bb->vec[val][1]=  y1 - ofs[1];
126
127                 if(val > 3)
128                         bb->vec[val][2]= -z1 - ofs[2];
129                 else
130                         bb->vec[val][2]=  z1 - ofs[2];
131         }
132
133         /* normals for plane equations */
134         normal_tri_v3( clip[0],bb->vec[0], bb->vec[1], bb->vec[4]);
135         normal_tri_v3( clip[1],bb->vec[1], bb->vec[2], bb->vec[5]);
136         normal_tri_v3( clip[2],bb->vec[2], bb->vec[3], bb->vec[6]);
137         normal_tri_v3( clip[3],bb->vec[3], bb->vec[0], bb->vec[7]);
138         normal_tri_v3( clip[4],bb->vec[4], bb->vec[5], bb->vec[6]);
139         normal_tri_v3( clip[5],bb->vec[0], bb->vec[2], bb->vec[1]);
140
141         /* then plane equations */
142         for(val=0; val<5; val++) {
143                 clip[val][3]= - clip[val][0]*bb->vec[val][0] - clip[val][1]*bb->vec[val][1] - clip[val][2]*bb->vec[val][2];
144         }
145         clip[5][3]= - clip[5][0]*bb->vec[0][0] - clip[5][1]*bb->vec[0][1] - clip[5][2]*bb->vec[0][2];
146
147         /* create bounding box */
148         for(ar= sa->regionbase.first; ar; ar= ar->next) {
149                 if(ar->regiontype==RGN_TYPE_WINDOW) {
150                         RegionView3D *rv3d= ar->regiondata;
151
152                         if(rv3d->viewlock & RV3D_BOXCLIP) {
153                                 rv3d->rflag |= RV3D_CLIPPING;
154                                 memcpy(rv3d->clip, clip, sizeof(clip));
155                                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
156                                 rv3d->clipbb= MEM_dupallocN(bb);
157                         }
158                 }
159         }
160         MEM_freeN(bb);
161 }
162
163 /* sync center/zoom view of region to others, for view transforms */
164 static void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
165 {
166         ARegion *artest;
167         RegionView3D *rv3d= ar->regiondata;
168         short clip= 0;
169
170         for(artest= sa->regionbase.first; artest; artest= artest->next) {
171                 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
172                         RegionView3D *rv3dtest= artest->regiondata;
173
174                         if(rv3dtest->viewlock) {
175                                 rv3dtest->dist= rv3d->dist;
176
177                                 if( ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ) {
178                                         if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
179                                                 rv3dtest->ofs[0]= rv3d->ofs[0];
180                                         else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
181                                                 rv3dtest->ofs[1]= rv3d->ofs[1];
182                                 }
183                                 else if( ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK) ) {
184                                         if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
185                                                 rv3dtest->ofs[0]= rv3d->ofs[0];
186                                         else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
187                                                 rv3dtest->ofs[2]= rv3d->ofs[2];
188                                 }
189                                 else if( ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ) {
190                                         if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
191                                                 rv3dtest->ofs[1]= rv3d->ofs[1];
192                                         if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
193                                                 rv3dtest->ofs[2]= rv3d->ofs[2];
194                                 }
195
196                                 clip |= rv3dtest->viewlock & RV3D_BOXCLIP;
197
198                                 ED_region_tag_redraw(artest);
199                         }
200                 }
201         }
202
203         if(clip) {
204                 view3d_boxview_clip(sa);
205         }
206 }
207
208 /* for home, center etc */
209 void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
210 {
211         ARegion *artest;
212         RegionView3D *rv3d= ar->regiondata;
213         short clip= 0;
214
215         for(artest= sa->regionbase.first; artest; artest= artest->next) {
216                 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
217                         RegionView3D *rv3dtest= artest->regiondata;
218
219                         if(rv3dtest->viewlock) {
220                                 rv3dtest->dist= rv3d->dist;
221                                 copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
222                                 ED_region_tag_redraw(artest);
223
224                                 clip |= rv3dtest->viewlock & RV3D_BOXCLIP;
225                         }
226                 }
227         }
228
229         if(clip) {
230                 view3d_boxview_clip(sa);
231         }
232 }
233
234 /* 'clip' is used to know if our clip setting has changed */
235 void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, short do_clip)
236 {
237         ARegion *arsync= NULL;
238         RegionView3D *rv3d= ar->regiondata;
239         short viewlock;
240         /* this function copies flags from the first of the 3 other quadview
241            regions to the 2 other, so it assumes this is the region whose
242            properties are always being edited, weak */
243         viewlock= rv3d->viewlock;
244
245         if((viewlock & RV3D_LOCKED)==0)
246                 viewlock= 0;
247         else if((viewlock & RV3D_BOXVIEW)==0) {
248                 viewlock &= ~RV3D_BOXCLIP;
249                 do_clip= TRUE;
250         }
251
252         for(; ar; ar= ar->prev) {
253                 if(ar->alignment==RGN_ALIGN_QSPLIT) {
254                         rv3d= ar->regiondata;
255                         rv3d->viewlock= viewlock;
256
257                         if(do_clip && (viewlock & RV3D_BOXCLIP)==0) {
258                                 rv3d->rflag &= ~RV3D_BOXCLIP;
259                         }
260
261                         /* use arsync so we sync with one of the aligned views below
262                          * else the view jumps on changing view settings like 'clip'
263                          * since it copies from the perspective view */
264                         arsync= ar;
265                 }
266         }
267
268         if(rv3d->viewlock & RV3D_BOXVIEW) {
269                 view3d_boxview_copy(sa, arsync ? arsync : sa->regionbase.last);
270         }
271
272         ED_area_tag_redraw(sa);
273 }
274
275 /* ************************** init for view ops **********************************/
276
277 typedef struct ViewOpsData {
278         ScrArea *sa;
279         ARegion *ar;
280         RegionView3D *rv3d;
281
282         /* needed for continuous zoom */
283         wmTimer *timer;
284         double timer_lastdraw;
285
286         float oldquat[4];
287         float trackvec[3];
288         float reverse, dist0;
289         float grid, far;
290         short axis_snap; /* view rotate only */
291
292         /* use for orbit selection and auto-dist */
293         float ofs[3], dyn_ofs[3];
294         short use_dyn_ofs;
295
296         int origx, origy, oldx, oldy;
297         int origkey; /* the key that triggered the operator */
298
299 } ViewOpsData;
300
301 #define TRACKBALLSIZE  (1.1)
302
303 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
304 {
305         float x, y, radius, d, z, t;
306
307         radius= TRACKBALLSIZE;
308
309         /* normalize x and y */
310         x= (rect->xmax + rect->xmin)/2 - mx;
311         x/= (float)((rect->xmax - rect->xmin)/4);
312         y= (rect->ymax + rect->ymin)/2 - my;
313         y/= (float)((rect->ymax - rect->ymin)/2);
314
315         d = sqrt(x*x + y*y);
316         if (d < radius * (float)M_SQRT1_2)      /* Inside sphere */
317                 z = sqrt(radius*radius - d*d);
318         else
319         {                       /* On hyperbola */
320                 t = radius / (float)M_SQRT2;
321                 z = t*t / d;
322         }
323
324         vec[0]= x;
325         vec[1]= y;
326         vec[2]= -z;             /* yah yah! */
327 }
328
329
330 static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
331 {
332         static float lastofs[3] = {0,0,0};
333         View3D *v3d;
334         RegionView3D *rv3d;
335         ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
336
337         /* store data */
338         op->customdata= vod;
339         vod->sa= CTX_wm_area(C);
340         vod->ar= CTX_wm_region(C);
341         v3d= vod->sa->spacedata.first;
342         vod->rv3d= rv3d= vod->ar->regiondata;
343         vod->dist0= rv3d->dist;
344         copy_qt_qt(vod->oldquat, rv3d->viewquat);
345         vod->origx= vod->oldx= event->x;
346         vod->origy= vod->oldy= event->y;
347         vod->origkey= event->type; /* the key that triggered the operator.  */
348         vod->use_dyn_ofs= (U.uiflag & USER_ORBIT_SELECTION) ? 1:0;
349
350         if (vod->use_dyn_ofs) {
351                 copy_v3_v3(vod->ofs, rv3d->ofs);
352                 /* If there's no selection, lastofs is unmodified and last value since static */
353                 calculateTransformCenter(C, V3D_CENTROID, lastofs);
354                 negate_v3_v3(vod->dyn_ofs, lastofs);
355         }
356         else if (U.uiflag & USER_ORBIT_ZBUF) {
357
358                 view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
359
360                 if((vod->use_dyn_ofs=view_autodist(CTX_data_scene(C), vod->ar, v3d, event->mval, vod->dyn_ofs))) {
361                         if (rv3d->persp==RV3D_PERSP) {
362                                 float my_origin[3]; /* original G.vd->ofs */
363                                 float my_pivot[3]; /* view */
364                                 float dvec[3];
365
366                                 // locals for dist correction
367                                 float mat[3][3];
368                                 float upvec[3];
369
370                                 negate_v3_v3(my_origin, rv3d->ofs);                             /* ofs is flipped */
371
372                                 /* Set the dist value to be the distance from this 3d point */
373                                 /* this means youll always be able to zoom into it and panning wont go bad when dist was zero */
374
375                                 /* remove dist value */
376                                 upvec[0] = upvec[1] = 0;
377                                 upvec[2] = rv3d->dist;
378                                 copy_m3_m4(mat, rv3d->viewinv);
379
380                                 mul_m3_v3(mat, upvec);
381                                 sub_v3_v3v3(my_pivot, rv3d->ofs, upvec);
382                                 negate_v3(my_pivot);                            /* ofs is flipped */
383
384                                 /* find a new ofs value that is allong the view axis (rather then the mouse location) */
385                                 closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin);
386                                 vod->dist0 = rv3d->dist = len_v3v3(my_pivot, dvec);
387
388                                 negate_v3_v3(rv3d->ofs, dvec);
389                         }
390                         negate_v3(vod->dyn_ofs);
391                         copy_v3_v3(vod->ofs, rv3d->ofs);
392                 } else {
393                         vod->ofs[0] = vod->ofs[1] = vod->ofs[2] = 0.0f;
394                 }
395         }
396
397         /* lookup, we dont pass on v3d to prevent confusement */
398         vod->grid= v3d->grid;
399         vod->far= v3d->far;
400
401         calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
402
403         initgrabz(rv3d, -rv3d->ofs[0], -rv3d->ofs[1], -rv3d->ofs[2]);
404
405         vod->reverse= 1.0f;
406         if (rv3d->persmat[2][1] < 0.0f)
407                 vod->reverse= -1.0f;
408
409         rv3d->rflag |= RV3D_NAVIGATING;
410 }
411
412 static void viewops_data_free(bContext *C, wmOperator *op)
413 {
414         ARegion *ar;
415         Paint *p = paint_get_active(CTX_data_scene(C));
416
417         if(op->customdata) {
418                 ViewOpsData *vod= op->customdata;
419                 ar= vod->ar;
420                 vod->rv3d->rflag &= ~RV3D_NAVIGATING;
421
422                 if(vod->timer)
423                         WM_event_remove_timer(CTX_wm_manager(C), vod->timer->win, vod->timer);
424
425                 MEM_freeN(vod);
426                 op->customdata= NULL;
427         }
428         else {
429                 ar= CTX_wm_region(C);
430         }
431
432         if(p && (p->flags & PAINT_FAST_NAVIGATE))
433                 ED_region_tag_redraw(ar);
434 }
435
436 /* ************************** viewrotate **********************************/
437
438 static const float thres = 0.93f; //cos(20 deg);
439
440 #define COS45 0.70710678118654746
441 #define SIN45 COS45
442
443 static float snapquats[39][5] = {
444         /*{q0, q1, q3, q4, view}*/
445         {COS45, -SIN45, 0.0, 0.0, RV3D_VIEW_FRONT},  //front
446         {0.0, 0.0, -SIN45, -SIN45, RV3D_VIEW_BACK}, //back
447         {1.0, 0.0, 0.0, 0.0, RV3D_VIEW_TOP},       //top
448         {0.0, -1.0, 0.0, 0.0, RV3D_VIEW_BOTTOM},      //bottom
449         {0.5, -0.5, -0.5, -0.5, RV3D_VIEW_RIGHT},    //left
450         {0.5, -0.5, 0.5, 0.5, RV3D_VIEW_LEFT},      //right
451
452         /* some more 45 deg snaps */
453         {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0},
454         {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0},
455         {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0},
456         {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0},
457         {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0},
458         {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0},
459         {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0},
460         {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0},
461         {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0},
462         {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0},
463         {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0},
464         {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0},
465         {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0},
466         {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0},
467         {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0},
468         {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0},
469         {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0},
470         {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0},
471         {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0},
472         {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0},
473         {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0},
474         {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0},
475         {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0},
476         {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0},
477         {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0},
478         {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0},
479         {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0},
480         {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0},
481         {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0},
482         {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0},
483         {-COS45, 0.0, 0.0, SIN45, 0},
484         {COS45, 0.0, 0.0, SIN45, 0},
485         {0.0, 0.0, 0.0, 1.0, 0}
486 };
487
488 enum {
489         VIEW_PASS= 0,
490         VIEW_APPLY,
491         VIEW_CONFIRM
492 };
493
494 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
495 #define VIEW_MODAL_CONFIRM                              1 /* used for all view operations */
496 #define VIEWROT_MODAL_AXIS_SNAP_ENABLE  2
497 #define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3
498 #define VIEWROT_MODAL_SWITCH_ZOOM               4
499 #define VIEWROT_MODAL_SWITCH_MOVE               5
500 #define VIEWROT_MODAL_SWITCH_ROTATE             6
501
502 /* called in transform_ops.c, on each regeneration of keymaps  */
503 void viewrotate_modal_keymap(wmKeyConfig *keyconf)
504 {
505         static EnumPropertyItem modal_items[] = {
506         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Confirm", ""},
507
508         {VIEWROT_MODAL_AXIS_SNAP_ENABLE,        "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""},
509         {VIEWROT_MODAL_AXIS_SNAP_DISABLE,       "AXIS_SNAP_DISABLE", 0, "Disable Axis Snap", ""},
510                 
511         {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
512         {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
513
514         {0, NULL, 0, NULL, NULL}};
515
516         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Rotate Modal");
517
518         /* this function is called for each spacetype, only needs to add map once */
519         if(keymap) return;
520
521         keymap= WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items);
522
523         /* items for modal map */
524         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
525         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
526
527         WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE);
528         WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE);
529
530         /* disabled mode switching for now, can re-implement better, later on
531         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
532         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
533         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
534         */
535         
536         /* assign map to operators */
537         WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate");
538
539 }
540
541 static void viewrotate_apply(ViewOpsData *vod, int x, int y)
542 {
543         RegionView3D *rv3d= vod->rv3d;
544
545         rv3d->view= 0; /* need to reset everytime because of view snapping */
546
547         if (U.flag & USER_TRACKBALL) {
548                 float phi, si, q1[4], dvec[3], newvec[3];
549
550                 calctrackballvec(&vod->ar->winrct, x, y, newvec);
551
552                 sub_v3_v3v3(dvec, newvec, vod->trackvec);
553
554                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
555                 si /= (float)(2.0 * TRACKBALLSIZE);
556
557                 cross_v3_v3v3(q1+1, vod->trackvec, newvec);
558                 normalize_v3(q1+1);
559
560                 /* Allow for rotation beyond the interval
561                         * [-pi, pi] */
562                 while (si > 1.0f)
563                         si -= 2.0f;
564
565                 /* This relation is used instead of
566                         * phi = asin(si) so that the angle
567                         * of rotation is linearly proportional
568                         * to the distance that the mouse is
569                         * dragged. */
570                 phi = si * (float)(M_PI / 2.0);
571
572                 q1[0]= cos(phi);
573                 mul_v3_fl(q1+1, sin(phi));
574                 mul_qt_qtqt(rv3d->viewquat, q1, vod->oldquat);
575
576                 if (vod->use_dyn_ofs) {
577                         /* compute the post multiplication quat, to rotate the offset correctly */
578                         copy_qt_qt(q1, vod->oldquat);
579                         conjugate_qt(q1);
580                         mul_qt_qtqt(q1, q1, rv3d->viewquat);
581
582                         conjugate_qt(q1); /* conj == inv for unit quat */
583                         copy_v3_v3(rv3d->ofs, vod->ofs);
584                         sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
585                         mul_qt_v3(q1, rv3d->ofs);
586                         add_v3_v3(rv3d->ofs, vod->dyn_ofs);
587                 }
588         }
589         else {
590                 /* New turntable view code by John Aughey */
591                 float phi, q1[4];
592                 float m[3][3];
593                 float m_inv[3][3];
594                 float xvec[3] = {1.0f, 0.0f, 0.0f};
595                 /* Sensitivity will control how fast the viewport rotates.  0.0035 was
596                         obtained experimentally by looking at viewport rotation sensitivities
597                         on other modeling programs. */
598                 /* Perhaps this should be a configurable user parameter. */
599                 const float sensitivity = 0.0035f;
600
601                 /* Get the 3x3 matrix and its inverse from the quaternion */
602                 quat_to_mat3( m,rv3d->viewquat);
603                 invert_m3_m3(m_inv,m);
604
605                 /* Determine the direction of the x vector (for rotating up and down) */
606                 /* This can likely be computed directly from the quaternion. */
607                 mul_m3_v3(m_inv,xvec);
608
609                 /* Perform the up/down rotation */
610                 phi = sensitivity * -(y - vod->oldy);
611                 q1[0] = cos(phi);
612                 mul_v3_v3fl(q1+1, xvec, sin(phi));
613                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
614
615                 if (vod->use_dyn_ofs) {
616                         conjugate_qt(q1); /* conj == inv for unit quat */
617                         sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
618                         mul_qt_v3(q1, rv3d->ofs);
619                         add_v3_v3(rv3d->ofs, vod->dyn_ofs);
620                 }
621
622                 /* Perform the orbital rotation */
623                 phi = sensitivity * vod->reverse * (x - vod->oldx);
624                 q1[0] = cos(phi);
625                 q1[1] = q1[2] = 0.0;
626                 q1[3] = sin(phi);
627                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
628
629                 if (vod->use_dyn_ofs) {
630                         conjugate_qt(q1);
631                         sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
632                         mul_qt_v3(q1, rv3d->ofs);
633                         add_v3_v3(rv3d->ofs, vod->dyn_ofs);
634                 }
635         }
636
637         /* check for view snap */
638         if (vod->axis_snap){
639                 int i;
640                 float viewquat_inv[4];
641                 float zaxis[3]={0,0,1};
642                 invert_qt_qt(viewquat_inv, rv3d->viewquat);
643
644                 mul_qt_v3(viewquat_inv, zaxis);
645
646                 for (i = 0 ; i < 39; i++){
647
648                         float view = (int)snapquats[i][4];
649                         float viewquat_inv_test[4];
650                         float zaxis_test[3]={0,0,1};
651
652                         invert_qt_qt(viewquat_inv_test, snapquats[i]);
653                         mul_qt_v3(viewquat_inv_test, zaxis_test);
654                         
655                         if(angle_v3v3(zaxis_test, zaxis) < DEG2RADF(45/3)) {
656                                 /* find the best roll */
657                                 float quat_roll[4], quat_final[4], quat_best[4];
658                                 float viewquat_align[4]; /* viewquat aligned to zaxis_test */
659                                 float viewquat_align_inv[4]; /* viewquat aligned to zaxis_test */
660                                 float best_angle = FLT_MAX;
661                                 int j;
662
663                                 /* viewquat_align is the original viewquat aligned to the snapped axis
664                                  * for testing roll */
665                                 rotation_between_vecs_to_quat(viewquat_align, zaxis_test, zaxis);
666                                 normalize_qt(viewquat_align);
667                                 mul_qt_qtqt(viewquat_align, rv3d->viewquat, viewquat_align);
668                                 normalize_qt(viewquat_align);
669                                 invert_qt_qt(viewquat_align_inv, viewquat_align);
670
671                                 /* find best roll */
672                                 for(j= 0; j<8; j++) {
673                                         float angle;
674                                         float xaxis1[3]={1,0,0};
675                                         float xaxis2[3]={1,0,0};
676                                         float quat_final_inv[4];
677
678                                         axis_angle_to_quat(quat_roll, zaxis_test, (float)j * DEG2RADF(45.0f));
679                                         normalize_qt(quat_roll);
680
681                                         mul_qt_qtqt(quat_final, snapquats[i], quat_roll);
682                                         normalize_qt(quat_final);
683                                         
684                                         /* compare 2 vector angles to find the least roll */
685                                         invert_qt_qt(quat_final_inv, quat_final);
686                                         mul_qt_v3(viewquat_align_inv, xaxis1);
687                                         mul_qt_v3(quat_final_inv, xaxis2);
688                                         angle= angle_v3v3(xaxis1, xaxis2);
689
690                                         if(angle <= best_angle) {
691                                                 best_angle= angle;
692                                                 copy_qt_qt(quat_best, quat_final);
693                                                 if(j) view= 0; /* view grid assumes certain up axis */
694                                         }
695                                 }
696
697                                 copy_qt_qt(rv3d->viewquat, quat_best);
698                                 rv3d->view= view; /* if we snap to a rolled camera the grid is invalid */
699
700                                 break;
701                         }
702                 }
703         }
704         vod->oldx= x;
705         vod->oldy= y;
706
707         /* avoid precision loss over time */
708         normalize_qt(rv3d->viewquat);
709
710         ED_region_tag_redraw(vod->ar);
711 }
712
713 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
714 {
715         ViewOpsData *vod= op->customdata;
716         short event_code= VIEW_PASS;
717
718         /* execute the events */
719         if(event->type==MOUSEMOVE) {
720                 event_code= VIEW_APPLY;
721         }
722         else if(event->type==EVT_MODAL_MAP) {
723                 switch (event->val) {
724                         case VIEW_MODAL_CONFIRM:
725                                 event_code= VIEW_CONFIRM;
726                                 break;
727                         case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
728                                 vod->axis_snap= TRUE;
729                                 event_code= VIEW_APPLY;
730                                 break;
731                         case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
732                                 vod->axis_snap= FALSE;
733                                 event_code= VIEW_APPLY;
734                                 break;
735                         case VIEWROT_MODAL_SWITCH_ZOOM:
736                                 WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
737                                 event_code= VIEW_CONFIRM;
738                                 break;
739                         case VIEWROT_MODAL_SWITCH_MOVE:
740                                 WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
741                                 event_code= VIEW_CONFIRM;
742                                 break;
743                 }
744         }
745         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
746                 event_code= VIEW_CONFIRM;
747         }
748
749         if(event_code==VIEW_APPLY) {
750                 viewrotate_apply(vod, event->x, event->y);
751         }
752         else if (event_code==VIEW_CONFIRM) {
753                 request_depth_update(vod->rv3d);
754                 viewops_data_free(C, op);
755
756                 return OPERATOR_FINISHED;
757         }
758
759         return OPERATOR_RUNNING_MODAL;
760 }
761
762 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
763 {
764         ViewOpsData *vod;
765         RegionView3D *rv3d;
766
767         /* makes op->customdata */
768         viewops_data_create(C, op, event);
769         vod= op->customdata;
770         rv3d= vod->rv3d;
771
772         if(rv3d->viewlock) { /* poll should check but in some cases fails, see poll func for details */
773                 viewops_data_free(C, op);
774                 return OPERATOR_PASS_THROUGH;
775         }
776
777         /* switch from camera view when: */
778         if(rv3d->persp != RV3D_PERSP) {
779
780                 if (U.uiflag & USER_AUTOPERSP) {
781                         rv3d->persp= RV3D_PERSP;
782                 }
783                 else if(rv3d->persp==RV3D_CAMOB) {
784
785                         /* changed since 2.4x, use the camera view */
786                         View3D *v3d = vod->sa->spacedata.first;
787
788                         if(v3d->camera) {
789                                 view3d_settings_from_ob(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
790                         }
791
792                         if(rv3d->persp==RV3D_CAMOB) {
793                                 rv3d->persp= rv3d->lpersp;
794                         }
795                 }
796                 ED_region_tag_redraw(vod->ar);
797         }
798         
799         if (event->type == MOUSEPAN) {
800                 viewrotate_apply(vod, event->prevx, event->prevy);
801                 request_depth_update(rv3d);
802                 
803                 viewops_data_free(C, op);
804                 
805                 return OPERATOR_FINISHED;
806         }
807         else if (event->type == MOUSEROTATE) {
808                 /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
809                 viewrotate_apply(vod, event->prevx, event->y);
810                 request_depth_update(rv3d);
811                 
812                 viewops_data_free(C, op);
813                 
814                 return OPERATOR_FINISHED;
815         }
816         else {          
817                 /* add temp handler */
818                 WM_event_add_modal_handler(C, op);
819
820                 return OPERATOR_RUNNING_MODAL;
821         }
822 }
823
824 static int view3d_camera_active_poll(bContext *C)
825 {
826         if(ED_operator_view3d_active(C)) {
827                 RegionView3D *rv3d= CTX_wm_region_view3d(C);
828                 if(rv3d && rv3d->persp==RV3D_CAMOB) {
829                         return 1;
830                 }
831         }
832
833         return 0;
834 }
835
836 void VIEW3D_OT_rotate(wmOperatorType *ot)
837 {
838
839         /* identifiers */
840         ot->name= "Rotate view";
841         ot->description = "Rotate the view";
842         ot->idname= "VIEW3D_OT_rotate";
843
844         /* api callbacks */
845         ot->invoke= viewrotate_invoke;
846         ot->modal= viewrotate_modal;
847         ot->poll= ED_operator_region_view3d_active;
848
849         /* flags */
850         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
851 }
852
853 /* ************************ viewmove ******************************** */
854
855
856 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
857
858 /* called in transform_ops.c, on each regeneration of keymaps  */
859 void viewmove_modal_keymap(wmKeyConfig *keyconf)
860 {
861         static EnumPropertyItem modal_items[] = {
862         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Confirm", ""},
863                 
864         {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
865         {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
866
867         {0, NULL, 0, NULL, NULL}};
868
869         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Move Modal");
870
871         /* this function is called for each spacetype, only needs to add map once */
872         if(keymap) return;
873
874         keymap= WM_modalkeymap_add(keyconf, "View3D Move Modal", modal_items);
875
876         /* items for modal map */
877         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
878         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
879
880         /* disabled mode switching for now, can re-implement better, later on
881         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
882         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
883         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
884         */
885         
886         /* assign map to operators */
887         WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
888 }
889
890
891 static void viewmove_apply(ViewOpsData *vod, int x, int y)
892 {
893         if(vod->rv3d->persp==RV3D_CAMOB) {
894                 float zoomfac= ((float)M_SQRT2 + (float)vod->rv3d->camzoom / 50.0f);
895                 zoomfac= (zoomfac * zoomfac) * 0.5f;
896
897                 vod->rv3d->camdx += (vod->oldx - x)/(vod->ar->winx * zoomfac);
898                 vod->rv3d->camdy += (vod->oldy - y)/(vod->ar->winy * zoomfac);
899                 CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
900                 CLAMP(vod->rv3d->camdy, -1.0f, 1.0f);
901 // XXX          preview3d_event= 0;
902         }
903         else {
904                 float dvec[3];
905
906                 window_to_3d_delta(vod->ar, dvec, x-vod->oldx, y-vod->oldy);
907                 add_v3_v3(vod->rv3d->ofs, dvec);
908
909                 if(vod->rv3d->viewlock & RV3D_BOXVIEW)
910                         view3d_boxview_sync(vod->sa, vod->ar);
911         }
912
913         vod->oldx= x;
914         vod->oldy= y;
915
916         ED_region_tag_redraw(vod->ar);
917 }
918
919
920 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
921 {
922
923         ViewOpsData *vod= op->customdata;
924         short event_code= VIEW_PASS;
925
926         /* execute the events */
927         if(event->type==MOUSEMOVE) {
928                 event_code= VIEW_APPLY;
929         }
930         else if(event->type==EVT_MODAL_MAP) {
931                 switch (event->val) {
932                         case VIEW_MODAL_CONFIRM:
933                                 event_code= VIEW_CONFIRM;
934                                 break;
935                         case VIEWROT_MODAL_SWITCH_ZOOM:
936                                 WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
937                                 event_code= VIEW_CONFIRM;
938                                 break;
939                         case VIEWROT_MODAL_SWITCH_ROTATE:
940                                 WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
941                                 event_code= VIEW_CONFIRM;
942                                 break;
943                 }
944         }
945         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
946                 event_code= VIEW_CONFIRM;
947         }
948
949         if(event_code==VIEW_APPLY) {
950                 viewmove_apply(vod, event->x, event->y);
951         }
952         else if (event_code==VIEW_CONFIRM) {
953                 request_depth_update(vod->rv3d);
954
955                 viewops_data_free(C, op);
956
957                 return OPERATOR_FINISHED;
958         }
959
960         return OPERATOR_RUNNING_MODAL;
961 }
962
963 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
964 {
965         /* makes op->customdata */
966         viewops_data_create(C, op, event);
967
968         if (event->type == MOUSEPAN) {
969                 ViewOpsData *vod= op->customdata;
970                 viewmove_apply(vod, event->prevx, event->prevy);
971                 request_depth_update(vod->rv3d);
972                 
973                 viewops_data_free(C, op);               
974                 
975                 return OPERATOR_FINISHED;
976         }
977         else {
978                 /* add temp handler */
979                 WM_event_add_modal_handler(C, op);
980
981                 return OPERATOR_RUNNING_MODAL;
982         }
983 }
984
985 void VIEW3D_OT_move(wmOperatorType *ot)
986 {
987
988         /* identifiers */
989         ot->name= "Move view";
990         ot->description = "Move the view";
991         ot->idname= "VIEW3D_OT_move";
992
993         /* api callbacks */
994         ot->invoke= viewmove_invoke;
995         ot->modal= viewmove_modal;
996         ot->poll= ED_operator_view3d_active;
997
998         /* flags */
999         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1000 }
1001
1002 /* ************************ viewzoom ******************************** */
1003
1004 /* called in transform_ops.c, on each regeneration of keymaps  */
1005 void viewzoom_modal_keymap(wmKeyConfig *keyconf)
1006 {
1007         static EnumPropertyItem modal_items[] = {
1008         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Confirm", ""},
1009                 
1010         {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
1011         {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
1012
1013         {0, NULL, 0, NULL, NULL}};
1014
1015         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Zoom Modal");
1016
1017         /* this function is called for each spacetype, only needs to add map once */
1018         if(keymap) return;
1019
1020         keymap= WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items);
1021
1022         /* items for modal map */
1023         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
1024         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
1025
1026         /* disabled mode switching for now, can re-implement better, later on
1027         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
1028         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
1029         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
1030          */
1031         
1032         /* assign map to operators */
1033         WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
1034 }
1035
1036 static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
1037 {
1038         RegionView3D *rv3d= ar->regiondata;
1039
1040         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
1041                 float dvec[3];
1042                 float tvec[3];
1043                 float tpos[3];
1044                 float new_dist;
1045                 short vb[2], mouseloc[2];
1046
1047                 mouseloc[0]= mx - ar->winrct.xmin;
1048                 mouseloc[1]= my - ar->winrct.ymin;
1049
1050                 /* find the current window width and height */
1051                 vb[0] = ar->winx;
1052                 vb[1] = ar->winy;
1053
1054                 negate_v3_v3(tpos, rv3d->ofs);
1055
1056                 /* Project cursor position into 3D space */
1057                 initgrabz(rv3d, tpos[0], tpos[1], tpos[2]);
1058                 window_to_3d_delta(ar, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
1059
1060                 /* Calculate view target position for dolly */
1061                 add_v3_v3v3(tvec, tpos, dvec);
1062                 negate_v3(tvec);
1063
1064                 /* Offset to target position and dolly */
1065                 new_dist = rv3d->dist * dfac;
1066
1067                 copy_v3_v3(rv3d->ofs, tvec);
1068                 rv3d->dist = new_dist;
1069
1070                 /* Calculate final offset */
1071                 madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac);
1072         } else {
1073                 rv3d->dist *= dfac;
1074         }
1075 }
1076
1077
1078 static void viewzoom_apply(ViewOpsData *vod, int x, int y, short viewzoom)
1079 {
1080         float zfac=1.0;
1081
1082         if(viewzoom==USER_ZOOM_CONT) {
1083                 double time= PIL_check_seconds_timer();
1084                 float time_step= (float)(time - vod->timer_lastdraw);
1085
1086                 // oldstyle zoom
1087                 zfac = 1.0f + (((float)(vod->origx - x + vod->origy - y) / 20.0f) * time_step);
1088                 vod->timer_lastdraw= time;
1089         }
1090         else if(viewzoom==USER_ZOOM_SCALE) {
1091                 int ctr[2], len1, len2;
1092                 // method which zooms based on how far you move the mouse
1093
1094                 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
1095                 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
1096
1097                 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
1098                 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
1099
1100                 zfac = vod->dist0 * ((float)len2/len1) / vod->rv3d->dist;
1101         }
1102         else {  /* USER_ZOOM_DOLLY */
1103                 float len1, len2;
1104                 
1105                 if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
1106                         len1 = (vod->ar->winrct.xmax - x) + 5;
1107                         len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
1108                 }
1109                 else {
1110                         len1 = (vod->ar->winrct.ymax - y) + 5;
1111                         len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
1112                 }
1113                 if (U.uiflag & USER_ZOOM_INVERT)
1114                         SWAP(float, len1, len2);
1115                 
1116                 zfac = vod->dist0 * (2.0f * ((len2/len1)-1.0f) + 1.0f) / vod->rv3d->dist;
1117         }
1118
1119         if(zfac != 1.0f && zfac*vod->rv3d->dist > 0.001f * vod->grid &&
1120                                 zfac * vod->rv3d->dist < 10.0f * vod->far)
1121                 view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
1122
1123
1124         if ((U.uiflag & USER_ORBIT_ZBUF) && (viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
1125                 float upvec[3], mat[3][3];
1126
1127                 /* Secret apricot feature, translate the view when in continues mode */
1128                 upvec[0] = upvec[1] = 0.0f;
1129                 upvec[2] = (vod->dist0 - vod->rv3d->dist) * vod->grid;
1130                 vod->rv3d->dist = vod->dist0;
1131                 copy_m3_m4(mat, vod->rv3d->viewinv);
1132                 mul_m3_v3(mat, upvec);
1133                 add_v3_v3(vod->rv3d->ofs, upvec);
1134         } else {
1135                 /* these limits were in old code too */
1136                 if(vod->rv3d->dist<0.001f * vod->grid) vod->rv3d->dist= 0.001f * vod->grid;
1137                 if(vod->rv3d->dist>10.0f * vod->far) vod->rv3d->dist=10.0f * vod->far;
1138         }
1139
1140 // XXX  if(vod->rv3d->persp==RV3D_ORTHO || vod->rv3d->persp==RV3D_CAMOB) preview3d_event= 0;
1141
1142         if(vod->rv3d->viewlock & RV3D_BOXVIEW)
1143                 view3d_boxview_sync(vod->sa, vod->ar);
1144
1145         ED_region_tag_redraw(vod->ar);
1146 }
1147
1148
1149 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
1150 {
1151         ViewOpsData *vod= op->customdata;
1152         short event_code= VIEW_PASS;
1153
1154         /* execute the events */
1155         if (event->type == TIMER && event->customdata == vod->timer) {
1156                 /* continuous zoom */
1157                 event_code= VIEW_APPLY;
1158         }
1159         else if(event->type==MOUSEMOVE) {
1160                 event_code= VIEW_APPLY;
1161         }
1162         else if(event->type==EVT_MODAL_MAP) {
1163                 switch (event->val) {
1164                         case VIEW_MODAL_CONFIRM:
1165                                 event_code= VIEW_CONFIRM;
1166                                 break;
1167                         case VIEWROT_MODAL_SWITCH_MOVE:
1168                                 WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
1169                                 event_code= VIEW_CONFIRM;
1170                                 break;
1171                         case VIEWROT_MODAL_SWITCH_ROTATE:
1172                                 WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
1173                                 event_code= VIEW_CONFIRM;
1174                                 break;
1175                 }
1176         }
1177         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
1178                 event_code= VIEW_CONFIRM;
1179         }
1180
1181         if(event_code==VIEW_APPLY) {
1182                 viewzoom_apply(vod, event->x, event->y, U.viewzoom);
1183         }
1184         else if (event_code==VIEW_CONFIRM) {
1185                 request_depth_update(vod->rv3d);
1186                 viewops_data_free(C, op);
1187
1188                 return OPERATOR_FINISHED;
1189         }
1190
1191         return OPERATOR_RUNNING_MODAL;
1192 }
1193
1194 static int viewzoom_exec(bContext *C, wmOperator *op)
1195 {
1196         View3D *v3d;
1197         RegionView3D *rv3d;
1198         ScrArea *sa;
1199         ARegion *ar;
1200
1201         int delta= RNA_int_get(op->ptr, "delta");
1202         int mx, my;
1203
1204         if(op->customdata) {
1205                 ViewOpsData *vod= op->customdata;
1206
1207                 sa= vod->sa;
1208                 ar= vod->ar;
1209         }
1210         else {
1211                 sa= CTX_wm_area(C);
1212                 ar= CTX_wm_region(C);
1213         }
1214
1215         v3d= sa->spacedata.first;
1216         rv3d= ar->regiondata;
1217
1218         mx= RNA_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") : ar->winx / 2;
1219         my= RNA_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") : ar->winy / 2;
1220
1221         if(delta < 0) {
1222                 /* this min and max is also in viewmove() */
1223                 if(rv3d->persp==RV3D_CAMOB) {
1224                         rv3d->camzoom-= 10;
1225                         if(rv3d->camzoom < RV3D_CAMZOOM_MIN) rv3d->camzoom= RV3D_CAMZOOM_MIN;
1226                 }
1227                 else if(rv3d->dist < 10.0f * v3d->far) {
1228                         view_zoom_mouseloc(ar, 1.2f, mx, my);
1229                 }
1230         }
1231         else {
1232                 if(rv3d->persp==RV3D_CAMOB) {
1233                         rv3d->camzoom+= 10;
1234                         if(rv3d->camzoom > RV3D_CAMZOOM_MAX) rv3d->camzoom= RV3D_CAMZOOM_MAX;
1235                 }
1236                 else if(rv3d->dist> 0.001f * v3d->grid) {
1237                         view_zoom_mouseloc(ar, .83333f, mx, my);
1238                 }
1239         }
1240
1241         if(rv3d->viewlock & RV3D_BOXVIEW)
1242                 view3d_boxview_sync(sa, ar);
1243
1244         request_depth_update(rv3d);
1245         ED_region_tag_redraw(ar);
1246
1247         viewops_data_free(C, op);
1248
1249         return OPERATOR_FINISHED;
1250 }
1251
1252 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
1253 {
1254         /* if one or the other zoom position aren't set, set from event */
1255         if (!RNA_property_is_set(op->ptr, "mx") || !RNA_property_is_set(op->ptr, "my"))
1256         {
1257                 RNA_int_set(op->ptr, "mx", event->x);
1258                 RNA_int_set(op->ptr, "my", event->y);
1259         }
1260
1261         if(RNA_property_is_set(op->ptr, "delta")) {
1262                 /* makes op->customdata */
1263                 viewops_data_create(C, op, event);
1264                 viewzoom_exec(C, op);
1265         }
1266         else {
1267                 ViewOpsData *vod;
1268
1269                 /* makes op->customdata */
1270                 viewops_data_create(C, op, event);
1271
1272                 vod= op->customdata;
1273
1274                 if (event->type == MOUSEZOOM) {
1275                         if (U.uiflag & USER_ZOOM_INVERT) /* Bypass Zoom invert flag */
1276                                 SWAP(int, event->x, event->prevx);
1277
1278                         if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
1279                                 vod->origx = vod->oldx = event->x;
1280                                 viewzoom_apply(vod, event->prevx, event->prevy, USER_ZOOM_DOLLY);
1281                         }
1282                         else {
1283                                 
1284                                 /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
1285                                 vod->origy = vod->oldy = vod->origy + event->x - event->prevx;
1286                                 viewzoom_apply(vod, event->prevx, event->prevy, USER_ZOOM_DOLLY);
1287                         }
1288                         request_depth_update(vod->rv3d);
1289                         
1290                         viewops_data_free(C, op);
1291                         return OPERATOR_FINISHED;
1292                 }
1293                 else {
1294                         if(U.viewzoom == USER_ZOOM_CONT) {
1295                                 /* needs a timer to continue redrawing */
1296                                 vod->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
1297                                 vod->timer_lastdraw= PIL_check_seconds_timer();
1298                         }
1299
1300                         /* add temp handler */
1301                         WM_event_add_modal_handler(C, op);
1302
1303                         return OPERATOR_RUNNING_MODAL;
1304                 }
1305         }
1306         return OPERATOR_FINISHED;
1307 }
1308
1309
1310 void VIEW3D_OT_zoom(wmOperatorType *ot)
1311 {
1312         /* identifiers */
1313         ot->name= "Zoom View";
1314         ot->description = "Zoom in/out in the view";
1315         ot->idname= "VIEW3D_OT_zoom";
1316
1317         /* api callbacks */
1318         ot->invoke= viewzoom_invoke;
1319         ot->exec= viewzoom_exec;
1320         ot->modal= viewzoom_modal;
1321         ot->poll= ED_operator_region_view3d_active;
1322
1323         /* flags */
1324         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1325
1326         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1327         RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
1328         RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
1329 }
1330
1331 static int view3d_all_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1332 {
1333         ARegion *ar= CTX_wm_region(C);
1334         View3D *v3d = CTX_wm_view3d(C);
1335         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1336         Scene *scene= CTX_data_scene(C);
1337         Base *base;
1338         float *curs;
1339
1340         int center= RNA_boolean_get(op->ptr, "center");
1341
1342         float size, min[3], max[3], afm[3];
1343         int ok= 1, onedone=0;
1344
1345         if(center) {
1346                 /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
1347                 curs= give_cursor(scene, v3d);
1348                 zero_v3(min);
1349                 zero_v3(max);
1350                 zero_v3(curs);
1351         }
1352         else {
1353                 INIT_MINMAX(min, max);
1354         }
1355
1356         for(base= scene->base.first; base; base= base->next) {
1357                 if(BASE_VISIBLE(v3d, base)) {
1358                         onedone= 1;
1359                         minmax_object(base->object, min, max);
1360                 }
1361         }
1362         if(!onedone) {
1363                 ED_region_tag_redraw(ar);
1364                 /* TODO - should this be cancel?
1365                  * I think no, because we always move the cursor, with or without
1366                  * object, but in this case there is no change in the scene,
1367                  * only the cursor so I choice a ED_region_tag like
1368                  * smooth_view do for the center_cursor.
1369                  * See bug #22640
1370                  */
1371                 return OPERATOR_FINISHED;
1372         }
1373
1374         sub_v3_v3v3(afm, max, min);
1375         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
1376         if(size == 0.0f) ok= 0;
1377
1378         if(ok) {
1379                 float new_dist;
1380                 float new_ofs[3];
1381
1382                 new_dist = size;
1383                 new_ofs[0]= -(min[0]+max[0])/2.0f;
1384                 new_ofs[1]= -(min[1]+max[1])/2.0f;
1385                 new_ofs[2]= -(min[2]+max[2])/2.0f;
1386
1387                 // correction for window aspect ratio
1388                 if(ar->winy>2 && ar->winx>2) {
1389                         size= (float)ar->winx/(float)ar->winy;
1390                         if(size < 1.0f) size= 1.0f/size;
1391                         new_dist*= size;
1392                 }
1393
1394                 if (rv3d->persp==RV3D_CAMOB) {
1395                         rv3d->persp= RV3D_PERSP;
1396                         smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1397                 }
1398                 else {
1399                         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1400                 }
1401         }
1402 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1403
1404         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
1405
1406         return OPERATOR_FINISHED;
1407 }
1408
1409
1410 void VIEW3D_OT_view_all(wmOperatorType *ot)
1411 {
1412         /* identifiers */
1413         ot->name= "View All";
1414         ot->description = "View all objects in scene";
1415         ot->idname= "VIEW3D_OT_view_all";
1416
1417         /* api callbacks */
1418         ot->exec= view3d_all_exec;
1419         ot->poll= ED_operator_region_view3d_active;
1420
1421         /* flags */
1422         ot->flag= 0;
1423
1424         RNA_def_boolean(ot->srna, "center", 0, "Center", "");
1425 }
1426
1427
1428 static int viewselected_exec(bContext *C, wmOperator *UNUSED(op)) /* like a localview without local!, was centerview() in 2.4x */
1429 {
1430         ARegion *ar= CTX_wm_region(C);
1431         View3D *v3d = CTX_wm_view3d(C);
1432         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1433         Scene *scene= CTX_data_scene(C);
1434         Object *ob= OBACT;
1435         Object *obedit= CTX_data_edit_object(C);
1436         float size, min[3], max[3], afm[3];
1437         int ok=0, ok_dist=1;
1438
1439         /* SMOOTHVIEW */
1440         float new_ofs[3];
1441         float new_dist;
1442
1443         INIT_MINMAX(min, max);
1444
1445         if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
1446                 /* hardcoded exception, we look for the one selected armature */
1447                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1448                 Base *base;
1449                 for(base=scene->base.first; base; base= base->next) {
1450                         if(TESTBASELIB(v3d, base)) {
1451                                 if(base->object->type==OB_ARMATURE)
1452                                         if(base->object->mode & OB_MODE_POSE)
1453                                                 break;
1454                         }
1455                 }
1456                 if(base)
1457                         ob= base->object;
1458         }
1459
1460
1461         if(obedit) {
1462                 ok = minmax_verts(obedit, min, max);    /* only selected */
1463         }
1464         else if(ob && (ob->mode & OB_MODE_POSE)) {
1465                 if(ob->pose) {
1466                         bArmature *arm= ob->data;
1467                         bPoseChannel *pchan;
1468                         float vec[3];
1469
1470                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1471                                 if(pchan->bone->flag & BONE_SELECTED) {
1472                                         if(pchan->bone->layer & arm->layer) {
1473                                                 bPoseChannel *pchan_tx= pchan->custom_tx ? pchan->custom_tx : pchan;
1474                                                 ok= 1;
1475                                                 mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head);
1476                                                 DO_MINMAX(vec, min, max);
1477                                                 mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail);
1478                                                 DO_MINMAX(vec, min, max);
1479                                         }
1480                                 }
1481                         }
1482                 }
1483         }
1484         else if (paint_facesel_test(ob)) {
1485                 ok= paintface_minmax(ob, min, max);
1486         }
1487         else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1488                 ok= PE_minmax(scene, min, max);
1489         }
1490         else {
1491                 Base *base= FIRSTBASE;
1492                 while(base) {
1493                         if(TESTBASE(v3d, base))  {
1494
1495                                 /* account for duplis */
1496                                 if (minmax_object_duplis(scene, base->object, min, max)==0)
1497                                         minmax_object(base->object, min, max); /* use if duplis not found */
1498
1499                                 ok= 1;
1500                         }
1501                         base= base->next;
1502                 }
1503         }
1504
1505         if(ok==0) return OPERATOR_FINISHED;
1506
1507         sub_v3_v3v3(afm, max, min);
1508         size= MAX3(afm[0], afm[1], afm[2]);
1509
1510         if(rv3d->persp==RV3D_ORTHO) {
1511                 if(size < 0.0001f) { /* if its a sinble point. dont even re-scale */
1512                         ok_dist= 0;
1513                 }
1514                 else {
1515                         /* perspective should be a bit farther away to look nice */
1516                         size*= 0.7f;
1517                 }
1518         }
1519         else {
1520                 if(size <= v3d->near*1.5f) {
1521                         size= v3d->near*1.5f;
1522                 }
1523         }
1524
1525         add_v3_v3v3(new_ofs, min, max);
1526         mul_v3_fl(new_ofs, -0.5f);
1527
1528         new_dist = size;
1529
1530         /* correction for window aspect ratio */
1531         if(ar->winy>2 && ar->winx>2) {
1532                 size= (float)ar->winx/(float)ar->winy;
1533                 if(size<1.0f) size= 1.0f/size;
1534                 new_dist*= size;
1535         }
1536
1537         if (rv3d->persp==RV3D_CAMOB) {
1538                 rv3d->persp= RV3D_PERSP;
1539                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1540         }
1541         else {
1542                 smooth_view(C, NULL, NULL, new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL);
1543         }
1544
1545         /* smooth view does viewlock RV3D_BOXVIEW copy */
1546         
1547 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1548
1549         return OPERATOR_FINISHED;
1550 }
1551
1552 void VIEW3D_OT_view_selected(wmOperatorType *ot)
1553 {
1554
1555         /* identifiers */
1556         ot->name= "View Selected";
1557         ot->description = "Move the view to the selection center";
1558         ot->idname= "VIEW3D_OT_view_selected";
1559
1560         /* api callbacks */
1561         ot->exec= viewselected_exec;
1562         ot->poll= ED_operator_region_view3d_active;
1563
1564         /* flags */
1565         ot->flag= 0;
1566 }
1567
1568 static int viewcenter_cursor_exec(bContext *C, wmOperator *UNUSED(op))
1569 {
1570         View3D *v3d = CTX_wm_view3d(C);
1571         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1572         Scene *scene= CTX_data_scene(C);
1573         
1574         if (rv3d) {
1575                 /* non camera center */
1576                 float new_ofs[3];
1577                 negate_v3_v3(new_ofs, give_cursor(scene, v3d));
1578                 smooth_view(C, NULL, NULL, new_ofs, NULL, NULL, NULL);
1579                 
1580                 /* smooth view does viewlock RV3D_BOXVIEW copy */
1581         }
1582         
1583         return OPERATOR_FINISHED;
1584 }
1585
1586 void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
1587 {
1588         /* identifiers */
1589         ot->name= "Center View to Cursor";
1590         ot->description= "Centers the view so that the cursor is in the middle of the view";
1591         ot->idname= "VIEW3D_OT_view_center_cursor";
1592         
1593         /* api callbacks */
1594         ot->exec= viewcenter_cursor_exec;
1595         ot->poll= ED_operator_view3d_active;
1596         
1597         /* flags */
1598         ot->flag= 0;
1599 }
1600
1601 static int view3d_center_camera_exec(bContext *C, wmOperator *UNUSED(op)) /* was view3d_home() in 2.4x */
1602 {
1603         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1604
1605         rv3d->camdx= rv3d->camdy= 0.0f;
1606
1607         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, CTX_wm_view3d(C));
1608
1609         return OPERATOR_FINISHED;
1610 }
1611
1612 void VIEW3D_OT_view_center_camera(wmOperatorType *ot)
1613 {
1614         /* identifiers */
1615         ot->name= "View Camera Center";
1616         ot->description = "Center the camera view";
1617         ot->idname= "VIEW3D_OT_view_center_camera";
1618
1619         /* api callbacks */
1620         ot->exec= view3d_center_camera_exec;
1621         ot->poll= view3d_camera_active_poll;
1622
1623         /* flags */
1624         ot->flag= 0;
1625 }
1626
1627 /* ********************* Set render border operator ****************** */
1628
1629 static int render_border_exec(bContext *C, wmOperator *op)
1630 {
1631         View3D *v3d = CTX_wm_view3d(C);
1632         ARegion *ar= CTX_wm_region(C);
1633         RegionView3D *rv3d= ED_view3d_context_rv3d(C);
1634         Scene *scene= CTX_data_scene(C);
1635
1636         rcti rect;
1637         rctf vb;
1638
1639         /* get border select values using rna */
1640         rect.xmin= RNA_int_get(op->ptr, "xmin");
1641         rect.ymin= RNA_int_get(op->ptr, "ymin");
1642         rect.xmax= RNA_int_get(op->ptr, "xmax");
1643         rect.ymax= RNA_int_get(op->ptr, "ymax");
1644
1645         /* calculate range */
1646         view3d_calc_camera_border(scene, ar, rv3d, v3d, &vb, FALSE);
1647
1648         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1649         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1650         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1651         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1652
1653         /* actually set border */
1654         CLAMP(scene->r.border.xmin, 0.0f, 1.0f);
1655         CLAMP(scene->r.border.ymin, 0.0f, 1.0f);
1656         CLAMP(scene->r.border.xmax, 0.0f, 1.0f);
1657         CLAMP(scene->r.border.ymax, 0.0f, 1.0f);
1658
1659         /* drawing a border surrounding the entire camera view switches off border rendering
1660          * or the border covers no pixels */
1661         if ((scene->r.border.xmin <= 0.0f && scene->r.border.xmax >= 1.0f &&
1662                 scene->r.border.ymin <= 0.0f && scene->r.border.ymax >= 1.0f) ||
1663            (scene->r.border.xmin == scene->r.border.xmax ||
1664                 scene->r.border.ymin == scene->r.border.ymax ))
1665         {
1666                 scene->r.mode &= ~R_BORDER;
1667         } else {
1668                 scene->r.mode |= R_BORDER;
1669         }
1670         
1671         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, NULL);
1672
1673         return OPERATOR_FINISHED;
1674
1675 }
1676
1677 void VIEW3D_OT_render_border(wmOperatorType *ot)
1678 {
1679         /* identifiers */
1680         ot->name= "Set Render Border";
1681         ot->description = "Set the boundaries of the border render and enables border render ";
1682         ot->idname= "VIEW3D_OT_render_border";
1683
1684         /* api callbacks */
1685         ot->invoke= WM_border_select_invoke;
1686         ot->exec= render_border_exec;
1687         ot->modal= WM_border_select_modal;
1688
1689         ot->poll= view3d_camera_active_poll;
1690
1691         /* flags */
1692         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1693
1694         /* rna */
1695         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1696         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1697         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1698         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1699
1700 }
1701 /* ********************* Border Zoom operator ****************** */
1702
1703 static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
1704 {
1705         ARegion *ar= CTX_wm_region(C);
1706         View3D *v3d = CTX_wm_view3d(C);
1707         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1708         Scene *scene= CTX_data_scene(C);
1709
1710         /* Zooms in on a border drawn by the user */
1711         rcti rect;
1712         float dvec[3], vb[2], xscale, yscale, scale;
1713
1714         /* SMOOTHVIEW */
1715         float new_dist;
1716         float new_ofs[3];
1717
1718         /* ZBuffer depth vars */
1719         bglMats mats;
1720         float depth_close= FLT_MAX;
1721         double cent[2],  p[3];
1722
1723         /* note; otherwise opengl won't work */
1724         view3d_operator_needs_opengl(C);
1725
1726         /* get border select values using rna */
1727         rect.xmin= RNA_int_get(op->ptr, "xmin");
1728         rect.ymin= RNA_int_get(op->ptr, "ymin");
1729         rect.xmax= RNA_int_get(op->ptr, "xmax");
1730         rect.ymax= RNA_int_get(op->ptr, "ymax");
1731
1732         /* Get Z Depths, needed for perspective, nice for ortho */
1733         bgl_get_mats(&mats);
1734         draw_depth(scene, ar, v3d, NULL);
1735         
1736         {
1737                 /* avoid allocating the whole depth buffer */
1738                 ViewDepths depth_temp= {0};
1739
1740                 /* avoid view3d_update_depths() for speed. */
1741                 view3d_update_depths_rect(ar, &depth_temp, &rect);
1742         
1743                 /* find the closest Z pixel */
1744                 depth_close= view3d_depth_near(&depth_temp);
1745         
1746                 MEM_freeN(depth_temp.depths);
1747         }
1748
1749         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1750         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1751
1752         if (rv3d->persp==RV3D_PERSP) {
1753                 double p_corner[3];
1754
1755                 /* no depths to use, we cant do anything! */
1756                 if (depth_close==FLT_MAX){
1757                         BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1758                         return OPERATOR_CANCELLED;
1759                 }
1760                 /* convert border to 3d coordinates */
1761                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1762                         (       !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])))
1763                         return OPERATOR_CANCELLED;
1764
1765                 dvec[0] = p[0]-p_corner[0];
1766                 dvec[1] = p[1]-p_corner[1];
1767                 dvec[2] = p[2]-p_corner[2];
1768
1769                 new_dist = len_v3(dvec);
1770                 if(new_dist <= v3d->near * 1.5f) new_dist= v3d->near * 1.5f;
1771
1772                 new_ofs[0] = -p[0];
1773                 new_ofs[1] = -p[1];
1774                 new_ofs[2] = -p[2];
1775
1776         } else { /* othographic */
1777                 /* find the current window width and height */
1778                 vb[0] = ar->winx;
1779                 vb[1] = ar->winy;
1780
1781                 new_dist = rv3d->dist;
1782
1783                 /* convert the drawn rectangle into 3d space */
1784                 if (depth_close!=FLT_MAX && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1785                         new_ofs[0] = -p[0];
1786                         new_ofs[1] = -p[1];
1787                         new_ofs[2] = -p[2];
1788                 } else {
1789                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1790                         copy_v3_v3(new_ofs, rv3d->ofs);
1791
1792                         initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1793
1794                         window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1795                         /* center the view to the center of the rectangle */
1796                         sub_v3_v3(new_ofs, dvec);
1797                 }
1798
1799                 /* work out the ratios, so that everything selected fits when we zoom */
1800                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1801                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1802                 scale = (xscale >= yscale)?xscale:yscale;
1803
1804                 /* zoom in as required, or as far as we can go */
1805                 new_dist = ((new_dist*scale) >= 0.001f * v3d->grid)? new_dist*scale:0.001f * v3d->grid;
1806         }
1807
1808         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1809
1810         if(rv3d->viewlock & RV3D_BOXVIEW)
1811                 view3d_boxview_sync(CTX_wm_area(C), ar);
1812
1813         return OPERATOR_FINISHED;
1814 }
1815
1816 static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1817 {
1818         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1819
1820         /* if in camera view do not exec the operator so we do not conflict with set render border*/
1821         if (rv3d->persp != RV3D_CAMOB)
1822                 return WM_border_select_invoke(C, op, event);
1823         else
1824                 return OPERATOR_PASS_THROUGH;
1825 }
1826
1827 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1828 {
1829         /* identifiers */
1830         ot->name= "Border Zoom";
1831         ot->description = "Zoom in the view to the nearest object contained in the border";
1832         ot->idname= "VIEW3D_OT_zoom_border";
1833
1834         /* api callbacks */
1835         ot->invoke= view3d_zoom_border_invoke;
1836         ot->exec= view3d_zoom_border_exec;
1837         ot->modal= WM_border_select_modal;
1838
1839         ot->poll= ED_operator_region_view3d_active;
1840
1841         /* flags */
1842         ot->flag= 0;
1843
1844         /* rna */
1845         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1846         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1847         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1848         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1849
1850 }
1851
1852 /* sets the view to 1:1 camera/render-pixel */
1853 static void view3d_set_1_to_1_viewborder(Scene *scene, ARegion *ar)
1854 {
1855         RegionView3D *rv3d= ar->regiondata;
1856         float size[2];
1857         int im_width= (scene->r.size*scene->r.xsch)/100;
1858         
1859         view3d_viewborder_size_get(scene, ar, size);
1860         
1861         rv3d->camzoom= (sqrtf(4.0f * (float)im_width/size[0]) - (float)M_SQRT2) * 50.0f;
1862         rv3d->camzoom= CLAMPIS(rv3d->camzoom, RV3D_CAMZOOM_MIN, RV3D_CAMZOOM_MAX);
1863 }
1864
1865 static int view3d_zoom_1_to_1_camera_exec(bContext *C, wmOperator *UNUSED(op))
1866 {
1867         Scene *scene= CTX_data_scene(C);
1868         ARegion *ar= CTX_wm_region(C);
1869
1870         view3d_set_1_to_1_viewborder(scene, ar);
1871
1872         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, CTX_wm_view3d(C));
1873
1874         return OPERATOR_FINISHED;
1875 }
1876
1877 void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot)
1878 {
1879         /* identifiers */
1880         ot->name= "Zoom Camera 1:1";
1881         ot->description = "Match the camera to 1:1 to the render output";
1882         ot->idname= "VIEW3D_OT_zoom_camera_1_to_1";
1883
1884         /* api callbacks */
1885         ot->exec= view3d_zoom_1_to_1_camera_exec;
1886         ot->poll= view3d_camera_active_poll;
1887
1888         /* flags */
1889         ot->flag= 0;
1890 }
1891
1892 /* ********************* Changing view operator ****************** */
1893
1894 static EnumPropertyItem prop_view_items[] = {
1895         {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1896         {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1897         {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1898         {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1899         {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1900         {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1901         {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1902         {0, NULL, 0, NULL, NULL}};
1903
1904
1905 /* would like to make this a generic function - outside of transform */
1906
1907 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo, int align_active)
1908 {
1909         View3D *v3d = CTX_wm_view3d(C);
1910         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1911         float new_quat[4];
1912
1913         new_quat[0]= q1; new_quat[1]= q2;
1914         new_quat[2]= q3; new_quat[3]= q4;
1915
1916         if(align_active) {
1917                 /* align to active object */
1918                 Object *obact= CTX_data_active_object(C);
1919                 if (obact==NULL) {
1920                         /* no active object, ignore this option */
1921                         align_active= FALSE;
1922                 }
1923                 else {
1924                         float obact_quat[4];
1925                         float twmat[3][3];
1926
1927                         /* same as transform manipulator when normal is set */
1928                         ED_getTransformOrientationMatrix(C, twmat, FALSE);
1929
1930                         mat3_to_quat( obact_quat,twmat);
1931                         invert_qt(obact_quat);
1932                         mul_qt_qtqt(new_quat, new_quat, obact_quat);
1933
1934                         rv3d->view= view= 0;
1935                 }
1936         }
1937
1938         if(align_active==FALSE) {
1939                 /* normal operation */
1940                 if(rv3d->viewlock) {
1941                         /* only pass on if */
1942                         if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
1943                         else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
1944                         else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
1945                         else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
1946                         else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
1947                         else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
1948                         else return;
1949                 }
1950
1951                 rv3d->view= view;
1952         }
1953
1954         if(rv3d->viewlock) {
1955                 ED_region_tag_redraw(CTX_wm_region(C));
1956                 return;
1957         }
1958
1959         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1960
1961                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= view ? RV3D_ORTHO : RV3D_PERSP;
1962                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1963
1964                 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1965         }
1966         else {
1967
1968                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= view ? RV3D_ORTHO : RV3D_PERSP;
1969                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1970
1971                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1972         }
1973
1974 }
1975
1976 static int viewnumpad_exec(bContext *C, wmOperator *op)
1977 {
1978         View3D *v3d = CTX_wm_view3d(C);
1979         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1980         Scene *scene= CTX_data_scene(C);
1981         static int perspo=RV3D_PERSP;
1982         int viewnum, align_active, nextperspo;
1983
1984         viewnum = RNA_enum_get(op->ptr, "type");
1985         align_active = RNA_boolean_get(op->ptr, "align_active");
1986
1987         /* set this to zero, gets handled in axis_set_view */
1988         if(rv3d->viewlock)
1989                 align_active= 0;
1990
1991         /* Use this to test if we started out with a camera */
1992
1993         if (rv3d->persp == RV3D_CAMOB) {
1994                 nextperspo= rv3d->lpersp;
1995         } else {
1996                 nextperspo= perspo;
1997         }
1998
1999         switch (viewnum) {
2000                 case RV3D_VIEW_BOTTOM :
2001                         axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, nextperspo, align_active);
2002                         break;
2003
2004                 case RV3D_VIEW_BACK:
2005                         axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, nextperspo, align_active);
2006                         break;
2007
2008                 case RV3D_VIEW_LEFT:
2009                         axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, nextperspo, align_active);
2010                         break;
2011
2012                 case RV3D_VIEW_TOP:
2013                         axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, nextperspo, align_active);
2014                         break;
2015
2016                 case RV3D_VIEW_FRONT:
2017                         axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, nextperspo, align_active);
2018                         break;
2019
2020                 case RV3D_VIEW_RIGHT:
2021                         axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, nextperspo, align_active);
2022                         break;
2023
2024                 case RV3D_VIEW_CAMERA:
2025                         if(rv3d->viewlock==0) {
2026                                 /* lastview -  */
2027
2028                                 if(rv3d->persp != RV3D_CAMOB) {
2029                                         Object *ob= OBACT;
2030
2031                                         if (!rv3d->smooth_timer) {
2032                                                 /* store settings of current view before allowing overwriting with camera view
2033                                                  * only if we're not currently in a view transition */
2034                                                 copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
2035                                                 rv3d->lview= rv3d->view;
2036                                                 rv3d->lpersp= rv3d->persp;
2037                                         }
2038
2039         #if 0
2040                                         if(G.qual==LR_ALTKEY) {
2041                                                 if(oldcamera && is_an_active_object(oldcamera)) {
2042                                                         v3d->camera= oldcamera;
2043                                                 }
2044                                                 handle_view3d_lock();
2045                                         }
2046         #endif
2047                                         
2048                                         /* first get the default camera for the view lock type */
2049                                         if(v3d->scenelock) {
2050                                                 /* sets the camera view if available */
2051                                                 v3d->camera= scene->camera;                                             
2052                                         }
2053                                         else {
2054                                                 /* use scene camera if one is not set (even though we're unlocked) */
2055                                                 if(v3d->camera==NULL) {
2056                                                         v3d->camera= scene->camera;
2057                                                 }
2058                                         }
2059
2060                                         /* if the camera isnt found, check a number of options */
2061                                         if(v3d->camera==NULL && ob && ob->type==OB_CAMERA)
2062                                                 v3d->camera= ob;
2063                                         
2064                                         if(v3d->camera==NULL)
2065                                                 v3d->camera= scene_find_camera(scene);          
2066
2067                                         /* couldnt find any useful camera, bail out */
2068                                         if(v3d->camera==NULL)
2069                                                 return OPERATOR_CANCELLED;
2070                                         
2071                                         /* important these dont get out of sync for locked scenes */
2072                                         if(v3d->scenelock)
2073                                                 scene->camera= v3d->camera;
2074
2075                                         /* finally do snazzy view zooming */
2076                                         rv3d->persp= RV3D_CAMOB;
2077                                         smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
2078
2079                                 }
2080                                 else{
2081                                         /* return to settings of last view */
2082                                         /* does smooth_view too */
2083                                         axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
2084                                 }
2085                         }
2086                         break;
2087
2088                 default :
2089                         break;
2090         }
2091
2092         if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
2093
2094         return OPERATOR_FINISHED;
2095 }
2096
2097
2098 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
2099 {
2100         /* identifiers */
2101         ot->name= "View numpad";
2102         ot->description = "Set the view";
2103         ot->idname= "VIEW3D_OT_viewnumpad";
2104
2105         /* api callbacks */
2106         ot->exec= viewnumpad_exec;
2107         ot->poll= ED_operator_region_view3d_active;
2108
2109         /* flags */
2110         ot->flag= 0;
2111
2112         RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
2113         RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
2114 }
2115
2116 static EnumPropertyItem prop_view_orbit_items[] = {
2117         {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
2118         {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
2119         {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
2120         {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
2121         {0, NULL, 0, NULL, NULL}};
2122
2123 static int vieworbit_exec(bContext *C, wmOperator *op)
2124 {
2125         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2126         float phi, q1[4], new_quat[4];
2127         int orbitdir;
2128
2129         orbitdir = RNA_enum_get(op->ptr, "type");
2130
2131         if(rv3d->viewlock==0) {
2132
2133                 if(rv3d->persp != RV3D_CAMOB) {
2134                         if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
2135                                 float si;
2136                                 /* z-axis */
2137                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
2138                                 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
2139                                 si= (float)sin(phi);
2140                                 q1[0]= (float)cos(phi);
2141                                 q1[1]= q1[2]= 0.0;
2142                                 q1[3]= si;
2143                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
2144                                 rv3d->view= 0;
2145                         }
2146                         else if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
2147                                 /* horizontal axis */
2148                                 copy_v3_v3(q1+1, rv3d->viewinv[0]);
2149
2150                                 normalize_v3(q1+1);
2151                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
2152                                 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
2153                                 q1[0]= (float)cos(phi);
2154                                 mul_v3_fl(q1+1, sin(phi));
2155                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
2156                                 rv3d->view= 0;
2157                         }
2158
2159                         smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
2160                 }
2161         }
2162
2163         return OPERATOR_FINISHED;
2164 }
2165
2166 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
2167 {
2168         /* identifiers */
2169         ot->name= "View Orbit";
2170         ot->description = "Orbit the view";
2171         ot->idname= "VIEW3D_OT_view_orbit";
2172
2173         /* api callbacks */
2174         ot->exec= vieworbit_exec;
2175         ot->poll= ED_operator_region_view3d_active;
2176
2177         /* flags */
2178         ot->flag= 0;
2179         RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
2180 }
2181
2182 static EnumPropertyItem prop_view_pan_items[] = {
2183         {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
2184         {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
2185         {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
2186         {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
2187         {0, NULL, 0, NULL, NULL}};
2188
2189 static int viewpan_exec(bContext *C, wmOperator *op)
2190 {
2191         ARegion *ar= CTX_wm_region(C);
2192         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2193         float vec[3];
2194         int pandir;
2195
2196         pandir = RNA_enum_get(op->ptr, "type");
2197
2198         initgrabz(rv3d, 0.0, 0.0, 0.0);
2199         if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
2200         else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
2201         else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
2202         else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
2203         add_v3_v3(rv3d->ofs, vec);
2204
2205         if(rv3d->viewlock & RV3D_BOXVIEW)
2206                 view3d_boxview_sync(CTX_wm_area(C), ar);
2207
2208         ED_region_tag_redraw(ar);
2209
2210         return OPERATOR_FINISHED;
2211 }
2212
2213 void VIEW3D_OT_view_pan(wmOperatorType *ot)
2214 {
2215         /* identifiers */
2216         ot->name= "View Pan";
2217         ot->description = "Pan the view";
2218         ot->idname= "VIEW3D_OT_view_pan";
2219
2220         /* api callbacks */
2221         ot->exec= viewpan_exec;
2222         ot->poll= ED_operator_region_view3d_active;
2223
2224         /* flags */
2225         ot->flag= 0;
2226         RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
2227 }
2228
2229 static int viewpersportho_exec(bContext *C, wmOperator *UNUSED(op))
2230 {
2231         ARegion *ar= CTX_wm_region(C);
2232         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2233
2234         if(rv3d->viewlock==0) {
2235                 if(rv3d->persp!=RV3D_ORTHO)
2236                         rv3d->persp=RV3D_ORTHO;
2237                 else rv3d->persp=RV3D_PERSP;
2238                 ED_region_tag_redraw(ar);
2239         }
2240
2241         return OPERATOR_FINISHED;
2242
2243 }
2244
2245 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
2246 {
2247         /* identifiers */
2248         ot->name= "View Persp/Ortho";
2249         ot->description = "Switch the current view from perspective/orthographic";
2250         ot->idname= "VIEW3D_OT_view_persportho";
2251
2252         /* api callbacks */
2253         ot->exec= viewpersportho_exec;
2254         ot->poll= ED_operator_region_view3d_active;
2255
2256         /* flags */
2257         ot->flag= 0;
2258 }
2259
2260 /* ******************** add background image operator **************** */
2261
2262 static BGpic *background_image_add(bContext *C)
2263 {
2264         View3D *v3d= CTX_wm_view3d(C);
2265         
2266         BGpic *bgpic= MEM_callocN(sizeof(BGpic), "Background Image");
2267         bgpic->size= 5.0;
2268         bgpic->blend= 0.5;
2269         bgpic->iuser.fie_ima= 2;
2270         bgpic->iuser.ok= 1;
2271         bgpic->view= 0; /* 0 for all */
2272         
2273         BLI_addtail(&v3d->bgpicbase, bgpic);
2274         
2275         return bgpic;
2276 }
2277
2278 static int background_image_add_exec(bContext *C, wmOperator *UNUSED(op))
2279 {
2280         background_image_add(C);
2281
2282         return OPERATOR_FINISHED;
2283 }
2284
2285 static int background_image_add_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2286 {
2287         View3D *v3d= CTX_wm_view3d(C);
2288         Image *ima= NULL;
2289         BGpic *bgpic;
2290         char name[32];
2291         
2292         /* check input variables */
2293         if(RNA_property_is_set(op->ptr, "filepath")) {
2294                 char path[FILE_MAX];
2295                 
2296                 RNA_string_get(op->ptr, "filepath", path);
2297                 ima= BKE_add_image_file(path);
2298         }
2299         else if(RNA_property_is_set(op->ptr, "name")) {
2300                 RNA_string_get(op->ptr, "name", name);
2301                 ima= (Image *)find_id("IM", name);
2302         }
2303         
2304         bgpic = background_image_add(C);
2305         
2306         if (ima) {
2307                 bgpic->ima = ima;
2308                 
2309                 if(ima->id.us==0) id_us_plus(&ima->id);
2310                 else id_lib_extern(&ima->id);
2311                 
2312                 if (!(v3d->flag & V3D_DISPBGPICS))
2313                         v3d->flag |= V3D_DISPBGPICS;
2314         }
2315         
2316         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2317         
2318         return OPERATOR_FINISHED;
2319 }
2320
2321 void VIEW3D_OT_background_image_add(wmOperatorType *ot)
2322 {
2323         /* identifiers */
2324         ot->name   = "Add Background Image";
2325         ot->description= "Add a new background image";
2326         ot->idname = "VIEW3D_OT_background_image_add";
2327
2328         /* api callbacks */
2329         ot->invoke = background_image_add_invoke;
2330         ot->exec   = background_image_add_exec;
2331         ot->poll   = ED_operator_view3d_active;
2332
2333         /* flags */
2334         ot->flag   = 0;
2335         
2336         /* properties */
2337         RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Image name to assign.");
2338         RNA_def_string(ot->srna, "filepath", "Path", FILE_MAX, "Filepath", "Path to image file");
2339 }
2340
2341
2342 /* ***** remove image operator ******* */
2343 static int background_image_remove_exec(bContext *C, wmOperator *op)
2344 {
2345         View3D *vd = CTX_wm_view3d(C);
2346         int index = RNA_int_get(op->ptr, "index");
2347         BGpic *bgpic_rem= BLI_findlink(&vd->bgpicbase, index);
2348
2349         if(bgpic_rem) {
2350                 BLI_remlink(&vd->bgpicbase, bgpic_rem);
2351                 if(bgpic_rem->ima) bgpic_rem->ima->id.us--;
2352                 MEM_freeN(bgpic_rem);
2353                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, vd);
2354                 return OPERATOR_FINISHED;
2355         }
2356         else {
2357                 return OPERATOR_CANCELLED;
2358         }
2359
2360 }
2361
2362 void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
2363 {
2364         /* identifiers */
2365         ot->name   = "Remove Background Image";
2366         ot->description= "Remove a background image from the 3D view";
2367         ot->idname = "VIEW3D_OT_background_image_remove";
2368
2369         /* api callbacks */
2370         ot->exec   = background_image_remove_exec;
2371         ot->poll   = ED_operator_view3d_active;
2372
2373         /* flags */
2374         ot->flag   = 0;
2375
2376         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove ", 0, INT_MAX);
2377 }
2378
2379 /* ********************* set clipping operator ****************** */
2380
2381 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
2382 {
2383         int val;
2384
2385         for(val=0; val<4; val++) {
2386
2387                 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
2388
2389                 clip[val][3]=
2390                         - clip[val][0]*clipbb->vec[val][0]
2391                         - clip[val][1]*clipbb->vec[val][1]
2392                         - clip[val][2]*clipbb->vec[val][2];
2393         }
2394 }
2395
2396 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
2397 {
2398         BoundBox clipbb_local;
2399         float imat[4][4];
2400         int i;
2401
2402         invert_m4_m4(imat, mat);
2403
2404         for(i=0; i<8; i++) {
2405                 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
2406         }
2407
2408         calc_clipping_plane(clip_local, &clipbb_local);
2409 }
2410
2411 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
2412 {
2413         if(rv3d->rflag & RV3D_CLIPPING)
2414                 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
2415 }
2416
2417 static int view3d_clipping_exec(bContext *C, wmOperator *op)
2418 {
2419         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2420         ViewContext vc;
2421         bglMats mats;
2422         rcti rect;
2423
2424         rect.xmin= RNA_int_get(op->ptr, "xmin");
2425         rect.ymin= RNA_int_get(op->ptr, "ymin");
2426         rect.xmax= RNA_int_get(op->ptr, "xmax");
2427         rect.ymax= RNA_int_get(op->ptr, "ymax");
2428
2429         rv3d->rflag |= RV3D_CLIPPING;
2430         rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
2431
2432         /* note; otherwise opengl won't work */
2433         view3d_operator_needs_opengl(C);
2434
2435         view3d_set_viewcontext(C, &vc);
2436         view3d_get_transformation(vc.ar, vc.rv3d, NULL, &mats); /* NULL because we don't want it in object space */
2437         view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
2438
2439         return OPERATOR_FINISHED;
2440 }
2441
2442 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
2443 {
2444         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2445         ARegion *ar= CTX_wm_region(C);
2446
2447         if(rv3d->rflag & RV3D_CLIPPING) {
2448                 rv3d->rflag &= ~RV3D_CLIPPING;
2449                 ED_region_tag_redraw(ar);
2450                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
2451                 rv3d->clipbb= NULL;
2452                 return OPERATOR_FINISHED;
2453         }
2454         else {
2455                 return WM_border_select_invoke(C, op, event);
2456         }
2457 }
2458
2459 /* toggles */
2460 void VIEW3D_OT_clip_border(wmOperatorType *ot)
2461 {
2462
2463         /* identifiers */
2464         ot->name= "Clipping Border";
2465         ot->description = "Set the view clipping border";
2466         ot->idname= "VIEW3D_OT_clip_border";
2467
2468         /* api callbacks */
2469         ot->invoke= view3d_clipping_invoke;
2470         ot->exec= view3d_clipping_exec;
2471         ot->modal= WM_border_select_modal;
2472
2473         ot->poll= ED_operator_region_view3d_active;
2474
2475         /* flags */
2476         ot->flag= 0;
2477
2478         /* rna */
2479         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2480         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2481         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2482         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2483 }
2484
2485 /* ***************** 3d cursor cursor op ******************* */
2486
2487 /* mx my in region coords */
2488 static int set_3dcursor_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
2489 {
2490         Scene *scene= CTX_data_scene(C);
2491         ARegion *ar= CTX_wm_region(C);
2492         View3D *v3d = CTX_wm_view3d(C);
2493         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2494         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2495         short mx, my, mval[2];
2496 //      short ctrl= 0; // XXX
2497         int flip;
2498         fp= give_cursor(scene, v3d);
2499
2500 //      if(obedit && ctrl) lr_click= 1;
2501         copy_v3_v3(oldcurs, fp);
2502
2503         mx= event->x - ar->winrct.xmin;
2504         my= event->y - ar->winrct.ymin;
2505
2506         project_short_noclip(ar, fp, mval);
2507         flip= initgrabz(rv3d, fp[0], fp[1], fp[2]);
2508         
2509         /* reset the depth based on the view offset */
2510         if(flip) {
2511                 negate_v3_v3(fp, rv3d->ofs);
2512
2513                 /* re initialize */
2514                 project_short_noclip(ar, fp, mval);
2515                 flip= initgrabz(rv3d, fp[0], fp[1], fp[2]);
2516         }
2517
2518         if(mval[0]!=IS_CLIPPED) {
2519                 short depth_used = 0;
2520
2521                 if (U.uiflag & USER_ORBIT_ZBUF) { /* maybe this should be accessed some other way */
2522                         short mval_depth[2];
2523                         mval_depth[0]= mx;
2524                         mval_depth[1]= my;
2525                         view3d_operator_needs_opengl(C);
2526                         if (view_autodist(scene, ar, v3d, mval_depth, fp))
2527                                 depth_used= 1;
2528                 }
2529
2530                 if(depth_used==0) {
2531                         window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2532                         sub_v3_v3(fp, dvec);
2533                 }
2534         }
2535         else {
2536
2537                 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2538                 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2539
2540                 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2541                 fz= fz/rv3d->zfac;
2542
2543                 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2544                 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2545                 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2546         }
2547
2548         if(v3d && v3d->localvd)
2549                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2550         else
2551                 WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene);
2552
2553         return OPERATOR_FINISHED;
2554 }
2555
2556 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2557 {
2558
2559         /* identifiers */
2560         ot->name= "Set 3D Cursor";
2561         ot->description = "Set the location of the 3D cursor";
2562         ot->idname= "VIEW3D_OT_cursor3d";
2563
2564         /* api callbacks */
2565         ot->invoke= set_3dcursor_invoke;
2566
2567         ot->poll= ED_operator_view3d_active;
2568
2569         /* flags */
2570 //      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2571
2572         /* rna later */
2573
2574 }
2575
2576 /* ***************** manipulator op ******************* */
2577
2578
2579 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2580 {
2581         View3D *v3d = CTX_wm_view3d(C);
2582
2583         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2584         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2585
2586         /* only no modifier or shift */
2587         if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2588
2589         /* note; otherwise opengl won't work */
2590         view3d_operator_needs_opengl(C);
2591
2592         if(0==BIF_do_manipulator(C, event, op))
2593                 return OPERATOR_PASS_THROUGH;
2594
2595         return OPERATOR_FINISHED;
2596 }
2597
2598 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2599 {
2600
2601         /* identifiers */
2602         ot->name= "3D Manipulator";
2603         ot->description = "Manipulate selected item by axis";
2604         ot->idname= "VIEW3D_OT_manipulator";
2605
2606         /* api callbacks */
2607         ot->invoke= manipulator_invoke;
2608
2609         ot->poll= ED_operator_view3d_active;
2610
2611         /* properties to pass to transform */
2612         Transform_Properties(ot, P_CONSTRAINT);
2613 }
2614
2615 static int enable_manipulator_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2616 {
2617         View3D *v3d = CTX_wm_view3d(C);
2618
2619         v3d->twtype=0;
2620         
2621         if (RNA_boolean_get(op->ptr, "translate"))
2622                 v3d->twtype |= V3D_MANIP_TRANSLATE;
2623         if (RNA_boolean_get(op->ptr, "rotate"))
2624                 v3d->twtype |= V3D_MANIP_ROTATE;
2625         if (RNA_boolean_get(op->ptr, "scale"))
2626                 v3d->twtype |= V3D_MANIP_SCALE;
2627                 
2628         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2629
2630         return OPERATOR_FINISHED;
2631 }
2632
2633 void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
2634 {
2635         /* identifiers */
2636         ot->name= "Enable 3D Manipulator";
2637         ot->description = "Enable the transform manipulator for use";
2638         ot->idname= "VIEW3D_OT_enable_manipulator";
2639         
2640         /* api callbacks */
2641         ot->invoke= enable_manipulator_invoke;
2642         ot->poll= ED_operator_view3d_active;
2643         
2644         /* rna later */
2645         RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator");
2646         RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator");
2647         RNA_def_boolean(ot->srna, "scale", 0, "Scale", "Enable the scale manipulator");
2648 }
2649
2650 /* ************************* below the line! *********************** */
2651
2652
2653 static float view_autodist_depth_margin(ARegion *ar, short mval[2], int margin)
2654 {
2655         ViewDepths depth_temp= {0};
2656         rcti rect;
2657         float depth_close;
2658
2659         if(margin==0) {
2660                 /* Get Z Depths, needed for perspective, nice for ortho */
2661                 rect.xmin= mval[0];
2662                 rect.ymin= mval[1];
2663                 rect.xmax= mval[0] + 1;
2664                 rect.ymax= mval[1] + 1;
2665         }
2666         else {
2667                 rect.xmax = mval[0] + margin;
2668                 rect.ymax = mval[1] + margin;
2669
2670                 rect.xmin = mval[0] - margin;
2671                 rect.ymin = mval[1] - margin;
2672         }
2673
2674         view3d_update_depths_rect(ar, &depth_temp, &rect);
2675         depth_close= view3d_depth_near(&depth_temp);
2676         if(depth_temp.depths) MEM_freeN(depth_temp.depths);
2677         return depth_close;
2678 }
2679
2680 /* XXX todo Zooms in on a border drawn by the user */
2681 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2682 {
2683         bglMats mats; /* ZBuffer depth vars */
2684         float depth_close= FLT_MAX;
2685         double cent[2],  p[3];
2686
2687         /* Get Z Depths, needed for perspective, nice for ortho */
2688         bgl_get_mats(&mats);
2689         draw_depth(scene, ar, v3d, NULL);
2690
2691         depth_close= view_autodist_depth_margin(ar, mval, 4);
2692
2693         if (depth_close==FLT_MAX)
2694                 return 0;
2695
2696         cent[0] = (double)mval[0];
2697         cent[1] = (double)mval[1];
2698
2699         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2700                 return 0;
2701
2702         mouse_worldloc[0] = (float)p[0];
2703         mouse_worldloc[1] = (float)p[1];
2704         mouse_worldloc[2] = (float)p[2];
2705         return 1;
2706 }
2707
2708 int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode) //, float *autodist )
2709 {
2710         /* Get Z Depths, needed for perspective, nice for ortho */
2711         switch(mode) {
2712         case 0:
2713                 draw_depth(scene, ar, v3d, NULL);
2714                 break;
2715         case 1:
2716                 draw_depth_gpencil(scene, ar, v3d);
2717                 break;
2718         }
2719
2720         return 1;
2721 }
2722
2723 // no 4x4 sampling, run view_autodist_init first
2724 int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3], int margin, float *force_depth) //, float *autodist )
2725 {
2726         bglMats mats; /* ZBuffer depth vars, could cache? */
2727         float depth;
2728         double cent[2],  p[3];
2729
2730         /* Get Z Depths, needed for perspective, nice for ortho */
2731         if(force_depth)
2732                 depth= *force_depth;
2733         else
2734                 depth= view_autodist_depth_margin(ar, mval, margin);
2735
2736         if (depth==FLT_MAX)
2737                 return 0;
2738
2739         cent[0] = (double)mval[0];
2740         cent[1] = (double)mval[1];
2741
2742         bgl_get_mats(&mats);
2743         if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2744                 return 0;
2745
2746         mouse_worldloc[0] = (float)p[0];
2747         mouse_worldloc[1] = (float)p[1];
2748         mouse_worldloc[2] = (float)p[2];
2749         return 1;
2750 }
2751
2752 int view_autodist_depth(struct ARegion *ar, short mval[2], int margin, float *depth)
2753 {
2754         *depth= view_autodist_depth_margin(ar, mval, margin);
2755
2756         return (*depth==FLT_MAX) ? 0:1;
2757 }
2758
2759 static int depth_segment_cb(int x, int y, void *userData)
2760 {
2761         struct { struct ARegion *ar; int margin; float depth; } *data = userData;
2762         short mval[2];
2763         float depth;
2764
2765         mval[0]= (short)x;
2766         mval[1]= (short)y;
2767
2768         depth= view_autodist_depth_margin(data->ar, mval, data->margin);
2769
2770         if(depth != FLT_MAX) {
2771                 data->depth= depth;
2772                 return 0;
2773         }
2774         else {
2775                 return 1;
2776         }
2777 }
2778
2779 int view_autodist_depth_segment(struct ARegion *ar, short mval_sta[2], short mval_end[2], int margin, float *depth)
2780 {
2781         struct { struct ARegion *ar; int margin; float depth; } data = {NULL};
2782         int p1[2];
2783         int p2[2];
2784
2785         data.ar= ar;
2786         data.margin= margin;
2787         data.depth= FLT_MAX;
2788
2789         VECCOPY2D(p1, mval_sta);
2790         VECCOPY2D(p2, mval_end);
2791
2792         plot_line_v2v2i(p1, p2, depth_segment_cb, &data);
2793
2794         *depth= data.depth;
2795
2796         return (*depth==FLT_MAX) ? 0:1;
2797 }
2798
2799 /* ********************* NDOF ************************ */
2800 /* note: this code is confusing and unclear... (ton) */
2801 /* **************************************************** */
2802
2803 // ndof scaling will be moved to user setting.
2804 // In the mean time this is just a place holder.
2805
2806 // Note: scaling in the plugin and ghostwinlay.c
2807 // should be removed. With driver default setting,
2808 // each axis returns approx. +-200 max deflection.
2809
2810 // The values I selected are based on the older
2811 // polling i/f. With event i/f, the sensistivity
2812 // can be increased for improved response from
2813 // small deflections of the device input.
2814
2815
2816 // lukep notes : i disagree on the range.
2817 // the normal 3Dconnection driver give +/-400
2818 // on defaut range in other applications
2819 // and up to +/- 1000 if set to maximum
2820 // because i remove the scaling by delta,
2821 // which was a bad idea as it depend of the system
2822 // speed and os, i changed the scaling values, but
2823 // those are still not ok
2824
2825 #if 0
2826 static float ndof_axis_scale[6] = {
2827         +0.01,  // Tx
2828         +0.01,  // Tz
2829         +0.01,  // Ty
2830         +0.0015,        // Rx
2831         +0.0015,        // Rz
2832         +0.0015 // Ry
2833 };
2834
2835 static void filterNDOFvalues(float *sbval)
2836 {
2837         int i=0;
2838         float max  = 0.0;
2839
2840         for (i =0; i<6;i++)
2841                 if (fabs(sbval[i]) > max)
2842                         max = fabs(sbval[i]);
2843         for (i =0; i<6;i++)
2844                 if (fabs(sbval[i]) != max )
2845                         sbval[i]=0.0;
2846 }
2847
2848 // statics for controlling rv3d->dist corrections.
2849 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2850 // viewmove restores based on dz_flag state.
2851
2852 int dz_flag = 0;
2853 float m_dist;
2854
2855 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int UNUSED(mode))
2856 {
2857         RegionView3D *rv3d= ar->regiondata;
2858         int i;
2859         float phi;
2860         float dval[7];
2861         // static fval[6] for low pass filter; device input vector is dval[6]
2862         static float fval[6];
2863         float tvec[3],rvec[3];
2864         float q1[4];
2865         float mat[3][3];
2866         float upvec[3];
2867
2868
2869         /*----------------------------------------------------
2870          * sometimes this routine is called from headerbuttons
2871          * viewmove needs to refresh the screen
2872          */
2873 // XXX  areawinset(ar->win);
2874
2875
2876         // fetch the current state of the ndof device
2877 // XXX  getndof(dval);
2878
2879         if (v3d->ndoffilter)
2880                 filterNDOFvalues(fval);
2881
2882         // Scale input values
2883
2884 //      if(dval[6] == 0) return; // guard against divide by zero
2885
2886         for(i=0;i<6;i++) {
2887
2888                 // user scaling
2889                 dval[i] = dval[i] * ndof_axis_scale[i];
2890         }
2891
2892
2893         // low pass filter with zero crossing reset
2894
2895         for(i=0;i<6;i++) {
2896                 if((dval[i] * fval[i]) >= 0)
2897                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
2898                 else
2899                         fval[i] = 0;
2900         }
2901
2902
2903         // force perspective mode. This is a hack and is
2904         // incomplete. It doesn't actually effect the view
2905         // until the first draw and doesn't update the menu
2906         // to reflect persp mode.
2907
2908         rv3d->persp = RV3D_PERSP;
2909
2910
2911         // Correct the distance jump if rv3d->dist != 0
2912
2913         // This is due to a side effect of the original
2914         // mouse view rotation code. The rotation point is
2915         // set a distance in front of the viewport to
2916         // make rotating with the mouse look better.
2917         // The distance effect is written at a low level
2918         // in the view management instead of the mouse
2919         // view function. This means that all other view
2920         // movement devices must subtract this from their
2921         // view transformations.
2922
2923         if(rv3d->dist != 0.0) {
2924                 dz_flag = 1;
2925                 m_dist = rv3d->dist;
2926                 upvec[0] = upvec[1] = 0;
2927                 upvec[2] = rv3d->dist;
2928                 copy_m3_m4(mat, rv3d->viewinv);
2929                 mul_m3_v3(mat, upvec);
2930                 sub_v3_v3(rv3d->ofs, upvec);
2931                 rv3d->dist = 0.0;
2932         }
2933
2934
2935         // Apply rotation
2936         // Rotations feel relatively faster than translations only in fly mode, so
2937         // we have no choice but to fix that here (not in the plugins)
2938         rvec[0] = -0.5 * dval[3];
2939         rvec[1] = -0.5 * dval[4];
2940         rvec[2] = -0.5 * dval[5];
2941
2942         // rotate device x and y by view z
2943
2944         copy_m3_m4(mat, rv3d->viewinv);
2945         mat[2][2] = 0.0f;
2946         mul_m3_v3(mat, rvec);
2947
2948         // rotate the view
2949
2950         phi = normalize_v3(rvec);
2951         if(phi != 0) {
2952                 axis_angle_to_quat(q1,rvec,phi);
2953                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2954         }
2955
2956
2957         // Apply translation
2958
2959         tvec[0] = dval[0];
2960         tvec[1] = dval[1];
2961         tvec[2] = -dval[2];
2962
2963         // the next three lines rotate the x and y translation coordinates
2964         // by the current z axis angle
2965
2966         copy_m3_m4(mat, rv3d->viewinv);
2967         mat[2][2] = 0.0f;
2968         mul_m3_v3(mat, tvec);
2969
2970         // translate the view
2971
2972         sub_v3_v3(rv3d->ofs, tvec);
2973
2974
2975         /*----------------------------------------------------
2976          * refresh the screen XXX
2977           */
2978
2979         // update render preview window
2980
2981 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2982 }
2983
2984 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int UNUSED(mode))
2985 {
2986         RegionView3D *rv3d= ar->regiondata;
2987         float fval[7];
2988         float dvec[3];
2989         float sbadjust = 1.0f;
2990         float len;
2991         short use_sel = 0;
2992         Object *ob = OBACT;
2993         float m[3][3];
2994         float m_inv[3][3];
2995         float xvec[3] = {1,0,0};
2996         float yvec[3] = {0,-1,0};
2997         float zvec[3] = {0,0,1};
2998         float phi;
2999         float q1[4];
3000         float obofs[3];
3001         float reverse;
3002         //float diff[4];
3003         float d, curareaX, curareaY;
3004         float mat[3][3];
3005         float upvec[3];
3006
3007         /* Sensitivity will control how fast the view rotates.  The value was
3008          * obtained experimentally by tweaking until the author didn't get dizzy watching.
3009          * Perhaps this should be a configurable user parameter.
3010          */
3011         float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
3012         float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
3013         float zsens = 0.3f;   /* zoom sensitivity */
3014
3015         const float minZoom = -30.0f;
3016         const float maxZoom = 300.0f;
3017
3018         //reset view type
3019         rv3d->view = 0;
3020 //printf("passing here \n");
3021 //
3022         if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
3023                 use_sel = 1;
3024         }
3025
3026         if((dz_flag)||rv3d->dist==0) {
3027                 dz_flag = 0;
3028                 rv3d->dist = m_dist;
3029                 upvec[0] = upvec[1] = 0;
3030                 upvec[2] = rv3d->dist;
3031                 copy_m3_m4(mat, rv3d->viewinv);
3032                 mul_m3_v3(mat, upvec);
3033                 add_v3_v3(rv3d->ofs, upvec);
3034         }
3035
3036         /*----------------------------------------------------
3037          * sometimes this routine is called from headerbuttons
3038          * viewmove needs to refresh the screen
3039          */
3040 // XXX  areawinset(curarea->win);
3041
3042         /*----------------------------------------------------
3043          * record how much time has passed. clamp at 10 Hz
3044          * pretend the previous frame occurred at the clamped time
3045          */
3046 //    now = PIL_check_seconds_timer();
3047  //   frametime = (now - prevTime);
3048  //   if (frametime > 0.1f){        /* if more than 1/10s */
3049  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
3050 //    }
3051 //    prevTime = now;
3052  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
3053
3054         /* fetch the current state of the ndof device & enforce dominant mode if selected */
3055 // XXX    getndof(fval);
3056         if (v3d->ndoffilter)
3057                 filterNDOFvalues(fval);
3058
3059
3060         // put scaling back here, was previously in ghostwinlay
3061         fval[0] = fval[0] * (1.0f/600.0f);
3062         fval[1] = fval[1] * (1.0f/600.0f);
3063         fval[2] = fval[2] * (1.0f/1100.0f);
3064         fval[3] = fval[3] * 0.00005f;
3065         fval[4] =-fval[4] * 0.00005f;
3066         fval[5] = fval[5] * 0.00005f;
3067         fval[6] = fval[6] / 1000000.0f;
3068
3069         // scale more if not in perspective mode
3070         if (rv3d->persp == RV3D_ORTHO) {
3071                 fval[0] = fval[0] * 0.05f;
3072                 fval[1] = fval[1] * 0.05f;
3073                 fval[2] = fval[2] * 0.05f;
3074                 fval[3] = fval[3] * 0.9f;
3075                 fval[4] = fval[4] * 0.9f;
3076                 fval[5] = fval[5] * 0.9f;
3077                 zsens *= 8;
3078         }
3079
3080         /* set object offset */
3081         if (ob) {
3082                 obofs[0] = -ob->obmat[3][0];
3083                 obofs[1] = -ob->obmat[3][1];
3084                 obofs[2] = -ob->obmat[3][2];
3085         }
3086         else {
3087                 copy_v3_v3(obofs, rv3d->ofs);
3088         }
3089
3090         /* calc an adjustment based on distance from camera
3091            disabled per patch 14402 */
3092          d = 1.0f;
3093
3094 /*    if (ob) {
3095                 sub_v3_v3v3(diff, obofs, rv3d->ofs);
3096                 d = len_v3(diff);
3097         }
3098 */
3099
3100         reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
3101
3102         /*----------------------------------------------------
3103          * ndof device pan
3104          */
3105         psens *= 1.0f + d;
3106         curareaX = sbadjust * psens * fval[0];
3107         curareaY = sbadjust * psens * fval[1];
3108         dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
3109         dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
3110         dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
3111         add_v3_v3(rv3d->ofs, dvec);
3112
3113         /*----------------------------------------------------
3114          * ndof device dolly
3115          */
3116         len = zsens * sbadjust * fval[2];
3117
3118         if (rv3d->persp==RV3D_CAMOB) {
3119                 if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
3120                         rv3d->camzoom+= 10.0f * -len;
3121                 }
3122                 if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
3123                 else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
3124         }
3125         else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
3126                 rv3d->dist*=(1.0 + len);
3127         }
3128
3129
3130         /*----------------------------------------------------
3131          * ndof device turntable
3132          * derived from the turntable code in viewmove
3133          */
3134
3135         /* Get the 3x3 matrix and its inverse from the quaternion */
3136         quat_to_mat3( m,rv3d->viewquat);
3137         invert_m3_m3(m_inv,m);
3138
3139         /* Determine the directi