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