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