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