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