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