Sculpt:
[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 = (vod->ar->winrct.ymax - y) + 5;
867                 float len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
868                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->rv3d->dist;
869         }
870
871         if(zfac != 1.0 && zfac*vod->rv3d->dist > 0.001*vod->grid &&
872                                 zfac*vod->rv3d->dist < 10.0*vod->far)
873                 view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
874
875
876         if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
877                 float upvec[3], mat[3][3];
878
879                 /* Secret apricot feature, translate the view when in continues mode */
880                 upvec[0] = upvec[1] = 0.0f;
881                 upvec[2] = (vod->dist0 - vod->rv3d->dist) * vod->grid;
882                 vod->rv3d->dist = vod->dist0;
883                 copy_m3_m4(mat, vod->rv3d->viewinv);
884                 mul_m3_v3(mat, upvec);
885                 add_v3_v3v3(vod->rv3d->ofs, vod->rv3d->ofs, upvec);
886         } else {
887                 /* these limits were in old code too */
888                 if(vod->rv3d->dist<0.001*vod->grid) vod->rv3d->dist= 0.001*vod->grid;
889                 if(vod->rv3d->dist>10.0*vod->far) vod->rv3d->dist=10.0*vod->far;
890         }
891
892 // XXX  if(vod->rv3d->persp==RV3D_ORTHO || vod->rv3d->persp==RV3D_CAMOB) preview3d_event= 0;
893
894         if(vod->rv3d->viewlock & RV3D_BOXVIEW)
895                 view3d_boxview_sync(vod->sa, vod->ar);
896
897         ED_region_tag_redraw(vod->ar);
898 }
899
900
901 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
902 {
903         ViewOpsData *vod= op->customdata;
904         short event_code= VIEW_PASS;
905
906         /* execute the events */
907         if(event->type==MOUSEMOVE) {
908                 event_code= VIEW_APPLY;
909         }
910         else if(event->type==EVT_MODAL_MAP) {
911                 switch (event->val) {
912                         case VIEW_MODAL_CONFIRM:
913                                 event_code= VIEW_CONFIRM;
914                                 break;
915                 }
916         }
917         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
918                 event_code= VIEW_CONFIRM;
919         }
920
921         if(event_code==VIEW_APPLY) {
922                 viewzoom_apply(vod, event->x, event->y);
923         }
924         else if (event_code==VIEW_CONFIRM) {
925                 request_depth_update(CTX_wm_region_view3d(C));
926                 viewops_data_free(C, op);
927
928                 return OPERATOR_FINISHED;
929         }
930
931         return OPERATOR_RUNNING_MODAL;
932 }
933
934 static int viewzoom_exec(bContext *C, wmOperator *op)
935 {
936         View3D *v3d = CTX_wm_view3d(C);
937         RegionView3D *rv3d= CTX_wm_region_view3d(C);
938         int delta= RNA_int_get(op->ptr, "delta");
939         int mx = RNA_int_get(op->ptr, "mx");
940         int my = RNA_int_get(op->ptr, "my");
941
942         if(delta < 0) {
943                 /* this min and max is also in viewmove() */
944                 if(rv3d->persp==RV3D_CAMOB) {
945                         rv3d->camzoom-= 10;
946                         if(rv3d->camzoom<-30) rv3d->camzoom= -30;
947                 }
948                 else if(rv3d->dist<10.0*v3d->far) {
949                         view_zoom_mouseloc(CTX_wm_region(C), 1.2f, mx, my);
950                 }
951         }
952         else {
953                 if(rv3d->persp==RV3D_CAMOB) {
954                         rv3d->camzoom+= 10;
955                         if(rv3d->camzoom>300) rv3d->camzoom= 300;
956                 }
957                 else if(rv3d->dist> 0.001*v3d->grid) {
958                         view_zoom_mouseloc(CTX_wm_region(C), .83333f, mx, my);
959                 }
960         }
961
962         if(rv3d->viewlock & RV3D_BOXVIEW)
963                 view3d_boxview_sync(CTX_wm_area(C), CTX_wm_region(C));
964
965         request_depth_update(CTX_wm_region_view3d(C));
966         ED_region_tag_redraw(CTX_wm_region(C));
967
968         return OPERATOR_FINISHED;
969 }
970
971 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
972 {
973         int delta= RNA_int_get(op->ptr, "delta");
974         
975         /* if one or the other zoom position aren't set, set from event */
976         if (!RNA_property_is_set(op->ptr, "mx") || !RNA_property_is_set(op->ptr, "my"))
977         {
978                 RNA_int_set(op->ptr, "mx", event->x);
979                 RNA_int_set(op->ptr, "my", event->y);
980         }
981
982         if(delta) {
983                 viewzoom_exec(C, op);
984         }
985         else {
986                 /* makes op->customdata */
987                 viewops_data_create(C, op, event);
988
989                 /* add temp handler */
990                 WM_event_add_modal_handler(C, op);
991
992                 return OPERATOR_RUNNING_MODAL;
993         }
994         return OPERATOR_FINISHED;
995 }
996
997
998 void VIEW3D_OT_zoom(wmOperatorType *ot)
999 {
1000         /* identifiers */
1001         ot->name= "Zoom view";
1002         ot->description = "Zoom in/out in the view.";
1003         ot->idname= "VIEW3D_OT_zoom";
1004
1005         /* api callbacks */
1006         ot->invoke= viewzoom_invoke;
1007         ot->exec= viewzoom_exec;
1008         ot->modal= viewzoom_modal;
1009         ot->poll= ED_operator_view3d_active;
1010
1011         /* flags */
1012         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1013
1014         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1015         RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
1016         RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
1017 }
1018
1019 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1020 {
1021         ARegion *ar= CTX_wm_region(C);
1022         View3D *v3d = CTX_wm_view3d(C);
1023         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1024         Scene *scene= CTX_data_scene(C);
1025         Base *base;
1026         float *curs;
1027
1028         int center= RNA_boolean_get(op->ptr, "center");
1029
1030         float size, min[3], max[3], afm[3];
1031         int ok= 1, onedone=0;
1032
1033         if(center) {
1034                 min[0]= min[1]= min[2]= 0.0f;
1035                 max[0]= max[1]= max[2]= 0.0f;
1036
1037                 /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
1038                 curs= give_cursor(scene, v3d);
1039                 curs[0]= curs[1]= curs[2]= 0.0;
1040         }
1041         else {
1042                 INIT_MINMAX(min, max);
1043         }
1044
1045         for(base= scene->base.first; base; base= base->next) {
1046                 if(base->lay & v3d->lay) {
1047                         onedone= 1;
1048                         minmax_object(base->object, min, max);
1049                 }
1050         }
1051         if(!onedone) return OPERATOR_FINISHED; /* TODO - should this be cancel? */
1052
1053         afm[0]= (max[0]-min[0]);
1054         afm[1]= (max[1]-min[1]);
1055         afm[2]= (max[2]-min[2]);
1056         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
1057         if(size==0.0) ok= 0;
1058
1059         if(ok) {
1060                 float new_dist;
1061                 float new_ofs[3];
1062
1063                 new_dist = size;
1064                 new_ofs[0]= -(min[0]+max[0])/2.0f;
1065                 new_ofs[1]= -(min[1]+max[1])/2.0f;
1066                 new_ofs[2]= -(min[2]+max[2])/2.0f;
1067
1068                 // correction for window aspect ratio
1069                 if(ar->winy>2 && ar->winx>2) {
1070                         size= (float)ar->winx/(float)ar->winy;
1071                         if(size<1.0) size= 1.0f/size;
1072                         new_dist*= size;
1073                 }
1074
1075                 if (rv3d->persp==RV3D_CAMOB) {
1076                         rv3d->persp= RV3D_PERSP;
1077                         smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL);
1078                 }
1079         else {
1080             smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1081         }
1082         }
1083 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1084
1085         if(rv3d->viewlock & RV3D_BOXVIEW)
1086                 view3d_boxview_copy(CTX_wm_area(C), ar);
1087
1088         return OPERATOR_FINISHED;
1089 }
1090
1091 void VIEW3D_OT_view_all(wmOperatorType *ot)
1092 {
1093         /* identifiers */
1094         ot->name= "View All";
1095         ot->description = "View all objects in scene.";
1096         ot->idname= "VIEW3D_OT_view_all";
1097
1098         /* api callbacks */
1099         ot->exec= viewhome_exec;
1100         ot->poll= ED_operator_view3d_active;
1101
1102         /* flags */
1103         ot->flag= 0;
1104
1105         RNA_def_boolean(ot->srna, "center", 0, "Center", "");
1106 }
1107
1108 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
1109 {
1110         ARegion *ar= CTX_wm_region(C);
1111         View3D *v3d = CTX_wm_view3d(C);
1112         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1113         Scene *scene= CTX_data_scene(C);
1114         Object *ob= OBACT;
1115         Object *obedit= CTX_data_edit_object(C);
1116         float size, min[3], max[3], afm[3];
1117         int ok=0;
1118
1119         /* SMOOTHVIEW */
1120         float new_ofs[3];
1121         float new_dist;
1122
1123         INIT_MINMAX(min, max);
1124
1125         if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
1126                 /* hardcoded exception, we look for the one selected armature */
1127                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1128                 Base *base;
1129                 for(base=scene->base.first; base; base= base->next) {
1130                         if(TESTBASELIB(v3d, base)) {
1131                                 if(base->object->type==OB_ARMATURE)
1132                                         if(base->object->mode & OB_MODE_POSE)
1133                                                 break;
1134                         }
1135                 }
1136                 if(base)
1137                         ob= base->object;
1138         }
1139
1140
1141         if(obedit) {
1142                 ok = minmax_verts(obedit, min, max);    /* only selected */
1143         }
1144         else if(ob && (ob->mode & OB_MODE_POSE)) {
1145                 if(ob->pose) {
1146                         bArmature *arm= ob->data;
1147                         bPoseChannel *pchan;
1148                         float vec[3];
1149
1150                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1151                                 if(pchan->bone->flag & BONE_SELECTED) {
1152                                         if(pchan->bone->layer & arm->layer) {
1153                                                 ok= 1;
1154                                                 VECCOPY(vec, pchan->pose_head);
1155                                                 mul_m4_v3(ob->obmat, vec);
1156                                                 DO_MINMAX(vec, min, max);
1157                                                 VECCOPY(vec, pchan->pose_tail);
1158                                                 mul_m4_v3(ob->obmat, vec);
1159                                                 DO_MINMAX(vec, min, max);
1160                                         }
1161                                 }
1162                         }
1163                 }
1164         }
1165         else if (paint_facesel_test(ob)) {
1166 // XXX          ok= minmax_tface(min, max);
1167         }
1168         else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1169                 ok= PE_minmax(scene, min, max);
1170         }
1171         else {
1172                 Base *base= FIRSTBASE;
1173                 while(base) {
1174                         if(TESTBASE(v3d, base))  {
1175                                 minmax_object(base->object, min, max);
1176                                 /* account for duplis */
1177                                 minmax_object_duplis(scene, base->object, min, max);
1178
1179                                 ok= 1;
1180                         }
1181                         base= base->next;
1182                 }
1183         }
1184
1185         if(ok==0) return OPERATOR_FINISHED;
1186
1187         afm[0]= (max[0]-min[0]);
1188         afm[1]= (max[1]-min[1]);
1189         afm[2]= (max[2]-min[2]);
1190         size= MAX3(afm[0], afm[1], afm[2]);
1191         /* perspective should be a bit farther away to look nice */
1192         if(rv3d->persp==RV3D_ORTHO)
1193                 size*= 0.7;
1194
1195         if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
1196
1197         new_ofs[0]= -(min[0]+max[0])/2.0f;
1198         new_ofs[1]= -(min[1]+max[1])/2.0f;
1199         new_ofs[2]= -(min[2]+max[2])/2.0f;
1200
1201         new_dist = size;
1202
1203         /* correction for window aspect ratio */
1204         if(ar->winy>2 && ar->winx>2) {
1205                 size= (float)ar->winx/(float)ar->winy;
1206                 if(size<1.0f) size= 1.0f/size;
1207                 new_dist*= size;
1208         }
1209
1210         v3d->cursor[0]= -new_ofs[0];
1211         v3d->cursor[1]= -new_ofs[1];
1212         v3d->cursor[2]= -new_ofs[2];
1213
1214         if (rv3d->persp==RV3D_CAMOB) {
1215                 rv3d->persp= RV3D_PERSP;
1216                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1217         }
1218         else {
1219                 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1220         }
1221
1222 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1223         if(rv3d->viewlock & RV3D_BOXVIEW)
1224                 view3d_boxview_copy(CTX_wm_area(C), ar);
1225
1226         return OPERATOR_FINISHED;
1227 }
1228
1229 void VIEW3D_OT_view_center(wmOperatorType *ot)
1230 {
1231
1232         /* identifiers */
1233         ot->name= "View Selected";
1234         ot->description = "Move the view to the selection center.";
1235         ot->idname= "VIEW3D_OT_view_center";
1236
1237         /* api callbacks */
1238         ot->exec= viewcenter_exec;
1239         ot->poll= ED_operator_view3d_active;
1240
1241         /* flags */
1242         ot->flag= 0;
1243 }
1244
1245 static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
1246 {
1247         View3D *v3d = CTX_wm_view3d(C);
1248         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1249         Scene *scene= CTX_data_scene(C);
1250         
1251         if (rv3d) {
1252                 if (rv3d->persp==RV3D_CAMOB) {
1253                         /* center the camera offset */
1254                         rv3d->camdx= rv3d->camdy= 0.0;
1255                 }
1256                 else {
1257                         /* non camera center */
1258                         float *curs= give_cursor(scene, v3d);
1259                         float new_ofs[3];
1260                         
1261                         new_ofs[0]= -curs[0];
1262                         new_ofs[1]= -curs[1];
1263                         new_ofs[2]= -curs[2];
1264                         
1265                         smooth_view(C, NULL, NULL, new_ofs, NULL, NULL, NULL);
1266                 }
1267                 
1268                 if (rv3d->viewlock & RV3D_BOXVIEW)
1269                         view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
1270         }
1271         
1272         return OPERATOR_FINISHED;
1273 }
1274
1275 void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
1276 {
1277         /* identifiers */
1278         ot->name= "Center View to Cursor";
1279         ot->description= "Centers the view so that the cursor is in the middle of the view.";
1280         ot->idname= "VIEW3D_OT_view_center_cursor";
1281         
1282         /* api callbacks */
1283         ot->exec= viewcenter_cursor_exec;
1284         ot->poll= ED_operator_view3d_active;
1285         
1286         /* flags */
1287         ot->flag= 0;
1288 }
1289
1290 /* ********************* Set render border operator ****************** */
1291
1292 static int render_border_exec(bContext *C, wmOperator *op)
1293 {
1294         View3D *v3d = CTX_wm_view3d(C);
1295         ARegion *ar= CTX_wm_region(C);
1296         Scene *scene= CTX_data_scene(C);
1297
1298         rcti rect;
1299         rctf vb;
1300
1301         /* get border select values using rna */
1302         rect.xmin= RNA_int_get(op->ptr, "xmin");
1303         rect.ymin= RNA_int_get(op->ptr, "ymin");
1304         rect.xmax= RNA_int_get(op->ptr, "xmax");
1305         rect.ymax= RNA_int_get(op->ptr, "ymax");
1306
1307         /* calculate range */
1308         calc_viewborder(scene, ar, v3d, &vb);
1309
1310         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1311         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1312         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1313         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1314
1315         /* actually set border */
1316         CLAMP(scene->r.border.xmin, 0.0, 1.0);
1317         CLAMP(scene->r.border.ymin, 0.0, 1.0);
1318         CLAMP(scene->r.border.xmax, 0.0, 1.0);
1319         CLAMP(scene->r.border.ymax, 0.0, 1.0);
1320
1321         /* drawing a border surrounding the entire camera view switches off border rendering
1322          * or the border covers no pixels */
1323         if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1324                 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1325            (scene->r.border.xmin == scene->r.border.xmax ||
1326                 scene->r.border.ymin == scene->r.border.ymax ))
1327         {
1328                 scene->r.mode &= ~R_BORDER;
1329         } else {
1330                 scene->r.mode |= R_BORDER;
1331         }
1332
1333         return OPERATOR_FINISHED;
1334
1335 }
1336
1337 static int view3d_render_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1338 {
1339         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1340
1341         /* if not in camera view do not exec the operator*/
1342         if (rv3d->persp == RV3D_CAMOB) return WM_border_select_invoke(C, op, event);
1343         else return OPERATOR_PASS_THROUGH;
1344 }
1345
1346 void VIEW3D_OT_render_border(wmOperatorType *ot)
1347 {
1348         /* identifiers */
1349         ot->name= "Set Render Border";
1350         ot->description = "Set the boundries of the border render and enables border render .";
1351         ot->idname= "VIEW3D_OT_render_border";
1352
1353         /* api callbacks */
1354         ot->invoke= view3d_render_border_invoke;
1355         ot->exec= render_border_exec;
1356         ot->modal= WM_border_select_modal;
1357
1358         ot->poll= ED_operator_view3d_active;
1359
1360         /* flags */
1361         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1362
1363         /* rna */
1364         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1365         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1366         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1367         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1368
1369 }
1370 /* ********************* Border Zoom operator ****************** */
1371
1372 static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
1373 {
1374         ARegion *ar= CTX_wm_region(C);
1375         View3D *v3d = CTX_wm_view3d(C);
1376         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1377         Scene *scene= CTX_data_scene(C);
1378
1379         /* Zooms in on a border drawn by the user */
1380         rcti rect;
1381         float dvec[3], vb[2], xscale, yscale, scale;
1382
1383         /* SMOOTHVIEW */
1384         float new_dist;
1385         float new_ofs[3];
1386
1387         /* ZBuffer depth vars */
1388         bglMats mats;
1389         float depth, depth_close= MAXFLOAT;
1390         int had_depth = 0;
1391         double cent[2],  p[3];
1392         int xs, ys;
1393
1394         /* note; otherwise opengl won't work */
1395         view3d_operator_needs_opengl(C);
1396
1397         /* get border select values using rna */
1398         rect.xmin= RNA_int_get(op->ptr, "xmin");
1399         rect.ymin= RNA_int_get(op->ptr, "ymin");
1400         rect.xmax= RNA_int_get(op->ptr, "xmax");
1401         rect.ymax= RNA_int_get(op->ptr, "ymax");
1402
1403         /* Get Z Depths, needed for perspective, nice for ortho */
1404         bgl_get_mats(&mats);
1405         draw_depth(scene, ar, v3d, NULL);
1406
1407         /* force updating */
1408         if (rv3d->depths) {
1409                 had_depth = 1;
1410                 rv3d->depths->damaged = 1;
1411         }
1412
1413         view3d_update_depths(ar, v3d);
1414
1415         /* Constrain rect to depth bounds */
1416         if (rect.xmin < 0) rect.xmin = 0;
1417         if (rect.ymin < 0) rect.ymin = 0;
1418         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1419         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1420
1421         /* Find the closest Z pixel */
1422         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1423                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1424                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1425                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1426                                 if (depth_close > depth) {
1427                                         depth_close = depth;
1428                                 }
1429                         }
1430                 }
1431         }
1432
1433         if (had_depth==0) {
1434                 MEM_freeN(rv3d->depths->depths);
1435                 rv3d->depths->depths = NULL;
1436         }
1437         rv3d->depths->damaged = 1;
1438
1439         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1440         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1441
1442         if (rv3d->persp==RV3D_PERSP) {
1443                 double p_corner[3];
1444
1445                 /* no depths to use, we cant do anything! */
1446                 if (depth_close==MAXFLOAT){
1447                         BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1448                         return OPERATOR_CANCELLED;
1449                 }
1450                 /* convert border to 3d coordinates */
1451                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1452                         (       !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])))
1453                         return OPERATOR_CANCELLED;
1454
1455                 dvec[0] = p[0]-p_corner[0];
1456                 dvec[1] = p[1]-p_corner[1];
1457                 dvec[2] = p[2]-p_corner[2];
1458
1459                 new_dist = len_v3(dvec);
1460                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1461
1462                 new_ofs[0] = -p[0];
1463                 new_ofs[1] = -p[1];
1464                 new_ofs[2] = -p[2];
1465
1466         } else { /* othographic */
1467                 /* find the current window width and height */
1468                 vb[0] = ar->winx;
1469                 vb[1] = ar->winy;
1470
1471                 new_dist = rv3d->dist;
1472
1473                 /* convert the drawn rectangle into 3d space */
1474                 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1475                         new_ofs[0] = -p[0];
1476                         new_ofs[1] = -p[1];
1477                         new_ofs[2] = -p[2];
1478                 } else {
1479                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1480                         new_ofs[0] = rv3d->ofs[0];
1481                         new_ofs[1] = rv3d->ofs[1];
1482                         new_ofs[2] = rv3d->ofs[2];
1483
1484                         initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1485
1486                         window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1487                         /* center the view to the center of the rectangle */
1488                         sub_v3_v3v3(new_ofs, new_ofs, dvec);
1489                 }
1490
1491                 /* work out the ratios, so that everything selected fits when we zoom */
1492                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1493                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1494                 scale = (xscale >= yscale)?xscale:yscale;
1495
1496                 /* zoom in as required, or as far as we can go */
1497                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1498         }
1499
1500         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1501
1502         if(rv3d->viewlock & RV3D_BOXVIEW)
1503                 view3d_boxview_sync(CTX_wm_area(C), ar);
1504
1505         return OPERATOR_FINISHED;
1506 }
1507
1508 static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1509 {
1510         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1511
1512         /* if in camera view do not exec the operator so we do not conflict with set render border*/
1513         if (rv3d->persp != RV3D_CAMOB)
1514                 return WM_border_select_invoke(C, op, event);
1515         else
1516                 return OPERATOR_PASS_THROUGH;
1517 }
1518
1519 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1520 {
1521
1522         /* identifiers */
1523         ot->name= "Border Zoom";
1524         ot->description = "Zoom in the view to the nearest object contained in the border.";
1525         ot->idname= "VIEW3D_OT_zoom_border";
1526
1527         /* api callbacks */
1528         ot->invoke= view3d_zoom_border_invoke;
1529         ot->exec= view3d_zoom_border_exec;
1530         ot->modal= WM_border_select_modal;
1531
1532         ot->poll= ED_operator_view3d_active;
1533
1534         /* flags */
1535         ot->flag= 0;
1536
1537         /* rna */
1538         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1539         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1540         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1541         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1542
1543 }
1544 /* ********************* Changing view operator ****************** */
1545
1546 static EnumPropertyItem prop_view_items[] = {
1547         {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1548         {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1549         {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1550         {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1551         {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1552         {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1553         {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1554         {0, NULL, 0, NULL, NULL}};
1555
1556
1557 /* would like to make this a generic function - outside of transform */
1558
1559 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo, int align_active)
1560 {
1561         View3D *v3d = CTX_wm_view3d(C);
1562         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1563         float new_quat[4];
1564
1565         new_quat[0]= q1; new_quat[1]= q2;
1566         new_quat[2]= q3; new_quat[3]= q4;
1567
1568         if(align_active) {
1569                 /* align to active object */
1570                 Object *obact= CTX_data_active_object(C);
1571                 if (obact==NULL) {
1572                         /* no active object, ignore this option */
1573                         align_active= FALSE;
1574                 }
1575                 else {
1576                         float obact_quat[4];
1577                         float twmat[3][3];
1578
1579                         /* same as transform manipulator when normal is set */
1580                         ED_getTransformOrientationMatrix(C, twmat, TRUE);
1581
1582                         mat3_to_quat( obact_quat,twmat);
1583                         invert_qt(obact_quat);
1584                         mul_qt_qtqt(new_quat, new_quat, obact_quat);
1585
1586                         rv3d->view= view= 0;
1587                 }
1588         }
1589
1590         if(align_active==FALSE) {
1591                 /* normal operation */
1592                 if(rv3d->viewlock) {
1593                         /* only pass on if */
1594                         if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
1595                         else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
1596                         else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
1597                         else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
1598                         else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
1599                         else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
1600                         else return;
1601                 }
1602
1603                 rv3d->view= view;
1604         }
1605
1606         if(rv3d->viewlock) {
1607                 ED_region_tag_redraw(CTX_wm_region(C));
1608                 return;
1609         }
1610
1611         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1612
1613                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1614                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1615
1616                 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1617         }
1618         else {
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, NULL, NULL, NULL, new_quat, NULL, NULL);
1624         }
1625
1626 }
1627
1628 static int viewnumpad_exec(bContext *C, wmOperator *op)
1629 {
1630         View3D *v3d = CTX_wm_view3d(C);
1631         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1632         Scene *scene= CTX_data_scene(C);
1633         static int perspo=RV3D_PERSP;
1634         int viewnum, align_active;
1635
1636         viewnum = RNA_enum_get(op->ptr, "type");
1637         align_active = RNA_boolean_get(op->ptr, "align_active");
1638
1639         /* Use this to test if we started out with a camera */
1640
1641         switch (viewnum) {
1642                 case RV3D_VIEW_BOTTOM :
1643                         axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, perspo, align_active);
1644                         break;
1645
1646                 case RV3D_VIEW_BACK:
1647                         axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, perspo, align_active);
1648                         break;
1649
1650                 case RV3D_VIEW_LEFT:
1651                         axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, perspo, align_active);
1652                         break;
1653
1654                 case RV3D_VIEW_TOP:
1655                         axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, perspo, align_active);
1656                         break;
1657
1658                 case RV3D_VIEW_FRONT:
1659                         axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, perspo, align_active);
1660                         break;
1661
1662                 case RV3D_VIEW_RIGHT:
1663                         axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, perspo, align_active);
1664                         break;
1665
1666                 case RV3D_VIEW_CAMERA:
1667                         if(rv3d->viewlock==0) {
1668                                 /* lastview -  */
1669
1670                                 if(rv3d->persp != RV3D_CAMOB) {
1671                                         /* store settings of current view before allowing overwriting with camera view */
1672                                         QUATCOPY(rv3d->lviewquat, rv3d->viewquat);
1673                                         rv3d->lview= rv3d->view;
1674                                         rv3d->lpersp= rv3d->persp;
1675
1676         #if 0
1677                                         if(G.qual==LR_ALTKEY) {
1678                                                 if(oldcamera && is_an_active_object(oldcamera)) {
1679                                                         v3d->camera= oldcamera;
1680                                                 }
1681                                                 handle_view3d_lock();
1682                                         }
1683         #endif
1684
1685                                         if(BASACT) {
1686                                                 /* check both G.vd as G.scene cameras */
1687                                                 if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1688                                                         v3d->camera= OBACT;
1689                                                         /*handle_view3d_lock();*/
1690                                                 }
1691                                         }
1692
1693                                         if(v3d->camera==NULL) {
1694                                                 v3d->camera= scene_find_camera(scene);
1695                                                 /*handle_view3d_lock();*/
1696                                         }
1697                                         rv3d->persp= RV3D_CAMOB;
1698                                         smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
1699
1700                                 }
1701                                 else{
1702                                         /* return to settings of last view */
1703                                         /* does smooth_view too */
1704                                         axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
1705                                 }
1706                         }
1707                         break;
1708
1709                 default :
1710                         break;
1711         }
1712
1713         if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
1714
1715         return OPERATOR_FINISHED;
1716 }
1717 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1718 {
1719         /* identifiers */
1720         ot->name= "View numpad";
1721         ot->description = "Set the view.";
1722         ot->idname= "VIEW3D_OT_viewnumpad";
1723
1724         /* api callbacks */
1725         ot->exec= viewnumpad_exec;
1726         ot->poll= ED_operator_view3d_active;
1727
1728         /* flags */
1729         ot->flag= 0;
1730
1731         RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
1732         RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
1733 }
1734
1735 static EnumPropertyItem prop_view_orbit_items[] = {
1736         {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
1737         {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
1738         {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
1739         {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
1740         {0, NULL, 0, NULL, NULL}};
1741
1742 static int vieworbit_exec(bContext *C, wmOperator *op)
1743 {
1744         ARegion *ar= CTX_wm_region(C);
1745         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1746         float phi, si, q1[4];
1747         int orbitdir;
1748
1749         orbitdir = RNA_enum_get(op->ptr, "type");
1750
1751         if(rv3d->viewlock==0) {
1752
1753                 if(rv3d->persp != RV3D_CAMOB) {
1754                         if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
1755                                 /* z-axis */
1756                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1757                                 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
1758                                 si= (float)sin(phi);
1759                                 q1[0]= (float)cos(phi);
1760                                 q1[1]= q1[2]= 0.0;
1761                                 q1[3]= si;
1762                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
1763                                 rv3d->view= 0;
1764                         }
1765                         if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
1766                                 /* horizontal axis */
1767                                 VECCOPY(q1+1, rv3d->viewinv[0]);
1768
1769                                 normalize_v3(q1+1);
1770                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1771                                 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
1772                                 si= (float)sin(phi);
1773                                 q1[0]= (float)cos(phi);
1774                                 q1[1]*= si;
1775                                 q1[2]*= si;
1776                                 q1[3]*= si;
1777                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
1778                                 rv3d->view= 0;
1779                         }
1780                         ED_region_tag_redraw(ar);
1781                 }
1782         }
1783
1784         return OPERATOR_FINISHED;
1785 }
1786
1787 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
1788 {
1789         /* identifiers */
1790         ot->name= "View Orbit";
1791         ot->description = "Orbit the view.";
1792         ot->idname= "VIEW3D_OT_view_orbit";
1793
1794         /* api callbacks */
1795         ot->exec= vieworbit_exec;
1796         ot->poll= ED_operator_view3d_active;
1797
1798         /* flags */
1799         ot->flag= 0;
1800         RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
1801 }
1802
1803 static EnumPropertyItem prop_view_pan_items[] = {
1804         {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
1805         {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
1806         {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
1807         {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
1808         {0, NULL, 0, NULL, NULL}};
1809
1810 static int viewpan_exec(bContext *C, wmOperator *op)
1811 {
1812         ARegion *ar= CTX_wm_region(C);
1813         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1814         float vec[3];
1815         int pandir;
1816
1817         pandir = RNA_enum_get(op->ptr, "type");
1818
1819         initgrabz(rv3d, 0.0, 0.0, 0.0);
1820
1821         if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
1822         else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
1823         else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
1824         else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
1825         rv3d->ofs[0]+= vec[0];
1826         rv3d->ofs[1]+= vec[1];
1827         rv3d->ofs[2]+= vec[2];
1828
1829         if(rv3d->viewlock & RV3D_BOXVIEW)
1830                 view3d_boxview_sync(CTX_wm_area(C), ar);
1831
1832         ED_region_tag_redraw(ar);
1833
1834         return OPERATOR_FINISHED;
1835 }
1836
1837 void VIEW3D_OT_view_pan(wmOperatorType *ot)
1838 {
1839         /* identifiers */
1840         ot->name= "View Pan";
1841         ot->description = "Pan the view.";
1842         ot->idname= "VIEW3D_OT_view_pan";
1843
1844         /* api callbacks */
1845         ot->exec= viewpan_exec;
1846         ot->poll= ED_operator_view3d_active;
1847
1848         /* flags */
1849         ot->flag= 0;
1850         RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
1851 }
1852
1853 static int viewpersportho_exec(bContext *C, wmOperator *op)
1854 {
1855         ARegion *ar= CTX_wm_region(C);
1856         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1857
1858         if(rv3d->viewlock==0) {
1859                 if(rv3d->persp!=RV3D_ORTHO)
1860                         rv3d->persp=RV3D_ORTHO;
1861                 else rv3d->persp=RV3D_PERSP;
1862                 ED_region_tag_redraw(ar);
1863         }
1864
1865         return OPERATOR_FINISHED;
1866
1867 }
1868
1869 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
1870 {
1871         /* identifiers */
1872         ot->name= "View Persp/Ortho";
1873         ot->description = "Switch the current view from perspective/orthographic.";
1874         ot->idname= "VIEW3D_OT_view_persportho";
1875
1876         /* api callbacks */
1877         ot->exec= viewpersportho_exec;
1878         ot->poll= ED_operator_view3d_active;
1879
1880         /* flags */
1881         ot->flag= 0;
1882 }
1883
1884
1885 /* ********************* set clipping operator ****************** */
1886
1887 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
1888 {
1889         int val;
1890
1891         for(val=0; val<4; val++) {
1892
1893                 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
1894
1895                 clip[val][3]=
1896                         - clip[val][0]*clipbb->vec[val][0]
1897                         - clip[val][1]*clipbb->vec[val][1]
1898                         - clip[val][2]*clipbb->vec[val][2];
1899         }
1900 }
1901
1902 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
1903 {
1904         BoundBox clipbb_local;
1905         float imat[4][4];
1906         int i;
1907
1908         invert_m4_m4(imat, mat);
1909
1910         for(i=0; i<8; i++) {
1911                 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
1912         }
1913
1914         calc_clipping_plane(clip_local, &clipbb_local);
1915 }
1916
1917 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
1918 {
1919         if(rv3d->rflag & RV3D_CLIPPING)
1920                 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
1921 }
1922
1923 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1924 {
1925         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1926         ViewContext vc;
1927         bglMats mats;
1928         rcti rect;
1929
1930         rect.xmin= RNA_int_get(op->ptr, "xmin");
1931         rect.ymin= RNA_int_get(op->ptr, "ymin");
1932         rect.xmax= RNA_int_get(op->ptr, "xmax");
1933         rect.ymax= RNA_int_get(op->ptr, "ymax");
1934
1935         rv3d->rflag |= RV3D_CLIPPING;
1936         rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1937
1938         /* note; otherwise opengl won't work */
1939         view3d_operator_needs_opengl(C);
1940
1941         view3d_set_viewcontext(C, &vc);
1942         view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
1943         view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
1944
1945         return OPERATOR_FINISHED;
1946 }
1947
1948 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
1949 {
1950         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1951         ARegion *ar= CTX_wm_region(C);
1952
1953         if(rv3d->rflag & RV3D_CLIPPING) {
1954                 rv3d->rflag &= ~RV3D_CLIPPING;
1955                 ED_region_tag_redraw(ar);
1956                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
1957                 rv3d->clipbb= NULL;
1958                 return OPERATOR_FINISHED;
1959         }
1960         else {
1961                 return WM_border_select_invoke(C, op, event);
1962         }
1963 }
1964
1965 /* toggles */
1966 void VIEW3D_OT_clip_border(wmOperatorType *ot)
1967 {
1968
1969         /* identifiers */
1970         ot->name= "Clipping Border";
1971         ot->description = "Set the view clipping border.";
1972         ot->idname= "VIEW3D_OT_clip_border";
1973
1974         /* api callbacks */
1975         ot->invoke= view3d_clipping_invoke;
1976         ot->exec= view3d_clipping_exec;
1977         ot->modal= WM_border_select_modal;
1978
1979         ot->poll= ED_operator_view3d_active;
1980
1981         /* flags */
1982         ot->flag= 0;
1983
1984         /* rna */
1985         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1986         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1987         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1988         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1989 }
1990
1991 /* ***************** 3d cursor cursor op ******************* */
1992
1993 /* mx my in region coords */
1994 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
1995 {
1996         Scene *scene= CTX_data_scene(C);
1997         ARegion *ar= CTX_wm_region(C);
1998         View3D *v3d = CTX_wm_view3d(C);
1999         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2000         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2001         short mx, my, mval[2];
2002 //      short ctrl= 0; // XXX
2003
2004         fp= give_cursor(scene, v3d);
2005
2006 //      if(obedit && ctrl) lr_click= 1;
2007         VECCOPY(oldcurs, fp);
2008
2009         mx= event->x - ar->winrct.xmin;
2010         my= event->y - ar->winrct.ymin;
2011         project_short_noclip(ar, fp, mval);
2012
2013         initgrabz(rv3d, fp[0], fp[1], fp[2]);
2014
2015         if(mval[0]!=IS_CLIPPED) {
2016
2017                 window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2018                 sub_v3_v3v3(fp, fp, dvec);
2019         }
2020         else {
2021
2022                 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2023                 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2024
2025                 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2026                 fz= fz/rv3d->zfac;
2027
2028                 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2029                 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2030                 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2031         }
2032
2033 //      if(lr_click) {
2034                 // XXX          if(obedit->type==OB_MESH) add_click_mesh();
2035                 //              else if ELEM(obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
2036                 //              else if (obedit->type==OB_ARMATURE) addvert_armature();
2037 //              VECCOPY(fp, oldcurs);
2038 //      }
2039         // XXX notifier for scene */
2040         ED_area_tag_redraw(CTX_wm_area(C));
2041
2042         return OPERATOR_FINISHED;
2043 }
2044
2045 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2046 {
2047
2048         /* identifiers */
2049         ot->name= "Set 3D Cursor";
2050         ot->description = "Set the location of the 3D cursor.";
2051         ot->idname= "VIEW3D_OT_cursor3d";
2052
2053         /* api callbacks */
2054         ot->invoke= set_3dcursor_invoke;
2055
2056         ot->poll= ED_operator_view3d_active;
2057     
2058         /* flags */
2059         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2060     
2061         /* rna later */
2062
2063 }
2064
2065 /* ***************** manipulator op ******************* */
2066
2067
2068 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2069 {
2070         View3D *v3d = CTX_wm_view3d(C);
2071
2072         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2073         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2074
2075         /* only no modifier or shift */
2076         if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2077
2078         /* note; otherwise opengl won't work */
2079         view3d_operator_needs_opengl(C);
2080
2081         if(0==BIF_do_manipulator(C, event, op))
2082                 return OPERATOR_PASS_THROUGH;
2083
2084         return OPERATOR_FINISHED;
2085 }
2086
2087 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2088 {
2089
2090         /* identifiers */
2091         ot->name= "3D Manipulator";
2092         ot->description = "Manipulate selected item by axis.";
2093         ot->idname= "VIEW3D_OT_manipulator";
2094
2095         /* api callbacks */
2096         ot->invoke= manipulator_invoke;
2097
2098         ot->poll= ED_operator_view3d_active;
2099
2100         /* rna later */
2101         RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
2102 }
2103
2104
2105
2106 /* ************************* below the line! *********************** */
2107
2108
2109 /* XXX todo Zooms in on a border drawn by the user */
2110 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2111 {
2112         RegionView3D *rv3d= ar->regiondata;
2113         bglMats mats; /* ZBuffer depth vars */
2114         rcti rect;
2115         float depth, depth_close= MAXFLOAT;
2116         int had_depth = 0;
2117         double cent[2],  p[3];
2118         int xs, ys;
2119
2120         rect.xmax = mval[0] + 4;
2121         rect.ymax = mval[1] + 4;
2122
2123         rect.xmin = mval[0] - 4;
2124         rect.ymin = mval[1] - 4;
2125
2126         /* Get Z Depths, needed for perspective, nice for ortho */
2127         bgl_get_mats(&mats);
2128         draw_depth(scene, ar, v3d, NULL);
2129
2130         /* force updating */
2131         if (rv3d->depths) {
2132                 had_depth = 1;
2133                 rv3d->depths->damaged = 1;
2134         }
2135
2136         view3d_update_depths(ar, v3d);
2137
2138         /* Constrain rect to depth bounds */
2139         if (rect.xmin < 0) rect.xmin = 0;
2140         if (rect.ymin < 0) rect.ymin = 0;
2141         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
2142         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
2143
2144         /* Find the closest Z pixel */
2145         for (xs=rect.xmin; xs < rect.xmax; xs++) {
2146                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
2147                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
2148                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
2149                                 if (depth_close > depth) {
2150                                         depth_close = depth;
2151                                 }
2152                         }
2153                 }
2154         }
2155
2156         if (depth_close==MAXFLOAT)
2157                 return 0;
2158
2159         if (had_depth==0) {
2160                 MEM_freeN(rv3d->depths->depths);
2161                 rv3d->depths->depths = NULL;
2162         }
2163         rv3d->depths->damaged = 1;
2164
2165         cent[0] = (double)mval[0];
2166         cent[1] = (double)mval[1];
2167
2168         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2169                 return 0;
2170
2171         mouse_worldloc[0] = (float)p[0];
2172         mouse_worldloc[1] = (float)p[1];
2173         mouse_worldloc[2] = (float)p[2];
2174         return 1;
2175 }
2176
2177
2178
2179 /* ********************* NDOF ************************ */
2180 /* note: this code is confusing and unclear... (ton) */
2181 /* **************************************************** */
2182
2183 // ndof scaling will be moved to user setting.
2184 // In the mean time this is just a place holder.
2185
2186 // Note: scaling in the plugin and ghostwinlay.c
2187 // should be removed. With driver default setting,
2188 // each axis returns approx. +-200 max deflection.
2189
2190 // The values I selected are based on the older
2191 // polling i/f. With event i/f, the sensistivity
2192 // can be increased for improved response from
2193 // small deflections of the device input.
2194
2195
2196 // lukep notes : i disagree on the range.
2197 // the normal 3Dconnection driver give +/-400
2198 // on defaut range in other applications
2199 // and up to +/- 1000 if set to maximum
2200 // because i remove the scaling by delta,
2201 // which was a bad idea as it depend of the system
2202 // speed and os, i changed the scaling values, but
2203 // those are still not ok
2204
2205
2206 float ndof_axis_scale[6] = {
2207         +0.01,  // Tx
2208         +0.01,  // Tz
2209         +0.01,  // Ty
2210         +0.0015,        // Rx
2211         +0.0015,        // Rz
2212         +0.0015 // Ry
2213 };
2214
2215 void filterNDOFvalues(float *sbval)
2216 {
2217         int i=0;
2218         float max  = 0.0;
2219
2220         for (i =0; i<6;i++)
2221                 if (fabs(sbval[i]) > max)
2222                         max = fabs(sbval[i]);
2223         for (i =0; i<6;i++)
2224                 if (fabs(sbval[i]) != max )
2225                         sbval[i]=0.0;
2226 }
2227
2228 // statics for controlling rv3d->dist corrections.
2229 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2230 // viewmove restores based on dz_flag state.
2231
2232 int dz_flag = 0;
2233 float m_dist;
2234
2235 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2236 {
2237         RegionView3D *rv3d= ar->regiondata;
2238     int i;
2239     float phi;
2240     float dval[7];
2241         // static fval[6] for low pass filter; device input vector is dval[6]
2242         static float fval[6];
2243     float tvec[3],rvec[3];
2244     float q1[4];
2245         float mat[3][3];
2246         float upvec[3];
2247
2248
2249     /*----------------------------------------------------
2250          * sometimes this routine is called from headerbuttons
2251      * viewmove needs to refresh the screen
2252      */
2253 // XXX  areawinset(ar->win);
2254
2255
2256         // fetch the current state of the ndof device
2257 // XXX  getndof(dval);
2258
2259         if (v3d->ndoffilter)
2260                 filterNDOFvalues(fval);
2261
2262         // Scale input values
2263
2264 //      if(dval[6] == 0) return; // guard against divide by zero
2265
2266         for(i=0;i<6;i++) {
2267
2268                 // user scaling
2269                 dval[i] = dval[i] * ndof_axis_scale[i];
2270         }
2271
2272
2273         // low pass filter with zero crossing reset
2274
2275         for(i=0;i<6;i++) {
2276                 if((dval[i] * fval[i]) >= 0)
2277                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
2278                 else
2279                         fval[i] = 0;
2280         }
2281
2282
2283         // force perspective mode. This is a hack and is
2284         // incomplete. It doesn't actually effect the view
2285         // until the first draw and doesn't update the menu
2286         // to reflect persp mode.
2287
2288         rv3d->persp = RV3D_PERSP;
2289
2290
2291         // Correct the distance jump if rv3d->dist != 0
2292
2293         // This is due to a side effect of the original
2294         // mouse view rotation code. The rotation point is
2295         // set a distance in front of the viewport to
2296         // make rotating with the mouse look better.
2297         // The distance effect is written at a low level
2298         // in the view management instead of the mouse
2299         // view function. This means that all other view
2300         // movement devices must subtract this from their
2301         // view transformations.
2302
2303         if(rv3d->dist != 0.0) {
2304                 dz_flag = 1;
2305                 m_dist = rv3d->dist;
2306                 upvec[0] = upvec[1] = 0;
2307                 upvec[2] = rv3d->dist;
2308                 copy_m3_m4(mat, rv3d->viewinv);
2309                 mul_m3_v3(mat, upvec);
2310                 sub_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2311                 rv3d->dist = 0.0;
2312         }
2313
2314
2315         // Apply rotation
2316         // Rotations feel relatively faster than translations only in fly mode, so
2317         // we have no choice but to fix that here (not in the plugins)
2318         rvec[0] = -0.5 * dval[3];
2319         rvec[1] = -0.5 * dval[4];
2320         rvec[2] = -0.5 * dval[5];
2321
2322         // rotate device x and y by view z
2323
2324         copy_m3_m4(mat, rv3d->viewinv);
2325         mat[2][2] = 0.0f;
2326         mul_m3_v3(mat, rvec);
2327
2328         // rotate the view
2329
2330         phi = normalize_v3(rvec);
2331         if(phi != 0) {
2332                 axis_angle_to_quat(q1,rvec,phi);
2333                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2334         }
2335
2336
2337         // Apply translation
2338
2339         tvec[0] = dval[0];
2340         tvec[1] = dval[1];
2341         tvec[2] = -dval[2];
2342
2343         // the next three lines rotate the x and y translation coordinates
2344         // by the current z axis angle
2345
2346         copy_m3_m4(mat, rv3d->viewinv);
2347         mat[2][2] = 0.0f;
2348         mul_m3_v3(mat, tvec);
2349
2350         // translate the view
2351
2352         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, tvec);
2353
2354
2355         /*----------------------------------------------------
2356      * refresh the screen XXX
2357       */
2358
2359         // update render preview window
2360
2361 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2362 }
2363
2364 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2365 {
2366         RegionView3D *rv3d= ar->regiondata;
2367         float fval[7];
2368         float dvec[3];
2369         float sbadjust = 1.0f;
2370         float len;
2371         short use_sel = 0;
2372         Object *ob = OBACT;
2373         float m[3][3];
2374         float m_inv[3][3];
2375         float xvec[3] = {1,0,0};
2376         float yvec[3] = {0,-1,0};
2377         float zvec[3] = {0,0,1};
2378         float phi, si;
2379         float q1[4];
2380         float obofs[3];
2381         float reverse;
2382         //float diff[4];
2383         float d, curareaX, curareaY;
2384         float mat[3][3];
2385         float upvec[3];
2386
2387     /* Sensitivity will control how fast the view rotates.  The value was
2388      * obtained experimentally by tweaking until the author didn't get dizzy watching.
2389      * Perhaps this should be a configurable user parameter.
2390      */
2391         float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
2392         float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
2393         float zsens = 0.3f;   /* zoom sensitivity */
2394
2395         const float minZoom = -30.0f;
2396         const float maxZoom = 300.0f;
2397
2398         //reset view type
2399         rv3d->view = 0;
2400 //printf("passing here \n");
2401 //
2402         if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
2403                 use_sel = 1;
2404         }
2405
2406         if((dz_flag)||rv3d->dist==0) {
2407                 dz_flag = 0;
2408                 rv3d->dist = m_dist;
2409                 upvec[0] = upvec[1] = 0;
2410                 upvec[2] = rv3d->dist;
2411                 copy_m3_m4(mat, rv3d->viewinv);
2412                 mul_m3_v3(mat, upvec);
2413                 add_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2414         }
2415
2416     /*----------------------------------------------------
2417          * sometimes this routine is called from headerbuttons
2418      * viewmove needs to refresh the screen
2419      */
2420 // XXX  areawinset(curarea->win);
2421
2422     /*----------------------------------------------------
2423      * record how much time has passed. clamp at 10 Hz
2424      * pretend the previous frame occured at the clamped time
2425      */
2426 //    now = PIL_check_seconds_timer();
2427  //   frametime = (now - prevTime);
2428  //   if (frametime > 0.1f){        /* if more than 1/10s */
2429  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
2430 //    }
2431 //    prevTime = now;
2432  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
2433
2434     /* fetch the current state of the ndof device & enforce dominant mode if selected */
2435 // XXX    getndof(fval);
2436         if (v3d->ndoffilter)
2437                 filterNDOFvalues(fval);
2438
2439
2440     // put scaling back here, was previously in ghostwinlay
2441         fval[0] = fval[0] * (1.0f/600.0f);
2442         fval[1] = fval[1] * (1.0f/600.0f);
2443         fval[2] = fval[2] * (1.0f/1100.0f);
2444         fval[3] = fval[3] * 0.00005f;
2445         fval[4] =-fval[4] * 0.00005f;
2446         fval[5] = fval[5] * 0.00005f;
2447         fval[6] = fval[6] / 1000000.0f;
2448
2449     // scale more if not in perspective mode
2450         if (rv3d->persp == RV3D_ORTHO) {
2451                 fval[0] = fval[0] * 0.05f;
2452                 fval[1] = fval[1] * 0.05f;
2453                 fval[2] = fval[2] * 0.05f;
2454                 fval[3] = fval[3] * 0.9f;
2455                 fval[4] = fval[4] * 0.9f;
2456                 fval[5] = fval[5] * 0.9f;
2457                 zsens *= 8;
2458         }
2459
2460     /* set object offset */
2461         if (ob) {
2462                 obofs[0] = -ob->obmat[3][0];
2463                 obofs[1] = -ob->obmat[3][1];
2464                 obofs[2] = -ob->obmat[3][2];
2465         }
2466         else {
2467                 VECCOPY(obofs, rv3d->ofs);
2468         }
2469
2470     /* calc an adjustment based on distance from camera
2471        disabled per patch 14402 */
2472      d = 1.0f;
2473
2474 /*    if (ob) {
2475         sub_v3_v3v3(diff, obofs, rv3d->ofs);
2476         d = len_v3(diff);
2477     }
2478 */
2479
2480     reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
2481
2482     /*----------------------------------------------------
2483      * ndof device pan
2484      */
2485     psens *= 1.0f + d;
2486     curareaX = sbadjust * psens * fval[0];
2487     curareaY = sbadjust * psens * fval[1];
2488     dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
2489     dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
2490     dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
2491     add_v3_v3v3(rv3d->ofs, rv3d->ofs, dvec);
2492
2493     /*----------------------------------------------------
2494      * ndof device dolly
2495      */
2496     len = zsens * sbadjust * fval[2];
2497
2498     if (rv3d->persp==RV3D_CAMOB) {
2499         if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
2500             rv3d->camzoom+= 10.0f * -len;
2501         }
2502         if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
2503         else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
2504     }
2505     else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
2506         rv3d->dist*=(1.0 + len);
2507     }
2508
2509
2510     /*----------------------------------------------------
2511      * ndof device turntable
2512      * derived from the turntable code in viewmove
2513      */
2514
2515     /* Get the 3x3 matrix and its inverse from the quaternion */
2516     quat_to_mat3( m,rv3d->viewquat);
2517     invert_m3_m3(m_inv,m);
2518
2519     /* Determine the direction of the x vector (for rotating up and down) */
2520     /* This can likely be compuated directly from the quaternion. */
2521     mul_m3_v3(m_inv,xvec);
2522     mul_m3_v3(m_inv,yvec);
2523     mul_m3_v3(m_inv,zvec);
2524
2525     /* Perform the up/down rotation */
2526     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
2527     si = sin(phi);
2528     q1[0] = cos(phi);
2529     q1[1] = si * xvec[0];
2530     q1[2] = si * xvec[1];
2531     q1[3] = si * xvec[2];
2532     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2533
2534     if (use_sel) {
2535         conjugate_qt(q1); /* conj == inv for unit quat */
2536         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2537         mul_qt_v3(q1, rv3d->ofs);
2538         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2539     }
2540
2541     /* Perform the orbital rotation */
2542     /* Perform the orbital rotation
2543        If the seen Up axis is parallel to the zoom axis, rotation should be
2544        achieved with a pure Roll motion (no Spin) on the device. When you start
2545        to tilt, moving from Top to Side view, Spinning will increasingly become
2546        more relevant while the Roll component will decrease. When a full
2547        Side view is reached, rotations around the world's Up axis are achieved
2548        with a pure Spin-only motion.  In other words the control of the spinning
2549        around the world's Up axis should move from the device's Spin axis to the
2550        device's Roll axis depending on the orientation of the world's Up axis
2551        relative to the screen. */
2552     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
2553     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
2554     q1[0] = cos(phi);
2555     q1[1] = q1[2] = 0.0;
2556     q1[3] = sin(phi);
2557     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2558
2559     if (use_sel) {
2560         conjugate_qt(q1);
2561         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2562         mul_qt_v3(q1, rv3d->ofs);
2563         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2564     }
2565
2566     /*----------------------------------------------------
2567      * refresh the screen
2568      */
2569 // XXX    scrarea_do_windraw(curarea);
2570 }
2571
2572
2573
2574