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