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