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