more lint includes
[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_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
546                         mul_qt_v3(q1, rv3d->ofs);
547                         add_v3_v3v3(rv3d->ofs, 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_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
579                         mul_qt_v3(q1, rv3d->ofs);
580                         add_v3_v3v3(rv3d->ofs, 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_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
593                         mul_qt_v3(q1, rv3d->ofs);
594                         add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
595                 }
596         }
597
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_v3v3(vod->rv3d->ofs, 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_v3v3(vod->rv3d->ofs, 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         Scene *scene= CTX_data_scene(C);
1486
1487         rcti rect;
1488         rctf vb;
1489
1490         /* get border select values using rna */
1491         rect.xmin= RNA_int_get(op->ptr, "xmin");
1492         rect.ymin= RNA_int_get(op->ptr, "ymin");
1493         rect.xmax= RNA_int_get(op->ptr, "xmax");
1494         rect.ymax= RNA_int_get(op->ptr, "ymax");
1495
1496         /* calculate range */
1497         calc_viewborder(scene, ar, v3d, &vb);
1498
1499         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1500         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1501         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1502         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1503
1504         /* actually set border */
1505         CLAMP(scene->r.border.xmin, 0.0, 1.0);
1506         CLAMP(scene->r.border.ymin, 0.0, 1.0);
1507         CLAMP(scene->r.border.xmax, 0.0, 1.0);
1508         CLAMP(scene->r.border.ymax, 0.0, 1.0);
1509
1510         /* drawing a border surrounding the entire camera view switches off border rendering
1511          * or the border covers no pixels */
1512         if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1513                 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1514            (scene->r.border.xmin == scene->r.border.xmax ||
1515                 scene->r.border.ymin == scene->r.border.ymax ))
1516         {
1517                 scene->r.mode &= ~R_BORDER;
1518         } else {
1519                 scene->r.mode |= R_BORDER;
1520         }
1521         
1522         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, NULL);
1523
1524         return OPERATOR_FINISHED;
1525
1526 }
1527
1528 static int view3d_render_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1529 {
1530         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1531
1532         /* if not in camera view do not exec the operator*/
1533         if (rv3d->persp == RV3D_CAMOB) return WM_border_select_invoke(C, op, event);
1534         else return OPERATOR_PASS_THROUGH;
1535 }
1536
1537 void VIEW3D_OT_render_border(wmOperatorType *ot)
1538 {
1539         /* identifiers */
1540         ot->name= "Set Render Border";
1541         ot->description = "Set the boundries of the border render and enables border render ";
1542         ot->idname= "VIEW3D_OT_render_border";
1543
1544         /* api callbacks */
1545         ot->invoke= view3d_render_border_invoke;
1546         ot->exec= render_border_exec;
1547         ot->modal= WM_border_select_modal;
1548
1549         ot->poll= ED_operator_view3d_active;
1550
1551         /* flags */
1552         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1553
1554         /* rna */
1555         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1556         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1557         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1558         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1559
1560 }
1561 /* ********************* Border Zoom operator ****************** */
1562
1563 static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
1564 {
1565         ARegion *ar= CTX_wm_region(C);
1566         View3D *v3d = CTX_wm_view3d(C);
1567         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1568         Scene *scene= CTX_data_scene(C);
1569
1570         /* Zooms in on a border drawn by the user */
1571         rcti rect;
1572         float dvec[3], vb[2], xscale, yscale, scale;
1573
1574         /* SMOOTHVIEW */
1575         float new_dist;
1576         float new_ofs[3];
1577
1578         /* ZBuffer depth vars */
1579         bglMats mats;
1580         float depth, depth_close= FLT_MAX;
1581         int had_depth = 0;
1582         double cent[2],  p[3];
1583         int xs, ys;
1584
1585         /* note; otherwise opengl won't work */
1586         view3d_operator_needs_opengl(C);
1587
1588         /* get border select values using rna */
1589         rect.xmin= RNA_int_get(op->ptr, "xmin");
1590         rect.ymin= RNA_int_get(op->ptr, "ymin");
1591         rect.xmax= RNA_int_get(op->ptr, "xmax");
1592         rect.ymax= RNA_int_get(op->ptr, "ymax");
1593
1594         /* Get Z Depths, needed for perspective, nice for ortho */
1595         bgl_get_mats(&mats);
1596         draw_depth(scene, ar, v3d, NULL);
1597
1598         /* force updating */
1599         if (rv3d->depths) {
1600                 had_depth = 1;
1601                 rv3d->depths->damaged = 1;
1602         }
1603
1604         view3d_update_depths(ar, v3d);
1605
1606         /* Constrain rect to depth bounds */
1607         if (rect.xmin < 0) rect.xmin = 0;
1608         if (rect.ymin < 0) rect.ymin = 0;
1609         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1610         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1611
1612         /* Find the closest Z pixel */
1613         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1614                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1615                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1616                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1617                                 if (depth_close > depth) {
1618                                         depth_close = depth;
1619                                 }
1620                         }
1621                 }
1622         }
1623
1624         if (had_depth==0) {
1625                 MEM_freeN(rv3d->depths->depths);
1626                 rv3d->depths->depths = NULL;
1627         }
1628         rv3d->depths->damaged = 1;
1629
1630         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1631         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1632
1633         if (rv3d->persp==RV3D_PERSP) {
1634                 double p_corner[3];
1635
1636                 /* no depths to use, we cant do anything! */
1637                 if (depth_close==FLT_MAX){
1638                         BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1639                         return OPERATOR_CANCELLED;
1640                 }
1641                 /* convert border to 3d coordinates */
1642                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1643                         (       !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])))
1644                         return OPERATOR_CANCELLED;
1645
1646                 dvec[0] = p[0]-p_corner[0];
1647                 dvec[1] = p[1]-p_corner[1];
1648                 dvec[2] = p[2]-p_corner[2];
1649
1650                 new_dist = len_v3(dvec);
1651                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1652
1653                 new_ofs[0] = -p[0];
1654                 new_ofs[1] = -p[1];
1655                 new_ofs[2] = -p[2];
1656
1657         } else { /* othographic */
1658                 /* find the current window width and height */
1659                 vb[0] = ar->winx;
1660                 vb[1] = ar->winy;
1661
1662                 new_dist = rv3d->dist;
1663
1664                 /* convert the drawn rectangle into 3d space */
1665                 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])) {
1666                         new_ofs[0] = -p[0];
1667                         new_ofs[1] = -p[1];
1668                         new_ofs[2] = -p[2];
1669                 } else {
1670                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1671                         copy_v3_v3(new_ofs, rv3d->ofs);
1672
1673                         initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1674
1675                         window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1676                         /* center the view to the center of the rectangle */
1677                         sub_v3_v3v3(new_ofs, new_ofs, dvec);
1678                 }
1679
1680                 /* work out the ratios, so that everything selected fits when we zoom */
1681                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1682                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1683                 scale = (xscale >= yscale)?xscale:yscale;
1684
1685                 /* zoom in as required, or as far as we can go */
1686                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1687         }
1688
1689         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1690
1691         if(rv3d->viewlock & RV3D_BOXVIEW)
1692                 view3d_boxview_sync(CTX_wm_area(C), ar);
1693
1694         return OPERATOR_FINISHED;
1695 }
1696
1697 static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1698 {
1699         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1700
1701         /* if in camera view do not exec the operator so we do not conflict with set render border*/
1702         if (rv3d->persp != RV3D_CAMOB)
1703                 return WM_border_select_invoke(C, op, event);
1704         else
1705                 return OPERATOR_PASS_THROUGH;
1706 }
1707
1708 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1709 {
1710
1711         /* identifiers */
1712         ot->name= "Border Zoom";
1713         ot->description = "Zoom in the view to the nearest object contained in the border";
1714         ot->idname= "VIEW3D_OT_zoom_border";
1715
1716         /* api callbacks */
1717         ot->invoke= view3d_zoom_border_invoke;
1718         ot->exec= view3d_zoom_border_exec;
1719         ot->modal= WM_border_select_modal;
1720
1721         ot->poll= ED_operator_view3d_active;
1722
1723         /* flags */
1724         ot->flag= 0;
1725
1726         /* rna */
1727         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1728         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1729         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1730         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1731
1732 }
1733 /* ********************* Changing view operator ****************** */
1734
1735 static EnumPropertyItem prop_view_items[] = {
1736         {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1737         {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1738         {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1739         {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1740         {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1741         {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1742         {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1743         {0, NULL, 0, NULL, NULL}};
1744
1745
1746 /* would like to make this a generic function - outside of transform */
1747
1748 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo, int align_active)
1749 {
1750         View3D *v3d = CTX_wm_view3d(C);
1751         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1752         float new_quat[4];
1753
1754         new_quat[0]= q1; new_quat[1]= q2;
1755         new_quat[2]= q3; new_quat[3]= q4;
1756
1757         if(align_active) {
1758                 /* align to active object */
1759                 Object *obact= CTX_data_active_object(C);
1760                 if (obact==NULL) {
1761                         /* no active object, ignore this option */
1762                         align_active= FALSE;
1763                 }
1764                 else {
1765                         float obact_quat[4];
1766                         float twmat[3][3];
1767
1768                         /* same as transform manipulator when normal is set */
1769                         ED_getTransformOrientationMatrix(C, twmat, TRUE);
1770
1771                         mat3_to_quat( obact_quat,twmat);
1772                         invert_qt(obact_quat);
1773                         mul_qt_qtqt(new_quat, new_quat, obact_quat);
1774
1775                         rv3d->view= view= 0;
1776                 }
1777         }
1778
1779         if(align_active==FALSE) {
1780                 /* normal operation */
1781                 if(rv3d->viewlock) {
1782                         /* only pass on if */
1783                         if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
1784                         else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
1785                         else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
1786                         else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
1787                         else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
1788                         else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
1789                         else return;
1790                 }
1791
1792                 rv3d->view= view;
1793         }
1794
1795         if(rv3d->viewlock) {
1796                 ED_region_tag_redraw(CTX_wm_region(C));
1797                 return;
1798         }
1799
1800         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1801
1802                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1803                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1804
1805                 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1806         }
1807         else {
1808
1809                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1810                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1811
1812                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1813         }
1814
1815 }
1816
1817 static int viewnumpad_exec(bContext *C, wmOperator *op)
1818 {
1819         View3D *v3d = CTX_wm_view3d(C);
1820         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1821         Scene *scene= CTX_data_scene(C);
1822         static int perspo=RV3D_PERSP;
1823         int viewnum, align_active, nextperspo;
1824
1825         viewnum = RNA_enum_get(op->ptr, "type");
1826         align_active = RNA_boolean_get(op->ptr, "align_active");
1827
1828
1829         /* Use this to test if we started out with a camera */
1830
1831         if (rv3d->persp == RV3D_CAMOB) {
1832                 nextperspo= rv3d->lpersp;
1833         } else {
1834                 nextperspo= perspo;
1835         }
1836
1837         switch (viewnum) {
1838                 case RV3D_VIEW_BOTTOM :
1839                         axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1840                         break;
1841
1842                 case RV3D_VIEW_BACK:
1843                         axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, nextperspo, align_active);
1844                         break;
1845
1846                 case RV3D_VIEW_LEFT:
1847                         axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, nextperspo, align_active);
1848                         break;
1849
1850                 case RV3D_VIEW_TOP:
1851                         axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1852                         break;
1853
1854                 case RV3D_VIEW_FRONT:
1855                         axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, nextperspo, align_active);
1856                         break;
1857
1858                 case RV3D_VIEW_RIGHT:
1859                         axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, nextperspo, align_active);
1860                         break;
1861
1862                 case RV3D_VIEW_CAMERA:
1863                         if(rv3d->viewlock==0) {
1864                                 /* lastview -  */
1865
1866                                 if(rv3d->persp != RV3D_CAMOB) {
1867
1868                                         if (!rv3d->smooth_timer) {
1869                                                 /* store settings of current view before allowing overwriting with camera view
1870                                                  * only if we're not currently in a view transition */
1871                                                 QUATCOPY(rv3d->lviewquat, rv3d->viewquat);
1872                                                 rv3d->lview= rv3d->view;
1873                                                 rv3d->lpersp= rv3d->persp;
1874                                         }
1875
1876         #if 0
1877                                         if(G.qual==LR_ALTKEY) {
1878                                                 if(oldcamera && is_an_active_object(oldcamera)) {
1879                                                         v3d->camera= oldcamera;
1880                                                 }
1881                                                 handle_view3d_lock();
1882                                         }
1883         #endif
1884
1885                                         if(BASACT) {
1886                                                 /* check both G.vd as G.scene cameras */
1887                                                 if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1888                                                         v3d->camera= OBACT;
1889                                                         /*handle_view3d_lock();*/
1890                                                 }
1891                                         }
1892
1893                                         if(v3d->camera==NULL) {
1894                                                 v3d->camera= scene_find_camera(scene);
1895                                                 /*handle_view3d_lock();*/
1896                                         }
1897                                         rv3d->persp= RV3D_CAMOB;
1898                                         smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
1899
1900                                 }
1901                                 else{
1902                                         /* return to settings of last view */
1903                                         /* does smooth_view too */
1904                                         axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
1905                                 }
1906                         }
1907                         break;
1908
1909                 default :
1910                         break;
1911         }
1912
1913         if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
1914
1915         return OPERATOR_FINISHED;
1916 }
1917 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1918 {
1919         /* identifiers */
1920         ot->name= "View numpad";
1921         ot->description = "Set the view";
1922         ot->idname= "VIEW3D_OT_viewnumpad";
1923
1924         /* api callbacks */
1925         ot->exec= viewnumpad_exec;
1926         ot->poll= ED_operator_view3d_active;
1927
1928         /* flags */
1929         ot->flag= 0;
1930
1931         RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
1932         RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
1933 }
1934
1935 static EnumPropertyItem prop_view_orbit_items[] = {
1936         {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
1937         {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
1938         {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
1939         {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
1940         {0, NULL, 0, NULL, NULL}};
1941
1942 static int vieworbit_exec(bContext *C, wmOperator *op)
1943 {
1944         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1945         float phi, q1[4], new_quat[4];
1946         int orbitdir;
1947
1948         orbitdir = RNA_enum_get(op->ptr, "type");
1949
1950         if(rv3d->viewlock==0) {
1951
1952                 if(rv3d->persp != RV3D_CAMOB) {
1953                         if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
1954                                 float si;
1955                                 /* z-axis */
1956                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1957                                 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
1958                                 si= (float)sin(phi);
1959                                 q1[0]= (float)cos(phi);
1960                                 q1[1]= q1[2]= 0.0;
1961                                 q1[3]= si;
1962                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
1963                                 rv3d->view= 0;
1964                         }
1965                         else if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
1966                                 /* horizontal axis */
1967                                 VECCOPY(q1+1, rv3d->viewinv[0]);
1968
1969                                 normalize_v3(q1+1);
1970                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1971                                 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
1972                                 q1[0]= (float)cos(phi);
1973                                 mul_v3_fl(q1+1, sin(phi));
1974                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
1975                                 rv3d->view= 0;
1976                         }
1977
1978                         smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1979                 }
1980         }
1981
1982         return OPERATOR_FINISHED;
1983 }
1984
1985 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
1986 {
1987         /* identifiers */
1988         ot->name= "View Orbit";
1989         ot->description = "Orbit the view";
1990         ot->idname= "VIEW3D_OT_view_orbit";
1991
1992         /* api callbacks */
1993         ot->exec= vieworbit_exec;
1994         ot->poll= ED_operator_view3d_rotate;
1995
1996         /* flags */
1997         ot->flag= 0;
1998         RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
1999 }
2000
2001 static EnumPropertyItem prop_view_pan_items[] = {
2002         {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
2003         {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
2004         {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
2005         {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
2006         {0, NULL, 0, NULL, NULL}};
2007
2008 static int viewpan_exec(bContext *C, wmOperator *op)
2009 {
2010         ARegion *ar= CTX_wm_region(C);
2011         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2012         float vec[3];
2013         int pandir;
2014
2015         pandir = RNA_enum_get(op->ptr, "type");
2016
2017         initgrabz(rv3d, 0.0, 0.0, 0.0);
2018
2019         if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
2020         else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
2021         else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
2022         else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
2023         rv3d->ofs[0]+= vec[0];
2024         rv3d->ofs[1]+= vec[1];
2025         rv3d->ofs[2]+= vec[2];
2026
2027         if(rv3d->viewlock & RV3D_BOXVIEW)
2028                 view3d_boxview_sync(CTX_wm_area(C), ar);
2029
2030         ED_region_tag_redraw(ar);
2031
2032         return OPERATOR_FINISHED;
2033 }
2034
2035 void VIEW3D_OT_view_pan(wmOperatorType *ot)
2036 {
2037         /* identifiers */
2038         ot->name= "View Pan";
2039         ot->description = "Pan the view";
2040         ot->idname= "VIEW3D_OT_view_pan";
2041
2042         /* api callbacks */
2043         ot->exec= viewpan_exec;
2044         ot->poll= ED_operator_view3d_active;
2045
2046         /* flags */
2047         ot->flag= 0;
2048         RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
2049 }
2050
2051 static int viewpersportho_exec(bContext *C, wmOperator *op)
2052 {
2053         ARegion *ar= CTX_wm_region(C);
2054         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2055
2056         if(rv3d->viewlock==0) {
2057                 if(rv3d->persp!=RV3D_ORTHO)
2058                         rv3d->persp=RV3D_ORTHO;
2059                 else rv3d->persp=RV3D_PERSP;
2060                 ED_region_tag_redraw(ar);
2061         }
2062
2063         return OPERATOR_FINISHED;
2064
2065 }
2066
2067 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
2068 {
2069         /* identifiers */
2070         ot->name= "View Persp/Ortho";
2071         ot->description = "Switch the current view from perspective/orthographic";
2072         ot->idname= "VIEW3D_OT_view_persportho";
2073
2074         /* api callbacks */
2075         ot->exec= viewpersportho_exec;
2076         ot->poll= ED_operator_view3d_active;
2077
2078         /* flags */
2079         ot->flag= 0;
2080 }
2081
2082 /* ******************** add background image operator **************** */
2083
2084 static int add_background_image_exec(bContext *C, wmOperator *op)
2085 {
2086         View3D *v3d= CTX_wm_view3d(C);
2087
2088         BGpic *bgpic= MEM_callocN(sizeof(BGpic), "Background Image");
2089         bgpic->size= 5.0;
2090         bgpic->blend= 0.5;
2091         bgpic->iuser.fie_ima= 2;
2092         bgpic->iuser.ok= 1;
2093         bgpic->view= 0; /* 0 for all */
2094
2095         BLI_addtail(&v3d->bgpicbase, bgpic);
2096
2097         //ED_region_tag_redraw(v3d);
2098
2099         return OPERATOR_FINISHED;
2100 }
2101
2102 static int add_background_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
2103 {
2104         return add_background_image_exec(C, op);
2105 }
2106
2107 void VIEW3D_OT_add_background_image(wmOperatorType *ot)
2108 {
2109         /* identifiers */
2110         ot->name   = "Add Background Image";
2111         ot->description= "Add a new background image";
2112         ot->idname = "VIEW3D_OT_add_background_image";
2113
2114         /* api callbacks */
2115         ot->invoke = add_background_image_invoke;
2116         ot->exec   = add_background_image_exec;
2117         ot->poll   = ED_operator_view3d_active;
2118
2119         /* flags */
2120         ot->flag   = 0;
2121 }
2122
2123 /* ***** remove image operator ******* */
2124 static int remove_background_image_exec(bContext *C, wmOperator *op)
2125 {
2126         BGpic *bgpic_rem = CTX_data_pointer_get_type(C, "bgpic", &RNA_BackgroundImage).data;
2127         View3D *vd = CTX_wm_view3d(C);
2128         int index = RNA_int_get(op->ptr, "index");
2129
2130         bgpic_rem = BLI_findlink(&vd->bgpicbase, index);
2131         if(bgpic_rem) {
2132                 BLI_remlink(&vd->bgpicbase, bgpic_rem);
2133                 if(bgpic_rem->ima) bgpic_rem->ima->id.us--;
2134                 MEM_freeN(bgpic_rem);
2135         }
2136
2137         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, vd);
2138
2139         return OPERATOR_FINISHED;
2140 }
2141
2142 void VIEW3D_OT_remove_background_image(wmOperatorType *ot)
2143 {
2144         /* identifiers */
2145         ot->name   = "Remove Background Image";
2146         ot->description= "Remove a background image from the 3D view";
2147         ot->idname = "VIEW3D_OT_remove_background_image";
2148
2149         /* api callbacks */
2150         ot->exec   = remove_background_image_exec;
2151         ot->poll   = ED_operator_view3d_active;
2152
2153         /* flags */
2154         ot->flag   = 0;
2155
2156         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove ", 0, INT_MAX);
2157 }
2158 /* ********************* set clipping operator ****************** */
2159
2160 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
2161 {
2162         int val;
2163
2164         for(val=0; val<4; val++) {
2165
2166                 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
2167
2168                 clip[val][3]=
2169                         - clip[val][0]*clipbb->vec[val][0]
2170                         - clip[val][1]*clipbb->vec[val][1]
2171                         - clip[val][2]*clipbb->vec[val][2];
2172         }
2173 }
2174
2175 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
2176 {
2177         BoundBox clipbb_local;
2178         float imat[4][4];
2179         int i;
2180
2181         invert_m4_m4(imat, mat);
2182
2183         for(i=0; i<8; i++) {
2184                 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
2185         }
2186
2187         calc_clipping_plane(clip_local, &clipbb_local);
2188 }
2189
2190 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
2191 {
2192         if(rv3d->rflag & RV3D_CLIPPING)
2193                 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
2194 }
2195
2196 static int view3d_clipping_exec(bContext *C, wmOperator *op)
2197 {
2198         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2199         ViewContext vc;
2200         bglMats mats;
2201         rcti rect;
2202
2203         rect.xmin= RNA_int_get(op->ptr, "xmin");
2204         rect.ymin= RNA_int_get(op->ptr, "ymin");
2205         rect.xmax= RNA_int_get(op->ptr, "xmax");
2206         rect.ymax= RNA_int_get(op->ptr, "ymax");
2207
2208         rv3d->rflag |= RV3D_CLIPPING;
2209         rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
2210
2211         /* note; otherwise opengl won't work */
2212         view3d_operator_needs_opengl(C);
2213
2214         view3d_set_viewcontext(C, &vc);
2215         view3d_get_transformation(vc.ar, vc.rv3d, NULL, &mats); /* NULL because we don't want it in object space */
2216         view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
2217
2218         return OPERATOR_FINISHED;
2219 }
2220
2221 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
2222 {
2223         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2224         ARegion *ar= CTX_wm_region(C);
2225
2226         if(rv3d->rflag & RV3D_CLIPPING) {
2227                 rv3d->rflag &= ~RV3D_CLIPPING;
2228                 ED_region_tag_redraw(ar);
2229                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
2230                 rv3d->clipbb= NULL;
2231                 return OPERATOR_FINISHED;
2232         }
2233         else {
2234                 return WM_border_select_invoke(C, op, event);
2235         }
2236 }
2237
2238 /* toggles */
2239 void VIEW3D_OT_clip_border(wmOperatorType *ot)
2240 {
2241
2242         /* identifiers */
2243         ot->name= "Clipping Border";
2244         ot->description = "Set the view clipping border";
2245         ot->idname= "VIEW3D_OT_clip_border";
2246
2247         /* api callbacks */
2248         ot->invoke= view3d_clipping_invoke;
2249         ot->exec= view3d_clipping_exec;
2250         ot->modal= WM_border_select_modal;
2251
2252         ot->poll= ED_operator_view3d_active;
2253
2254         /* flags */
2255         ot->flag= 0;
2256
2257         /* rna */
2258         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2259         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2260         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2261         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2262 }
2263
2264 /* ***************** 3d cursor cursor op ******************* */
2265
2266 /* mx my in region coords */
2267 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
2268 {
2269         Scene *scene= CTX_data_scene(C);
2270         ARegion *ar= CTX_wm_region(C);
2271         View3D *v3d = CTX_wm_view3d(C);
2272         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2273         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2274         short mx, my, mval[2];
2275 //      short ctrl= 0; // XXX
2276
2277         fp= give_cursor(scene, v3d);
2278
2279 //      if(obedit && ctrl) lr_click= 1;
2280         VECCOPY(oldcurs, fp);
2281
2282         mx= event->x - ar->winrct.xmin;
2283         my= event->y - ar->winrct.ymin;
2284         project_short_noclip(ar, fp, mval);
2285
2286         initgrabz(rv3d, fp[0], fp[1], fp[2]);
2287
2288         if(mval[0]!=IS_CLIPPED) {
2289                 short depth_used = 0;
2290
2291                 if (U.uiflag & USER_ORBIT_ZBUF) { /* maybe this should be accessed some other way */
2292                         short mval_depth[2] = {mx, my};
2293                         view3d_operator_needs_opengl(C);
2294                         if (view_autodist(scene, ar, v3d, mval_depth, fp))
2295                                 depth_used= 1;
2296                 }
2297
2298                 if(depth_used==0) {
2299                         window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2300                         sub_v3_v3v3(fp, fp, dvec);
2301                 }
2302         }
2303         else {
2304
2305                 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2306                 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2307
2308                 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2309                 fz= fz/rv3d->zfac;
2310
2311                 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2312                 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2313                 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2314         }
2315
2316         if(v3d && v3d->localvd)
2317                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2318         else
2319                 WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene);
2320
2321         return OPERATOR_FINISHED;
2322 }
2323
2324 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2325 {
2326
2327         /* identifiers */
2328         ot->name= "Set 3D Cursor";
2329         ot->description = "Set the location of the 3D cursor";
2330         ot->idname= "VIEW3D_OT_cursor3d";
2331
2332         /* api callbacks */
2333         ot->invoke= set_3dcursor_invoke;
2334
2335         ot->poll= ED_operator_view3d_active;
2336     
2337         /* flags */
2338 //      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2339     
2340         /* rna later */
2341
2342 }
2343
2344 /* ***************** manipulator op ******************* */
2345
2346
2347 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2348 {
2349         View3D *v3d = CTX_wm_view3d(C);
2350
2351         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2352         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2353
2354         /* only no modifier or shift */
2355         if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2356
2357         /* note; otherwise opengl won't work */
2358         view3d_operator_needs_opengl(C);
2359
2360         if(0==BIF_do_manipulator(C, event, op))
2361                 return OPERATOR_PASS_THROUGH;
2362
2363         return OPERATOR_FINISHED;
2364 }
2365
2366 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2367 {
2368
2369         /* identifiers */
2370         ot->name= "3D Manipulator";
2371         ot->description = "Manipulate selected item by axis";
2372         ot->idname= "VIEW3D_OT_manipulator";
2373
2374         /* api callbacks */
2375         ot->invoke= manipulator_invoke;
2376
2377         ot->poll= ED_operator_view3d_active;
2378
2379         /* rna later */
2380         RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
2381 }
2382
2383 static int enable_manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2384 {
2385         View3D *v3d = CTX_wm_view3d(C);
2386
2387         v3d->twtype=0;
2388         
2389         if (RNA_boolean_get(op->ptr, "translate"))
2390                 v3d->twtype |= V3D_MANIP_TRANSLATE;
2391         if (RNA_boolean_get(op->ptr, "rotate"))
2392                 v3d->twtype |= V3D_MANIP_ROTATE;
2393         if (RNA_boolean_get(op->ptr, "scale"))
2394                 v3d->twtype |= V3D_MANIP_SCALE;
2395                 
2396         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2397
2398         return OPERATOR_FINISHED;
2399 }
2400
2401 void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
2402 {
2403         /* identifiers */
2404         ot->name= "Enable 3D Manipulator";
2405         ot->description = "Enable the transform manipulator for use";
2406         ot->idname= "VIEW3D_OT_enable_manipulator";
2407         
2408         /* api callbacks */
2409         ot->invoke= enable_manipulator_invoke;
2410         ot->poll= ED_operator_view3d_active;
2411         
2412         /* rna later */
2413         RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator");
2414         RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator");
2415         RNA_def_boolean(ot->srna, "scale", 0, "Scale", "Enable the scale manipulator");
2416 }
2417
2418 /* ************************* below the line! *********************** */
2419
2420
2421 static float view_autodist_depth_margin(ARegion *ar, short *mval, int margin)
2422 {
2423         RegionView3D *rv3d= ar->regiondata;
2424         float depth= FLT_MAX;
2425
2426         if(margin==0) {
2427                 if (mval[0] < 0) return 0;
2428                 if (mval[1] < 0) return 0;
2429                 if (mval[0] >= rv3d->depths->w) return 0;
2430                 if (mval[1] >= rv3d->depths->h) return 0;
2431
2432                 /* Get Z Depths, needed for perspective, nice for ortho */
2433                 depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
2434                 if(depth >= rv3d->depths->depth_range[1] || depth <= rv3d->depths->depth_range[0]) {
2435                         depth= FLT_MAX;
2436                 }
2437         }
2438         else {
2439                 rcti rect;
2440                 float depth_close= FLT_MAX;
2441                 int xs, ys;
2442
2443                 rect.xmax = mval[0] + margin;
2444                 rect.ymax = mval[1] + margin;
2445
2446                 rect.xmin = mval[0] - margin;
2447                 rect.ymin = mval[1] - margin;
2448
2449                 /* Constrain rect to depth bounds */
2450                 if (rect.xmin < 0) rect.xmin = 0;
2451                 if (rect.ymin < 0) rect.ymin = 0;
2452                 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
2453                 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
2454
2455                 /* Find the closest Z pixel */
2456                 for (xs=rect.xmin; xs < rect.xmax; xs++) {
2457                         for (ys=rect.ymin; ys < rect.ymax; ys++) {
2458                                 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
2459                                 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
2460                                         if (depth_close > depth) {
2461                                                 depth_close = depth;
2462                                         }
2463                                 }
2464                         }
2465                 }
2466
2467                 depth= depth_close;
2468         }
2469
2470         return depth;
2471 }
2472
2473 /* XXX todo Zooms in on a border drawn by the user */
2474 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2475 {
2476         RegionView3D *rv3d= ar->regiondata;
2477         bglMats mats; /* ZBuffer depth vars */
2478         float depth_close= FLT_MAX;
2479         int had_depth = 0;
2480         double cent[2],  p[3];
2481
2482         /* Get Z Depths, needed for perspective, nice for ortho */
2483         bgl_get_mats(&mats);
2484         draw_depth(scene, ar, v3d, NULL);
2485
2486         /* force updating */
2487         if (rv3d->depths) {
2488                 had_depth = 1;
2489                 rv3d->depths->damaged = 1;
2490         }
2491
2492         view3d_update_depths(ar, v3d);
2493
2494         depth_close= view_autodist_depth_margin(ar, mval, 4);
2495
2496         if (depth_close==FLT_MAX)
2497                 return 0;
2498
2499         if (had_depth==0) {
2500                 MEM_freeN(rv3d->depths->depths);
2501                 rv3d->depths->depths = NULL;
2502         }
2503         rv3d->depths->damaged = 1;
2504
2505         cent[0] = (double)mval[0];
2506         cent[1] = (double)mval[1];
2507
2508         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2509                 return 0;
2510
2511         mouse_worldloc[0] = (float)p[0];
2512         mouse_worldloc[1] = (float)p[1];
2513         mouse_worldloc[2] = (float)p[2];
2514         return 1;
2515 }
2516
2517 int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode) //, float *autodist )
2518 {
2519         RegionView3D *rv3d= ar->regiondata;
2520
2521         /* Get Z Depths, needed for perspective, nice for ortho */
2522         switch(mode) {
2523         case 0:
2524                 draw_depth(scene, ar, v3d, NULL);
2525                 break;
2526         case 1:
2527                 draw_depth_gpencil(scene, ar, v3d);
2528                 break;
2529         }
2530
2531         /* force updating */
2532         if (rv3d->depths) {
2533                 rv3d->depths->damaged = 1;
2534         }
2535
2536         view3d_update_depths(ar, v3d);
2537         return 1;
2538 }
2539
2540 // no 4x4 sampling, run view_autodist_init first
2541 int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3], int margin, float *force_depth) //, float *autodist )
2542 {
2543         bglMats mats; /* ZBuffer depth vars, could cache? */
2544         float depth;
2545         double cent[2],  p[3];
2546
2547         /* Get Z Depths, needed for perspective, nice for ortho */
2548         if(force_depth)
2549                 depth= *force_depth;
2550         else
2551                 depth= view_autodist_depth_margin(ar, mval, margin);
2552
2553         if (depth==FLT_MAX)
2554                 return 0;
2555
2556         cent[0] = (double)mval[0];
2557         cent[1] = (double)mval[1];
2558
2559         bgl_get_mats(&mats);
2560         if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2561                 return 0;
2562
2563         mouse_worldloc[0] = (float)p[0];
2564         mouse_worldloc[1] = (float)p[1];
2565         mouse_worldloc[2] = (float)p[2];
2566         return 1;
2567 }
2568
2569 int view_autodist_depth(struct ARegion *ar, short *mval, int margin, float *depth)
2570 {
2571         *depth= view_autodist_depth_margin(ar, mval, margin);
2572
2573         return (*depth==FLT_MAX) ? 0:1;
2574                 return 0;
2575 }
2576
2577 /* ********************* NDOF ************************ */
2578 /* note: this code is confusing and unclear... (ton) */
2579 /* **************************************************** */
2580
2581 // ndof scaling will be moved to user setting.
2582 // In the mean time this is just a place holder.
2583
2584 // Note: scaling in the plugin and ghostwinlay.c
2585 // should be removed. With driver default setting,
2586 // each axis returns approx. +-200 max deflection.
2587
2588 // The values I selected are based on the older
2589 // polling i/f. With event i/f, the sensistivity
2590 // can be increased for improved response from
2591 // small deflections of the device input.
2592
2593
2594 // lukep notes : i disagree on the range.
2595 // the normal 3Dconnection driver give +/-400
2596 // on defaut range in other applications
2597 // and up to +/- 1000 if set to maximum
2598 // because i remove the scaling by delta,
2599 // which was a bad idea as it depend of the system
2600 // speed and os, i changed the scaling values, but
2601 // those are still not ok
2602
2603
2604 float ndof_axis_scale[6] = {
2605         +0.01,  // Tx
2606         +0.01,  // Tz
2607         +0.01,  // Ty
2608         +0.0015,        // Rx
2609         +0.0015,        // Rz
2610         +0.0015 // Ry
2611 };
2612
2613 void filterNDOFvalues(float *sbval)
2614 {
2615         int i=0;
2616         float max  = 0.0;
2617
2618         for (i =0; i<6;i++)
2619                 if (fabs(sbval[i]) > max)
2620                         max = fabs(sbval[i]);
2621         for (i =0; i<6;i++)
2622                 if (fabs(sbval[i]) != max )
2623                         sbval[i]=0.0;
2624 }
2625
2626 // statics for controlling rv3d->dist corrections.
2627 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2628 // viewmove restores based on dz_flag state.
2629
2630 int dz_flag = 0;
2631 float m_dist;
2632
2633 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2634 {
2635         RegionView3D *rv3d= ar->regiondata;
2636         int i;
2637         float phi;
2638         float dval[7];
2639         // static fval[6] for low pass filter; device input vector is dval[6]
2640         static float fval[6];
2641         float tvec[3],rvec[3];
2642         float q1[4];
2643         float mat[3][3];
2644         float upvec[3];
2645
2646
2647         /*----------------------------------------------------
2648          * sometimes this routine is called from headerbuttons
2649          * viewmove needs to refresh the screen
2650          */
2651 // XXX  areawinset(ar->win);
2652
2653
2654         // fetch the current state of the ndof device
2655 // XXX  getndof(dval);
2656
2657         if (v3d->ndoffilter)
2658                 filterNDOFvalues(fval);
2659
2660         // Scale input values
2661
2662 //      if(dval[6] == 0) return; // guard against divide by zero
2663
2664         for(i=0;i<6;i++) {
2665
2666                 // user scaling
2667                 dval[i] = dval[i] * ndof_axis_scale[i];
2668         }
2669
2670
2671         // low pass filter with zero crossing reset
2672
2673         for(i=0;i<6;i++) {
2674                 if((dval[i] * fval[i]) >= 0)
2675                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
2676                 else
2677                         fval[i] = 0;
2678         }
2679
2680
2681         // force perspective mode. This is a hack and is
2682         // incomplete. It doesn't actually effect the view
2683         // until the first draw and doesn't update the menu
2684         // to reflect persp mode.
2685
2686         rv3d->persp = RV3D_PERSP;
2687
2688
2689         // Correct the distance jump if rv3d->dist != 0
2690
2691         // This is due to a side effect of the original
2692         // mouse view rotation code. The rotation point is
2693         // set a distance in front of the viewport to
2694         // make rotating with the mouse look better.
2695         // The distance effect is written at a low level
2696         // in the view management instead of the mouse
2697         // view function. This means that all other view
2698         // movement devices must subtract this from their
2699         // view transformations.
2700
2701         if(rv3d->dist != 0.0) {
2702                 dz_flag = 1;
2703                 m_dist = rv3d->dist;
2704                 upvec[0] = upvec[1] = 0;
2705                 upvec[2] = rv3d->dist;
2706                 copy_m3_m4(mat, rv3d->viewinv);
2707                 mul_m3_v3(mat, upvec);
2708                 sub_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2709                 rv3d->dist = 0.0;
2710         }
2711
2712
2713         // Apply rotation
2714         // Rotations feel relatively faster than translations only in fly mode, so
2715         // we have no choice but to fix that here (not in the plugins)
2716         rvec[0] = -0.5 * dval[3];
2717         rvec[1] = -0.5 * dval[4];
2718         rvec[2] = -0.5 * dval[5];
2719
2720         // rotate device x and y by view z
2721
2722         copy_m3_m4(mat, rv3d->viewinv);
2723         mat[2][2] = 0.0f;
2724         mul_m3_v3(mat, rvec);
2725
2726         // rotate the view
2727
2728         phi = normalize_v3(rvec);
2729         if(phi != 0) {
2730                 axis_angle_to_quat(q1,rvec,phi);
2731                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2732         }
2733
2734
2735         // Apply translation
2736
2737         tvec[0] = dval[0];
2738         tvec[1] = dval[1];
2739         tvec[2] = -dval[2];
2740
2741         // the next three lines rotate the x and y translation coordinates
2742         // by the current z axis angle
2743
2744         copy_m3_m4(mat, rv3d->viewinv);
2745         mat[2][2] = 0.0f;
2746         mul_m3_v3(mat, tvec);
2747
2748         // translate the view
2749
2750         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, tvec);
2751
2752
2753         /*----------------------------------------------------
2754          * refresh the screen XXX
2755           */
2756
2757         // update render preview window
2758
2759 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2760 }
2761
2762 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2763 {
2764         RegionView3D *rv3d= ar->regiondata;
2765         float fval[7];
2766         float dvec[3];
2767         float sbadjust = 1.0f;
2768         float len;
2769         short use_sel = 0;
2770         Object *ob = OBACT;
2771         float m[3][3];
2772         float m_inv[3][3];
2773         float xvec[3] = {1,0,0};
2774         float yvec[3] = {0,-1,0};
2775         float zvec[3] = {0,0,1};
2776         float phi;
2777         float q1[4];
2778         float obofs[3];
2779         float reverse;
2780         //float diff[4];
2781         float d, curareaX, curareaY;
2782         float mat[3][3];
2783         float upvec[3];
2784
2785         /* Sensitivity will control how fast the view rotates.  The value was
2786          * obtained experimentally by tweaking until the author didn't get dizzy watching.
2787          * Perhaps this should be a configurable user parameter.
2788          */
2789         float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
2790         float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
2791         float zsens = 0.3f;   /* zoom sensitivity */
2792
2793         const float minZoom = -30.0f;
2794         const float maxZoom = 300.0f;
2795
2796         //reset view type
2797         rv3d->view = 0;
2798 //printf("passing here \n");
2799 //
2800         if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
2801                 use_sel = 1;
2802         }
2803
2804         if((dz_flag)||rv3d->dist==0) {
2805                 dz_flag = 0;
2806                 rv3d->dist = m_dist;
2807                 upvec[0] = upvec[1] = 0;
2808                 upvec[2] = rv3d->dist;
2809                 copy_m3_m4(mat, rv3d->viewinv);
2810                 mul_m3_v3(mat, upvec);
2811                 add_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2812         }
2813
2814         /*----------------------------------------------------
2815          * sometimes this routine is called from headerbuttons
2816          * viewmove needs to refresh the screen
2817          */
2818 // XXX  areawinset(curarea->win);
2819
2820         /*----------------------------------------------------
2821          * record how much time has passed. clamp at 10 Hz
2822          * pretend the previous frame occured at the clamped time
2823          */
2824 //    now = PIL_check_seconds_timer();
2825  //   frametime = (now - prevTime);
2826  //   if (frametime > 0.1f){        /* if more than 1/10s */
2827  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
2828 //    }
2829 //    prevTime = now;
2830  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
2831
2832         /* fetch the current state of the ndof device & enforce dominant mode if selected */
2833 // XXX    getndof(fval);
2834         if (v3d->ndoffilter)
2835                 filterNDOFvalues(fval);
2836
2837
2838         // put scaling back here, was previously in ghostwinlay
2839         fval[0] = fval[0] * (1.0f/600.0f);
2840         fval[1] = fval[1] * (1.0f/600.0f);
2841         fval[2] = fval[2] * (1.0f/1100.0f);
2842         fval[3] = fval[3] * 0.00005f;
2843         fval[4] =-fval[4] * 0.00005f;
2844         fval[5] = fval[5] * 0.00005f;
2845         fval[6] = fval[6] / 1000000.0f;
2846
2847         // scale more if not in perspective mode
2848         if (rv3d->persp == RV3D_ORTHO) {
2849                 fval[0] = fval[0] * 0.05f;
2850                 fval[1] = fval[1] * 0.05f;
2851                 fval[2] = fval[2] * 0.05f;
2852                 fval[3] = fval[3] * 0.9f;
2853                 fval[4] = fval[4] * 0.9f;
2854                 fval[5] = fval[5] * 0.9f;
2855                 zsens *= 8;
2856         }
2857
2858         /* set object offset */
2859         if (ob) {
2860                 obofs[0] = -ob->obmat[3][0];
2861                 obofs[1] = -ob->obmat[3][1];
2862                 obofs[2] = -ob->obmat[3][2];
2863         }
2864         else {
2865                 VECCOPY(obofs, rv3d->ofs);
2866         }
2867
2868         /* calc an adjustment based on distance from camera
2869            disabled per patch 14402 */
2870          d = 1.0f;
2871
2872 /*    if (ob) {
2873                 sub_v3_v3v3(diff, obofs, rv3d->ofs);
2874                 d = len_v3(diff);
2875         }
2876 */
2877
2878         reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
2879
2880         /*----------------------------------------------------
2881          * ndof device pan
2882          */
2883         psens *= 1.0f + d;
2884         curareaX = sbadjust * psens * fval[0];
2885         curareaY = sbadjust * psens * fval[1];
2886         dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
2887         dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
2888         dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
2889         add_v3_v3v3(rv3d->ofs, rv3d->ofs, dvec);
2890
2891         /*----------------------------------------------------
2892          * ndof device dolly
2893          */
2894         len = zsens * sbadjust * fval[2];
2895
2896         if (rv3d->persp==RV3D_CAMOB) {
2897                 if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
2898                         rv3d->camzoom+= 10.0f * -len;
2899                 }
2900                 if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
2901                 else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
2902         }
2903         else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
2904                 rv3d->dist*=(1.0 + len);
2905         }
2906
2907
2908         /*----------------------------------------------------
2909          * ndof device turntable
2910          * derived from the turntable code in viewmove
2911          */
2912
2913         /* Get the 3x3 matrix and its inverse from the quaternion */
2914         quat_to_mat3( m,rv3d->viewquat);
2915         invert_m3_m3(m_inv,m);
2916
2917         /* Determine the direction of the x vector (for rotating up and down) */
2918         /* This can likely be compuated directly from the quaternion. */
2919         mul_m3_v3(m_inv,xvec);
2920         mul_m3_v3(m_inv,yvec);
2921         mul_m3_v3(m_inv,zvec);
2922
2923         /* Perform the up/down rotation */
2924         phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
2925         q1[0] = cos(phi);
2926         mul_v3_v3fl(q1+1, xvec, sin(phi));
2927         mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2928
2929         if (use_sel) {
2930                 conjugate_qt(q1); /* conj == inv for unit quat */
2931                 sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2932                 mul_qt_v3(q1, rv3d->ofs);
2933                 add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2934         }
2935
2936         /* Perform the orbital rotation */
2937         /* Perform the orbital rotation
2938            If the seen Up axis is parallel to the zoom axis, rotation should be
2939            achieved with a pure Roll motion (no Spin) on the device. When you start
2940            to tilt, moving from Top to Side view, Spinning will increasingly become
2941            more relevant while the Roll component will decrease. When a full
2942            Side view is reached, rotations around the world's Up axis are achieved
2943            with a pure Spin-only motion.  In other words the control of the spinning
2944            around the world's Up axis should move from the device's Spin axis to the
2945            device's Roll axis depending on the orientation of the world's Up axis
2946            relative to the screen. */
2947         //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
2948         phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
2949         q1[0] = cos(phi);
2950         q1[1] = q1[2] = 0.0;
2951         q1[3] = sin(phi);
2952         mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2953
2954         if (use_sel) {
2955                 conjugate_qt(q1);
2956                 sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2957                 mul_qt_v3(q1, rv3d->ofs);
2958                 add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2959         }
2960
2961         /*----------------------------------------------------
2962          * refresh the screen
2963          */
2964 // XXX    scrarea_do_windraw(curarea);
2965 }
2966
2967
2968
2969