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