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