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