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