Fix for [#19921] pressing NumpadDot on isolated mode centers the 3D cursor
[blender-staging.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;
1632
1633         viewnum = RNA_enum_get(op->ptr, "type");
1634         align_active = RNA_boolean_get(op->ptr, "align_active");
1635
1636         /* Use this to test if we started out with a camera */
1637
1638         switch (viewnum) {
1639                 case RV3D_VIEW_BOTTOM :
1640                         axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, perspo, align_active);
1641                         break;
1642
1643                 case RV3D_VIEW_BACK:
1644                         axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, perspo, align_active);
1645                         break;
1646
1647                 case RV3D_VIEW_LEFT:
1648                         axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, perspo, align_active);
1649                         break;
1650
1651                 case RV3D_VIEW_TOP:
1652                         axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, perspo, align_active);
1653                         break;
1654
1655                 case RV3D_VIEW_FRONT:
1656                         axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, perspo, align_active);
1657                         break;
1658
1659                 case RV3D_VIEW_RIGHT:
1660                         axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, perspo, align_active);
1661                         break;
1662
1663                 case RV3D_VIEW_CAMERA:
1664                         if(rv3d->viewlock==0) {
1665                                 /* lastview -  */
1666
1667                                 if(rv3d->persp != RV3D_CAMOB) {
1668                                         /* store settings of current view before allowing overwriting with camera view */
1669                                         QUATCOPY(rv3d->lviewquat, rv3d->viewquat);
1670                                         rv3d->lview= rv3d->view;
1671                                         rv3d->lpersp= rv3d->persp;
1672
1673         #if 0
1674                                         if(G.qual==LR_ALTKEY) {
1675                                                 if(oldcamera && is_an_active_object(oldcamera)) {
1676                                                         v3d->camera= oldcamera;
1677                                                 }
1678                                                 handle_view3d_lock();
1679                                         }
1680         #endif
1681
1682                                         if(BASACT) {
1683                                                 /* check both G.vd as G.scene cameras */
1684                                                 if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1685                                                         v3d->camera= OBACT;
1686                                                         /*handle_view3d_lock();*/
1687                                                 }
1688                                         }
1689
1690                                         if(v3d->camera==NULL) {
1691                                                 v3d->camera= scene_find_camera(scene);
1692                                                 /*handle_view3d_lock();*/
1693                                         }
1694                                         rv3d->persp= RV3D_CAMOB;
1695                                         smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
1696
1697                                 }
1698                                 else{
1699                                         /* return to settings of last view */
1700                                         /* does smooth_view too */
1701                                         axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
1702                                 }
1703                         }
1704                         break;
1705
1706                 default :
1707                         break;
1708         }
1709
1710         if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
1711
1712         return OPERATOR_FINISHED;
1713 }
1714 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1715 {
1716         /* identifiers */
1717         ot->name= "View numpad";
1718         ot->description = "Set the view.";
1719         ot->idname= "VIEW3D_OT_viewnumpad";
1720
1721         /* api callbacks */
1722         ot->exec= viewnumpad_exec;
1723         ot->poll= ED_operator_view3d_active;
1724
1725         /* flags */
1726         ot->flag= 0;
1727
1728         RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
1729         RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
1730 }
1731
1732 static EnumPropertyItem prop_view_orbit_items[] = {
1733         {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
1734         {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
1735         {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
1736         {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
1737         {0, NULL, 0, NULL, NULL}};
1738
1739 static int vieworbit_exec(bContext *C, wmOperator *op)
1740 {
1741         ARegion *ar= CTX_wm_region(C);
1742         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1743         float phi, si, q1[4];
1744         int orbitdir;
1745
1746         orbitdir = RNA_enum_get(op->ptr, "type");
1747
1748         if(rv3d->viewlock==0) {
1749
1750                 if(rv3d->persp != RV3D_CAMOB) {
1751                         if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
1752                                 /* z-axis */
1753                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1754                                 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
1755                                 si= (float)sin(phi);
1756                                 q1[0]= (float)cos(phi);
1757                                 q1[1]= q1[2]= 0.0;
1758                                 q1[3]= si;
1759                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
1760                                 rv3d->view= 0;
1761                         }
1762                         if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
1763                                 /* horizontal axis */
1764                                 VECCOPY(q1+1, rv3d->viewinv[0]);
1765
1766                                 normalize_v3(q1+1);
1767                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1768                                 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
1769                                 si= (float)sin(phi);
1770                                 q1[0]= (float)cos(phi);
1771                                 q1[1]*= si;
1772                                 q1[2]*= si;
1773                                 q1[3]*= si;
1774                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
1775                                 rv3d->view= 0;
1776                         }
1777                         ED_region_tag_redraw(ar);
1778                 }
1779         }
1780
1781         return OPERATOR_FINISHED;
1782 }
1783
1784 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
1785 {
1786         /* identifiers */
1787         ot->name= "View Orbit";
1788         ot->description = "Orbit the view.";
1789         ot->idname= "VIEW3D_OT_view_orbit";
1790
1791         /* api callbacks */
1792         ot->exec= vieworbit_exec;
1793         ot->poll= ED_operator_view3d_active;
1794
1795         /* flags */
1796         ot->flag= 0;
1797         RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
1798 }
1799
1800 static EnumPropertyItem prop_view_pan_items[] = {
1801         {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
1802         {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
1803         {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
1804         {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
1805         {0, NULL, 0, NULL, NULL}};
1806
1807 static int viewpan_exec(bContext *C, wmOperator *op)
1808 {
1809         ARegion *ar= CTX_wm_region(C);
1810         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1811         float vec[3];
1812         int pandir;
1813
1814         pandir = RNA_enum_get(op->ptr, "type");
1815
1816         initgrabz(rv3d, 0.0, 0.0, 0.0);
1817
1818         if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
1819         else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
1820         else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
1821         else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
1822         rv3d->ofs[0]+= vec[0];
1823         rv3d->ofs[1]+= vec[1];
1824         rv3d->ofs[2]+= vec[2];
1825
1826         if(rv3d->viewlock & RV3D_BOXVIEW)
1827                 view3d_boxview_sync(CTX_wm_area(C), ar);
1828
1829         ED_region_tag_redraw(ar);
1830
1831         return OPERATOR_FINISHED;
1832 }
1833
1834 void VIEW3D_OT_view_pan(wmOperatorType *ot)
1835 {
1836         /* identifiers */
1837         ot->name= "View Pan";
1838         ot->description = "Pan the view.";
1839         ot->idname= "VIEW3D_OT_view_pan";
1840
1841         /* api callbacks */
1842         ot->exec= viewpan_exec;
1843         ot->poll= ED_operator_view3d_active;
1844
1845         /* flags */
1846         ot->flag= 0;
1847         RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
1848 }
1849
1850 static int viewpersportho_exec(bContext *C, wmOperator *op)
1851 {
1852         ARegion *ar= CTX_wm_region(C);
1853         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1854
1855         if(rv3d->viewlock==0) {
1856                 if(rv3d->persp!=RV3D_ORTHO)
1857                         rv3d->persp=RV3D_ORTHO;
1858                 else rv3d->persp=RV3D_PERSP;
1859                 ED_region_tag_redraw(ar);
1860         }
1861
1862         return OPERATOR_FINISHED;
1863
1864 }
1865
1866 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
1867 {
1868         /* identifiers */
1869         ot->name= "View Persp/Ortho";
1870         ot->description = "Switch the current view from perspective/orthographic.";
1871         ot->idname= "VIEW3D_OT_view_persportho";
1872
1873         /* api callbacks */
1874         ot->exec= viewpersportho_exec;
1875         ot->poll= ED_operator_view3d_active;
1876
1877         /* flags */
1878         ot->flag= 0;
1879 }
1880
1881
1882 /* ********************* set clipping operator ****************** */
1883
1884 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
1885 {
1886         int val;
1887
1888         for(val=0; val<4; val++) {
1889
1890                 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
1891
1892                 clip[val][3]=
1893                         - clip[val][0]*clipbb->vec[val][0]
1894                         - clip[val][1]*clipbb->vec[val][1]
1895                         - clip[val][2]*clipbb->vec[val][2];
1896         }
1897 }
1898
1899 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
1900 {
1901         BoundBox clipbb_local;
1902         float imat[4][4];
1903         int i;
1904
1905         invert_m4_m4(imat, mat);
1906
1907         for(i=0; i<8; i++) {
1908                 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
1909         }
1910
1911         calc_clipping_plane(clip_local, &clipbb_local);
1912 }
1913
1914 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
1915 {
1916         if(rv3d->rflag & RV3D_CLIPPING)
1917                 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
1918 }
1919
1920 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1921 {
1922         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1923         rcti rect;
1924         double mvmatrix[16];
1925         double projmatrix[16];
1926         double xs, ys, p[3];
1927         GLint viewport[4];
1928         short val;
1929
1930         rect.xmin= RNA_int_get(op->ptr, "xmin");
1931         rect.ymin= RNA_int_get(op->ptr, "ymin");
1932         rect.xmax= RNA_int_get(op->ptr, "xmax");
1933         rect.ymax= RNA_int_get(op->ptr, "ymax");
1934
1935         rv3d->rflag |= RV3D_CLIPPING;
1936         rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1937
1938         /* note; otherwise opengl won't work */
1939         view3d_operator_needs_opengl(C);
1940
1941         /* Get the matrices needed for gluUnProject */
1942         glGetIntegerv(GL_VIEWPORT, viewport);
1943         glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
1944         glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
1945
1946         /* near zero floating point values can give issues with gluUnProject
1947                 in side view on some implementations */
1948         if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
1949         if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
1950
1951         /* Set up viewport so that gluUnProject will give correct values */
1952         viewport[0] = 0;
1953         viewport[1] = 0;
1954
1955         /* four clipping planes and bounding volume */
1956         /* first do the bounding volume */
1957         for(val=0; val<4; val++) {
1958
1959                 xs= (val==0||val==3)?rect.xmin:rect.xmax;
1960                 ys= (val==0||val==1)?rect.ymin:rect.ymax;
1961
1962                 gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1963                 VECCOPY(rv3d->clipbb->vec[val], p);
1964
1965                 gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1966                 VECCOPY(rv3d->clipbb->vec[4+val], p);
1967         }
1968
1969         /* then plane equations */
1970         calc_clipping_plane(rv3d->clip, rv3d->clipbb);
1971
1972         return OPERATOR_FINISHED;
1973 }
1974
1975 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
1976 {
1977         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1978         ARegion *ar= CTX_wm_region(C);
1979
1980         if(rv3d->rflag & RV3D_CLIPPING) {
1981                 rv3d->rflag &= ~RV3D_CLIPPING;
1982                 ED_region_tag_redraw(ar);
1983                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
1984                 rv3d->clipbb= NULL;
1985                 return OPERATOR_FINISHED;
1986         }
1987         else {
1988                 return WM_border_select_invoke(C, op, event);
1989         }
1990 }
1991
1992 /* toggles */
1993 void VIEW3D_OT_clip_border(wmOperatorType *ot)
1994 {
1995
1996         /* identifiers */
1997         ot->name= "Clipping Border";
1998         ot->description = "Set the view clipping border.";
1999         ot->idname= "VIEW3D_OT_clip_border";
2000
2001         /* api callbacks */
2002         ot->invoke= view3d_clipping_invoke;
2003         ot->exec= view3d_clipping_exec;
2004         ot->modal= WM_border_select_modal;
2005
2006         ot->poll= ED_operator_view3d_active;
2007
2008         /* flags */
2009         ot->flag= 0;
2010
2011         /* rna */
2012         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2013         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2014         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2015         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2016 }
2017
2018 /* ***************** 3d cursor cursor op ******************* */
2019
2020 /* mx my in region coords */
2021 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
2022 {
2023         Scene *scene= CTX_data_scene(C);
2024         ARegion *ar= CTX_wm_region(C);
2025         View3D *v3d = CTX_wm_view3d(C);
2026         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2027         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2028         short mx, my, mval[2];
2029 //      short ctrl= 0; // XXX
2030
2031         fp= give_cursor(scene, v3d);
2032
2033 //      if(obedit && ctrl) lr_click= 1;
2034         VECCOPY(oldcurs, fp);
2035
2036         mx= event->x - ar->winrct.xmin;
2037         my= event->y - ar->winrct.ymin;
2038         project_short_noclip(ar, fp, mval);
2039
2040         initgrabz(rv3d, fp[0], fp[1], fp[2]);
2041
2042         if(mval[0]!=IS_CLIPPED) {
2043
2044                 window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2045                 sub_v3_v3v3(fp, fp, dvec);
2046         }
2047         else {
2048
2049                 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2050                 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2051
2052                 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2053                 fz= fz/rv3d->zfac;
2054
2055                 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2056                 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2057                 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2058         }
2059
2060 //      if(lr_click) {
2061                 // XXX          if(obedit->type==OB_MESH) add_click_mesh();
2062                 //              else if ELEM(obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
2063                 //              else if (obedit->type==OB_ARMATURE) addvert_armature();
2064 //              VECCOPY(fp, oldcurs);
2065 //      }
2066         // XXX notifier for scene */
2067         ED_area_tag_redraw(CTX_wm_area(C));
2068
2069         return OPERATOR_FINISHED;
2070 }
2071
2072 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2073 {
2074
2075         /* identifiers */
2076         ot->name= "Set 3D Cursor";
2077         ot->description = "Set the location of the 3D cursor.";
2078         ot->idname= "VIEW3D_OT_cursor3d";
2079
2080         /* api callbacks */
2081         ot->invoke= set_3dcursor_invoke;
2082
2083         ot->poll= ED_operator_view3d_active;
2084     
2085         /* flags */
2086         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2087     
2088         /* rna later */
2089
2090 }
2091
2092 /* ***************** manipulator op ******************* */
2093
2094
2095 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2096 {
2097         View3D *v3d = CTX_wm_view3d(C);
2098
2099         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2100         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2101
2102         /* only no modifier or shift */
2103         if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2104
2105         /* note; otherwise opengl won't work */
2106         view3d_operator_needs_opengl(C);
2107
2108         if(0==BIF_do_manipulator(C, event, op))
2109                 return OPERATOR_PASS_THROUGH;
2110
2111         return OPERATOR_FINISHED;
2112 }
2113
2114 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2115 {
2116
2117         /* identifiers */
2118         ot->name= "3D Manipulator";
2119         ot->description = "Manipulate selected item by axis.";
2120         ot->idname= "VIEW3D_OT_manipulator";
2121
2122         /* api callbacks */
2123         ot->invoke= manipulator_invoke;
2124
2125         ot->poll= ED_operator_view3d_active;
2126
2127         /* rna later */
2128         RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
2129 }
2130
2131
2132
2133 /* ************************* below the line! *********************** */
2134
2135
2136 /* XXX todo Zooms in on a border drawn by the user */
2137 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2138 {
2139         RegionView3D *rv3d= ar->regiondata;
2140         bglMats mats; /* ZBuffer depth vars */
2141         rcti rect;
2142         float depth, depth_close= MAXFLOAT;
2143         int had_depth = 0;
2144         double cent[2],  p[3];
2145         int xs, ys;
2146
2147         rect.xmax = mval[0] + 4;
2148         rect.ymax = mval[1] + 4;
2149
2150         rect.xmin = mval[0] - 4;
2151         rect.ymin = mval[1] - 4;
2152
2153         /* Get Z Depths, needed for perspective, nice for ortho */
2154         bgl_get_mats(&mats);
2155         draw_depth(scene, ar, v3d, NULL);
2156
2157         /* force updating */
2158         if (rv3d->depths) {
2159                 had_depth = 1;
2160                 rv3d->depths->damaged = 1;
2161         }
2162
2163         view3d_update_depths(ar, v3d);
2164
2165         /* Constrain rect to depth bounds */
2166         if (rect.xmin < 0) rect.xmin = 0;
2167         if (rect.ymin < 0) rect.ymin = 0;
2168         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
2169         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
2170
2171         /* Find the closest Z pixel */
2172         for (xs=rect.xmin; xs < rect.xmax; xs++) {
2173                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
2174                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
2175                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
2176                                 if (depth_close > depth) {
2177                                         depth_close = depth;
2178                                 }
2179                         }
2180                 }
2181         }
2182
2183         if (depth_close==MAXFLOAT)
2184                 return 0;
2185
2186         if (had_depth==0) {
2187                 MEM_freeN(rv3d->depths->depths);
2188                 rv3d->depths->depths = NULL;
2189         }
2190         rv3d->depths->damaged = 1;
2191
2192         cent[0] = (double)mval[0];
2193         cent[1] = (double)mval[1];
2194
2195         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2196                 return 0;
2197
2198         mouse_worldloc[0] = (float)p[0];
2199         mouse_worldloc[1] = (float)p[1];
2200         mouse_worldloc[2] = (float)p[2];
2201         return 1;
2202 }
2203
2204 int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d) //, float *autodist )
2205 {
2206         RegionView3D *rv3d= ar->regiondata;
2207
2208         /* Get Z Depths, needed for perspective, nice for ortho */
2209         draw_depth(scene, ar, v3d, NULL);
2210
2211         /* force updating */
2212         if (rv3d->depths) {
2213                 rv3d->depths->damaged = 1;
2214         }
2215
2216         view3d_update_depths(ar, v3d);
2217         return 1;
2218 }
2219
2220 // no 4x4 sampling, run view_autodist_init first
2221 int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2222 {
2223         RegionView3D *rv3d= ar->regiondata;
2224         bglMats mats; /* ZBuffer depth vars, could cache? */
2225         float depth;
2226         double cent[2],  p[3];
2227
2228         if (mval[0] < 0) return 0;
2229         if (mval[1] < 0) return 0;
2230         if (mval[0] >= rv3d->depths->w) return 0;
2231         if (mval[1] >= rv3d->depths->h) return 0;
2232
2233         /* Get Z Depths, needed for perspective, nice for ortho */
2234         bgl_get_mats(&mats);
2235         depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
2236
2237         if (depth==MAXFLOAT)
2238                 return 0;
2239
2240         cent[0] = (double)mval[0];
2241         cent[1] = (double)mval[1];
2242
2243         if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2244                 return 0;
2245
2246         mouse_worldloc[0] = (float)p[0];
2247         mouse_worldloc[1] = (float)p[1];
2248         mouse_worldloc[2] = (float)p[2];
2249         return 1;
2250 }
2251
2252 /* ********************* NDOF ************************ */
2253 /* note: this code is confusing and unclear... (ton) */
2254 /* **************************************************** */
2255
2256 // ndof scaling will be moved to user setting.
2257 // In the mean time this is just a place holder.
2258
2259 // Note: scaling in the plugin and ghostwinlay.c
2260 // should be removed. With driver default setting,
2261 // each axis returns approx. +-200 max deflection.
2262
2263 // The values I selected are based on the older
2264 // polling i/f. With event i/f, the sensistivity
2265 // can be increased for improved response from
2266 // small deflections of the device input.
2267
2268
2269 // lukep notes : i disagree on the range.
2270 // the normal 3Dconnection driver give +/-400
2271 // on defaut range in other applications
2272 // and up to +/- 1000 if set to maximum
2273 // because i remove the scaling by delta,
2274 // which was a bad idea as it depend of the system
2275 // speed and os, i changed the scaling values, but
2276 // those are still not ok
2277
2278
2279 float ndof_axis_scale[6] = {
2280         +0.01,  // Tx
2281         +0.01,  // Tz
2282         +0.01,  // Ty
2283         +0.0015,        // Rx
2284         +0.0015,        // Rz
2285         +0.0015 // Ry
2286 };
2287
2288 void filterNDOFvalues(float *sbval)
2289 {
2290         int i=0;
2291         float max  = 0.0;
2292
2293         for (i =0; i<6;i++)
2294                 if (fabs(sbval[i]) > max)
2295                         max = fabs(sbval[i]);
2296         for (i =0; i<6;i++)
2297                 if (fabs(sbval[i]) != max )
2298                         sbval[i]=0.0;
2299 }
2300
2301 // statics for controlling rv3d->dist corrections.
2302 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2303 // viewmove restores based on dz_flag state.
2304
2305 int dz_flag = 0;
2306 float m_dist;
2307
2308 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2309 {
2310         RegionView3D *rv3d= ar->regiondata;
2311     int i;
2312     float phi;
2313     float dval[7];
2314         // static fval[6] for low pass filter; device input vector is dval[6]
2315         static float fval[6];
2316     float tvec[3],rvec[3];
2317     float q1[4];
2318         float mat[3][3];
2319         float upvec[3];
2320
2321
2322     /*----------------------------------------------------
2323          * sometimes this routine is called from headerbuttons
2324      * viewmove needs to refresh the screen
2325      */
2326 // XXX  areawinset(ar->win);
2327
2328
2329         // fetch the current state of the ndof device
2330 // XXX  getndof(dval);
2331
2332         if (v3d->ndoffilter)
2333                 filterNDOFvalues(fval);
2334
2335         // Scale input values
2336
2337 //      if(dval[6] == 0) return; // guard against divide by zero
2338
2339         for(i=0;i<6;i++) {
2340
2341                 // user scaling
2342                 dval[i] = dval[i] * ndof_axis_scale[i];
2343         }
2344
2345
2346         // low pass filter with zero crossing reset
2347
2348         for(i=0;i<6;i++) {
2349                 if((dval[i] * fval[i]) >= 0)
2350                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
2351                 else
2352                         fval[i] = 0;
2353         }
2354
2355
2356         // force perspective mode. This is a hack and is
2357         // incomplete. It doesn't actually effect the view
2358         // until the first draw and doesn't update the menu
2359         // to reflect persp mode.
2360
2361         rv3d->persp = RV3D_PERSP;
2362
2363
2364         // Correct the distance jump if rv3d->dist != 0
2365
2366         // This is due to a side effect of the original
2367         // mouse view rotation code. The rotation point is
2368         // set a distance in front of the viewport to
2369         // make rotating with the mouse look better.
2370         // The distance effect is written at a low level
2371         // in the view management instead of the mouse
2372         // view function. This means that all other view
2373         // movement devices must subtract this from their
2374         // view transformations.
2375
2376         if(rv3d->dist != 0.0) {
2377                 dz_flag = 1;
2378                 m_dist = rv3d->dist;
2379                 upvec[0] = upvec[1] = 0;
2380                 upvec[2] = rv3d->dist;
2381                 copy_m3_m4(mat, rv3d->viewinv);
2382                 mul_m3_v3(mat, upvec);
2383                 sub_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2384                 rv3d->dist = 0.0;
2385         }
2386
2387
2388         // Apply rotation
2389         // Rotations feel relatively faster than translations only in fly mode, so
2390         // we have no choice but to fix that here (not in the plugins)
2391         rvec[0] = -0.5 * dval[3];
2392         rvec[1] = -0.5 * dval[4];
2393         rvec[2] = -0.5 * dval[5];
2394
2395         // rotate device x and y by view z
2396
2397         copy_m3_m4(mat, rv3d->viewinv);
2398         mat[2][2] = 0.0f;
2399         mul_m3_v3(mat, rvec);
2400
2401         // rotate the view
2402
2403         phi = normalize_v3(rvec);
2404         if(phi != 0) {
2405                 axis_angle_to_quat(q1,rvec,phi);
2406                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2407         }
2408
2409
2410         // Apply translation
2411
2412         tvec[0] = dval[0];
2413         tvec[1] = dval[1];
2414         tvec[2] = -dval[2];
2415
2416         // the next three lines rotate the x and y translation coordinates
2417         // by the current z axis angle
2418
2419         copy_m3_m4(mat, rv3d->viewinv);
2420         mat[2][2] = 0.0f;
2421         mul_m3_v3(mat, tvec);
2422
2423         // translate the view
2424
2425         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, tvec);
2426
2427
2428         /*----------------------------------------------------
2429      * refresh the screen XXX
2430       */
2431
2432         // update render preview window
2433
2434 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2435 }
2436
2437 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2438 {
2439         RegionView3D *rv3d= ar->regiondata;
2440         float fval[7];
2441         float dvec[3];
2442         float sbadjust = 1.0f;
2443         float len;
2444         short use_sel = 0;
2445         Object *ob = OBACT;
2446         float m[3][3];
2447         float m_inv[3][3];
2448         float xvec[3] = {1,0,0};
2449         float yvec[3] = {0,-1,0};
2450         float zvec[3] = {0,0,1};
2451         float phi, si;
2452         float q1[4];
2453         float obofs[3];
2454         float reverse;
2455         //float diff[4];
2456         float d, curareaX, curareaY;
2457         float mat[3][3];
2458         float upvec[3];
2459
2460     /* Sensitivity will control how fast the view rotates.  The value was
2461      * obtained experimentally by tweaking until the author didn't get dizzy watching.
2462      * Perhaps this should be a configurable user parameter.
2463      */
2464         float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
2465         float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
2466         float zsens = 0.3f;   /* zoom sensitivity */
2467
2468         const float minZoom = -30.0f;
2469         const float maxZoom = 300.0f;
2470
2471         //reset view type
2472         rv3d->view = 0;
2473 //printf("passing here \n");
2474 //
2475         if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
2476                 use_sel = 1;
2477         }
2478
2479         if((dz_flag)||rv3d->dist==0) {
2480                 dz_flag = 0;
2481                 rv3d->dist = m_dist;
2482                 upvec[0] = upvec[1] = 0;
2483                 upvec[2] = rv3d->dist;
2484                 copy_m3_m4(mat, rv3d->viewinv);
2485                 mul_m3_v3(mat, upvec);
2486                 add_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2487         }
2488
2489     /*----------------------------------------------------
2490          * sometimes this routine is called from headerbuttons
2491      * viewmove needs to refresh the screen
2492      */
2493 // XXX  areawinset(curarea->win);
2494
2495     /*----------------------------------------------------
2496      * record how much time has passed. clamp at 10 Hz
2497      * pretend the previous frame occured at the clamped time
2498      */
2499 //    now = PIL_check_seconds_timer();
2500  //   frametime = (now - prevTime);
2501  //   if (frametime > 0.1f){        /* if more than 1/10s */
2502  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
2503 //    }
2504 //    prevTime = now;
2505  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
2506
2507     /* fetch the current state of the ndof device & enforce dominant mode if selected */
2508 // XXX    getndof(fval);
2509         if (v3d->ndoffilter)
2510                 filterNDOFvalues(fval);
2511
2512
2513     // put scaling back here, was previously in ghostwinlay
2514         fval[0] = fval[0] * (1.0f/600.0f);
2515         fval[1] = fval[1] * (1.0f/600.0f);
2516         fval[2] = fval[2] * (1.0f/1100.0f);
2517         fval[3] = fval[3] * 0.00005f;
2518         fval[4] =-fval[4] * 0.00005f;
2519         fval[5] = fval[5] * 0.00005f;
2520         fval[6] = fval[6] / 1000000.0f;
2521
2522     // scale more if not in perspective mode
2523         if (rv3d->persp == RV3D_ORTHO) {
2524                 fval[0] = fval[0] * 0.05f;
2525                 fval[1] = fval[1] * 0.05f;
2526                 fval[2] = fval[2] * 0.05f;
2527                 fval[3] = fval[3] * 0.9f;
2528                 fval[4] = fval[4] * 0.9f;
2529                 fval[5] = fval[5] * 0.9f;
2530                 zsens *= 8;
2531         }
2532
2533     /* set object offset */
2534         if (ob) {
2535                 obofs[0] = -ob->obmat[3][0];
2536                 obofs[1] = -ob->obmat[3][1];
2537                 obofs[2] = -ob->obmat[3][2];
2538         }
2539         else {
2540                 VECCOPY(obofs, rv3d->ofs);
2541         }
2542
2543     /* calc an adjustment based on distance from camera
2544        disabled per patch 14402 */
2545      d = 1.0f;
2546
2547 /*    if (ob) {
2548         sub_v3_v3v3(diff, obofs, rv3d->ofs);
2549         d = len_v3(diff);
2550     }
2551 */
2552
2553     reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
2554
2555     /*----------------------------------------------------
2556      * ndof device pan
2557      */
2558     psens *= 1.0f + d;
2559     curareaX = sbadjust * psens * fval[0];
2560     curareaY = sbadjust * psens * fval[1];
2561     dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
2562     dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
2563     dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
2564     add_v3_v3v3(rv3d->ofs, rv3d->ofs, dvec);
2565
2566     /*----------------------------------------------------
2567      * ndof device dolly
2568      */
2569     len = zsens * sbadjust * fval[2];
2570
2571     if (rv3d->persp==RV3D_CAMOB) {
2572         if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
2573             rv3d->camzoom+= 10.0f * -len;
2574         }
2575         if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
2576         else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
2577     }
2578     else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
2579         rv3d->dist*=(1.0 + len);
2580     }
2581
2582
2583     /*----------------------------------------------------
2584      * ndof device turntable
2585      * derived from the turntable code in viewmove
2586      */
2587
2588     /* Get the 3x3 matrix and its inverse from the quaternion */
2589     quat_to_mat3( m,rv3d->viewquat);
2590     invert_m3_m3(m_inv,m);
2591
2592     /* Determine the direction of the x vector (for rotating up and down) */
2593     /* This can likely be compuated directly from the quaternion. */
2594     mul_m3_v3(m_inv,xvec);
2595     mul_m3_v3(m_inv,yvec);
2596     mul_m3_v3(m_inv,zvec);
2597
2598     /* Perform the up/down rotation */
2599     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
2600     si = sin(phi);
2601     q1[0] = cos(phi);
2602     q1[1] = si * xvec[0];
2603     q1[2] = si * xvec[1];
2604     q1[3] = si * xvec[2];
2605     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2606
2607     if (use_sel) {
2608         conjugate_qt(q1); /* conj == inv for unit quat */
2609         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2610         mul_qt_v3(q1, rv3d->ofs);
2611         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2612     }
2613
2614     /* Perform the orbital rotation */
2615     /* Perform the orbital rotation
2616        If the seen Up axis is parallel to the zoom axis, rotation should be
2617        achieved with a pure Roll motion (no Spin) on the device. When you start
2618        to tilt, moving from Top to Side view, Spinning will increasingly become
2619        more relevant while the Roll component will decrease. When a full
2620        Side view is reached, rotations around the world's Up axis are achieved
2621        with a pure Spin-only motion.  In other words the control of the spinning
2622        around the world's Up axis should move from the device's Spin axis to the
2623        device's Roll axis depending on the orientation of the world's Up axis
2624        relative to the screen. */
2625     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
2626     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
2627     q1[0] = cos(phi);
2628     q1[1] = q1[2] = 0.0;
2629     q1[3] = sin(phi);
2630     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2631
2632     if (use_sel) {
2633         conjugate_qt(q1);
2634         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2635         mul_qt_v3(q1, rv3d->ofs);
2636         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2637     }
2638
2639     /*----------------------------------------------------
2640      * refresh the screen
2641      */
2642 // XXX    scrarea_do_windraw(curarea);
2643 }
2644
2645
2646
2647