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