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