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