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