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