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