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