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