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