2.5
[blender.git] / source / blender / editors / space_view3d / view3d_edit.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_lamp_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_userdef_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_world_types.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
50 #include "BLI_rand.h"
51
52 #include "BKE_action.h"
53 #include "BKE_context.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_object.h"
56 #include "BKE_global.h"
57 #include "BKE_scene.h"
58 #include "BKE_screen.h"
59 #include "BKE_utildefines.h"
60
61 #include "RE_pipeline.h"        // make_stars
62
63 #include "BIF_gl.h"
64 #include "BIF_retopo.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68
69 #include "RNA_access.h"
70 #include "RNA_define.h"
71
72 #include "ED_screen.h"
73 #include "ED_types.h"
74
75 #include "UI_interface.h"
76 #include "UI_resources.h"
77 #include "UI_view2d.h"
78
79 #include "PIL_time.h" /* smoothview */
80
81 #include "view3d_intern.h"      // own include
82
83 /* ********************** view3d_edit: view manipulations ********************* */
84
85 /* ************************** init for view ops **********************************/
86
87 typedef struct ViewOpsData {
88         ARegion *ar;
89         View3D *v3d;
90         
91         float oldquat[4];
92         float trackvec[3];
93         float ofs[3], obofs[3];
94         float reverse, dist0;
95         
96         int origx, origy, oldx, oldy;
97         int origkey;
98         
99 } ViewOpsData;
100
101 #define TRACKBALLSIZE  (1.1)
102
103 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
104 {
105         float x, y, radius, d, z, t;
106         
107         radius= TRACKBALLSIZE;
108         
109         /* normalize x and y */
110         x= (rect->xmax + rect->xmin)/2 - mx;
111         x/= (float)((rect->xmax - rect->xmin)/4);
112         y= (rect->ymax + rect->ymin)/2 - my;
113         y/= (float)((rect->ymax - rect->ymin)/2);
114         
115         d = sqrt(x*x + y*y);
116         if (d < radius*M_SQRT1_2)       /* Inside sphere */
117                 z = sqrt(radius*radius - d*d);
118         else
119         {                       /* On hyperbola */
120                 t = radius / M_SQRT2;
121                 z = t*t / d;
122         }
123
124         vec[0]= x;
125         vec[1]= y;
126         vec[2]= -z;             /* yah yah! */
127 }
128
129
130 static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
131 {
132         ScrArea *sa= CTX_wm_area(C);
133         View3D *v3d= sa->spacedata.first;
134         ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
135         
136         /* store data */
137         op->customdata= vod;
138         vod->ar= CTX_wm_region(C);
139         vod->v3d= v3d;
140         vod->dist0= v3d->dist;
141         QUATCOPY(vod->oldquat, v3d->viewquat);
142         vod->origx= vod->oldx= event->x;
143         vod->origy= vod->oldy= event->y;
144         vod->origkey= event->type;
145         
146         calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
147         
148         initgrabz(v3d, -v3d->ofs[0], -v3d->ofs[1], -v3d->ofs[2]);
149         
150         vod->reverse= 1.0f;
151         if (v3d->persmat[2][1] < 0.0f)
152                 vod->reverse= -1.0f;
153         
154 }       
155
156 /* ************************** viewrotate **********************************/
157
158 static const float thres = 0.93f; //cos(20 deg);
159
160 #define COS45 0.70710678118654746
161 #define SIN45 COS45
162
163 static float snapquats[39][6] = {
164         /*{q0, q1, q3, q4, view, oposite_direction}*/
165 {COS45, -SIN45, 0.0, 0.0, 1, 0},  //front
166 {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back
167 {1.0, 0.0, 0.0, 0.0, 7, 0},       //top
168 {0.0, -1.0, 0.0, 0.0, 7, 1},      //bottom
169 {0.5, -0.5, -0.5, -0.5, 3, 0},    //left
170 {0.5, -0.5, 0.5, 0.5, 3, 1},      //right
171         
172         /* some more 45 deg snaps */
173 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
174 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
175 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
176 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
177 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
178 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
179 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
180 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
181 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
182 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
183 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
184 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
185 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
186 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
187 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
188 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
189 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
190 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
191 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
192 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
193 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
194 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
195 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
196 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
197 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
198 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
199 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
200 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
201 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
202 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
203 {-COS45, 0.0, 0.0, SIN45, 0, 0},
204 {COS45, 0.0, 0.0, SIN45, 0, 0},
205 {0.0, 0.0, 0.0, 1.0, 0, 0}
206 };
207
208
209 static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl)
210 {
211         View3D *v3d= vod->v3d;
212         int use_sel= 0; /* XXX */
213         
214         v3d->view= 0; /* need to reset everytime because of view snapping */
215         
216         if (U.flag & USER_TRACKBALL) {
217                 float phi, si, q1[4], dvec[3], newvec[3];
218                 
219                 calctrackballvec(&vod->ar->winrct, x, y, newvec);
220         
221                 VecSubf(dvec, newvec, vod->trackvec);
222         
223                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
224                 si/= (2.0*TRACKBALLSIZE);
225         
226                 Crossf(q1+1, vod->trackvec, newvec);
227                 Normalize(q1+1);
228                 
229                 /* Allow for rotation beyond the interval
230                         * [-pi, pi] */
231                 while (si > 1.0)
232                         si -= 2.0;
233                 
234                 /* This relation is used instead of
235                         * phi = asin(si) so that the angle
236                         * of rotation is linearly proportional
237                         * to the distance that the mouse is
238                         * dragged. */
239                 phi = si * M_PI / 2.0;
240                 
241                 si= sin(phi);
242                 q1[0]= cos(phi);
243                 q1[1]*= si;
244                 q1[2]*= si;
245                 q1[3]*= si;     
246                 QuatMul(v3d->viewquat, q1, vod->oldquat);
247                 
248                 if (use_sel) {
249                         /* compute the post multiplication quat, to rotate the offset correctly */
250                         QUATCOPY(q1, vod->oldquat);
251                         QuatConj(q1);
252                         QuatMul(q1, q1, v3d->viewquat);
253                         
254                         QuatConj(q1); /* conj == inv for unit quat */
255                         VECCOPY(v3d->ofs, vod->ofs);
256                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
257                         QuatMulVecf(q1, v3d->ofs);
258                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
259                 }
260         } 
261         else {
262                 /* New turntable view code by John Aughey */
263                 float si, phi, q1[4];
264                 float m[3][3];
265                 float m_inv[3][3];
266                 float xvec[3] = {1,0,0};
267                 /* Sensitivity will control how fast the viewport rotates.  0.0035 was
268                         obtained experimentally by looking at viewport rotation sensitivities
269                         on other modeling programs. */
270                 /* Perhaps this should be a configurable user parameter. */
271                 const float sensitivity = 0.0035;
272                 
273                 /* Get the 3x3 matrix and its inverse from the quaternion */
274                 QuatToMat3(v3d->viewquat, m);
275                 Mat3Inv(m_inv,m);
276                 
277                 /* Determine the direction of the x vector (for rotating up and down) */
278                 /* This can likely be compuated directly from the quaternion. */
279                 Mat3MulVecfl(m_inv,xvec);
280                 
281                 /* Perform the up/down rotation */
282                 phi = sensitivity * -(y - vod->oldy);
283                 si = sin(phi);
284                 q1[0] = cos(phi);
285                 q1[1] = si * xvec[0];
286                 q1[2] = si * xvec[1];
287                 q1[3] = si * xvec[2];
288                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
289                 
290                 if (use_sel) {
291                         QuatConj(q1); /* conj == inv for unit quat */
292                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
293                         QuatMulVecf(q1, v3d->ofs);
294                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
295                 }
296                 
297                 /* Perform the orbital rotation */
298                 phi = sensitivity * vod->reverse * (x - vod->oldx);
299                 q1[0] = cos(phi);
300                 q1[1] = q1[2] = 0.0;
301                 q1[3] = sin(phi);
302                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
303                 
304                 if (use_sel) {
305                         QuatConj(q1);
306                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
307                         QuatMulVecf(q1, v3d->ofs);
308                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
309                 }
310         }
311         
312         /* check for view snap */
313         if (ctrl){
314                 int i;
315                 float viewmat[3][3];
316                 
317                 
318                 QuatToMat3(v3d->viewquat, viewmat);
319                 
320                 for (i = 0 ; i < 39; i++){
321                         float snapmat[3][3];
322                         float view = (int)snapquats[i][4];
323                         float oposite_dir = (int)snapquats[i][5];
324                         
325                         QuatToMat3(snapquats[i], snapmat);
326                         
327                         if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
328                                 (Inpf(snapmat[1], viewmat[1]) > thres) &&
329                                 (Inpf(snapmat[2], viewmat[2]) > thres)){
330                                 
331                                 QUATCOPY(v3d->viewquat, snapquats[i]);
332                                 
333                                 v3d->view = view;
334                                 if (view){
335                                         if (oposite_dir){
336                                                 v3d->flag2 |= V3D_OPP_DIRECTION_NAME;
337                                         }else{
338                                                 v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME;
339                                         }
340                                 }
341                                 
342                                 break;
343                         }
344                 }
345         }
346         vod->oldx= x;
347         vod->oldy= y;
348
349         ED_region_tag_redraw(vod->ar);
350 }
351
352 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
353 {
354         ViewOpsData *vod= op->customdata;
355
356         /* execute the events */
357         switch(event->type) {
358                 case MOUSEMOVE:
359                         viewrotate_apply(vod, event->x, event->y, event->ctrl);
360                         break;
361                         
362                 default:
363                         if(event->type==vod->origkey && event->val==0) {
364                                 
365                                 MEM_freeN(vod);
366                                 op->customdata= NULL;
367                                 
368                                 return OPERATOR_FINISHED;
369                         }
370         }
371         
372         return OPERATOR_RUNNING_MODAL;
373 }
374
375 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
376 {
377         ViewOpsData *vod;
378         
379         /* makes op->customdata */
380         viewops_data(C, op, event);
381         vod= op->customdata;
382         
383         /* switch from camera view when: */
384         if(vod->v3d->persp != V3D_PERSP) {
385                 
386                 if (U.uiflag & USER_AUTOPERSP) 
387                         vod->v3d->persp= V3D_PERSP;
388                 else if(vod->v3d->persp==V3D_CAMOB)
389                         vod->v3d->persp= V3D_PERSP;
390                 ED_region_tag_redraw(vod->ar);
391         }
392         
393         /* add temp handler */
394         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
395         
396         return OPERATOR_RUNNING_MODAL;
397 }
398
399
400 void ED_VIEW3D_OT_viewrotate(wmOperatorType *ot)
401 {
402         
403         /* identifiers */
404         ot->name= "Rotate view";
405         ot->idname= "ED_VIEW3D_OT_viewrotate";
406         
407         /* api callbacks */
408         ot->invoke= viewrotate_invoke;
409         ot->modal= viewrotate_modal;
410         ot->poll= ED_operator_areaactive;
411 }
412
413 /* ************************ viewmove ******************************** */
414
415 static void viewmove_apply(ViewOpsData *vod, int x, int y)
416 {
417         if(vod->v3d->persp==V3D_CAMOB) {
418                 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
419                 
420                 vod->v3d->camdx += (vod->oldx - x)/(max);
421                 vod->v3d->camdy += (vod->oldy - y)/(max);
422                 CLAMP(vod->v3d->camdx, -1.0f, 1.0f);
423                 CLAMP(vod->v3d->camdy, -1.0f, 1.0f);
424 // XXX          preview3d_event= 0;
425         }
426         else {
427                 float dvec[3];
428                 
429                 window_to_3d(vod->ar, vod->v3d, dvec, x-vod->oldx, y-vod->oldy);
430                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, dvec);
431         }
432         
433         vod->oldx= x;
434         vod->oldy= y;
435         
436         ED_region_tag_redraw(vod->ar);
437 }
438
439
440 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
441 {       
442         ViewOpsData *vod= op->customdata;
443         
444         /* execute the events */
445         switch(event->type) {
446                 case MOUSEMOVE:
447                         viewmove_apply(vod, event->x, event->y);
448                         break;
449                         
450                 default:
451                         if(event->type==vod->origkey && event->val==0) {
452                                 
453                                 MEM_freeN(vod);
454                                 op->customdata= NULL;
455                                 
456                                 return OPERATOR_FINISHED;
457                         }
458         }
459         
460         return OPERATOR_RUNNING_MODAL;
461 }
462
463 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
464 {
465         /* makes op->customdata */
466         viewops_data(C, op, event);
467         
468         /* add temp handler */
469         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
470         
471         return OPERATOR_RUNNING_MODAL;
472 }
473
474
475 void ED_VIEW3D_OT_viewmove(wmOperatorType *ot)
476 {
477         
478         /* identifiers */
479         ot->name= "Rotate view";
480         ot->idname= "ED_VIEW3D_OT_viewmove";
481         
482         /* api callbacks */
483         ot->invoke= viewmove_invoke;
484         ot->modal= viewmove_modal;
485         ot->poll= ED_operator_areaactive;
486 }
487
488 /* ************************ viewzoom ******************************** */
489
490 static void view_zoom_mouseloc(ARegion *ar, View3D *v3d, float dfac, int mx, int my)
491 {
492         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
493                 float dvec[3];
494                 float tvec[3];
495                 float tpos[3];
496                 float new_dist;
497                 short vb[2], mouseloc[2];
498                 
499                 mouseloc[0]= mx - ar->winrct.xmin;
500                 mouseloc[1]= my - ar->winrct.ymin;
501                 
502                 /* find the current window width and height */
503                 vb[0] = ar->winx;
504                 vb[1] = ar->winy;
505                 
506                 tpos[0] = -v3d->ofs[0];
507                 tpos[1] = -v3d->ofs[1];
508                 tpos[2] = -v3d->ofs[2];
509                 
510                 /* Project cursor position into 3D space */
511                 initgrabz(v3d, tpos[0], tpos[1], tpos[2]);
512                 window_to_3d(ar, v3d, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
513                 
514                 /* Calculate view target position for dolly */
515                 tvec[0] = -(tpos[0] + dvec[0]);
516                 tvec[1] = -(tpos[1] + dvec[1]);
517                 tvec[2] = -(tpos[2] + dvec[2]);
518                 
519                 /* Offset to target position and dolly */
520                 new_dist = v3d->dist * dfac;
521                 
522                 VECCOPY(v3d->ofs, tvec);
523                 v3d->dist = new_dist;
524                 
525                 /* Calculate final offset */
526                 dvec[0] = tvec[0] + dvec[0] * dfac;
527                 dvec[1] = tvec[1] + dvec[1] * dfac;
528                 dvec[2] = tvec[2] + dvec[2] * dfac;
529                 
530                 VECCOPY(v3d->ofs, dvec);
531         } else {
532                 v3d->dist *= dfac;
533         }
534 }
535
536
537 static void viewzoom_apply(ViewOpsData *vod, int x, int y)
538 {
539         float zfac=1.0;
540
541         if(U.viewzoom==USER_ZOOM_CONT) {
542                 // oldstyle zoom
543                 zfac = 1.0+(float)(vod->origx - x + vod->origy - y)/1000.0;
544         }
545         else if(U.viewzoom==USER_ZOOM_SCALE) {
546                 int ctr[2], len1, len2;
547                 // method which zooms based on how far you move the mouse
548                 
549                 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
550                 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
551                 
552                 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
553                 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
554                 
555                 zfac = vod->dist0 * ((float)len2/len1) / vod->v3d->dist;
556         }
557         else {  /* USER_ZOOM_DOLLY */
558                 float len1 = (vod->ar->winrct.ymax - y) + 5;
559                 float len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
560                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->v3d->dist;
561         }
562
563         if(zfac != 1.0 && zfac*vod->v3d->dist > 0.001*vod->v3d->grid && 
564                                 zfac*vod->v3d->dist < 10.0*vod->v3d->far)
565                 view_zoom_mouseloc(vod->ar, vod->v3d, zfac, vod->oldx, vod->oldy);
566
567
568         if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->v3d->persp==V3D_PERSP)) {
569                 float upvec[3], mat[3][3];
570                 
571                 /* Secret apricot feature, translate the view when in continues mode */
572                 upvec[0] = upvec[1] = 0.0f;
573                 upvec[2] = (vod->dist0 - vod->v3d->dist) * vod->v3d->grid;
574                 vod->v3d->dist = vod->dist0;
575                 Mat3CpyMat4(mat, vod->v3d->viewinv);
576                 Mat3MulVecfl(mat, upvec);
577                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, upvec);
578         } else {
579                 /* these limits are in toets.c too */
580                 if(vod->v3d->dist<0.001*vod->v3d->grid) vod->v3d->dist= 0.001*vod->v3d->grid;
581                 if(vod->v3d->dist>10.0*vod->v3d->far) vod->v3d->dist=10.0*vod->v3d->far;
582         }
583
584 // XXX  if(vod->v3d->persp==V3D_ORTHO || vod->v3d->persp==V3D_CAMOB) preview3d_event= 0;
585         
586         ED_region_tag_redraw(vod->ar);
587 }
588
589
590 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
591 {       
592         ViewOpsData *vod= op->customdata;
593         
594         /* execute the events */
595         switch(event->type) {
596                 case MOUSEMOVE:
597                         viewzoom_apply(vod, event->x, event->y);
598                         break;
599                         
600                 default:
601                         if(event->type==vod->origkey && event->val==0) {
602                                 
603                                 MEM_freeN(vod);
604                                 op->customdata= NULL;
605                                 
606                                 return OPERATOR_FINISHED;
607                         }
608         }
609         
610         return OPERATOR_RUNNING_MODAL;
611 }
612
613 static int viewzoom_exec(bContext *C, wmOperator *op)
614 {
615         ScrArea *sa= CTX_wm_area(C);
616         View3D *v3d= sa->spacedata.first;
617         int delta= RNA_int_get(op->ptr, "delta");
618
619         if(delta < 0) {
620                 /* this min and max is also in viewmove() */
621                 if(v3d->persp==V3D_CAMOB) {
622                         v3d->camzoom-= 10;
623                         if(v3d->camzoom<-30) v3d->camzoom= -30;
624                 }
625                 else if(v3d->dist<10.0*v3d->far) v3d->dist*=1.2f;
626         }
627         else {
628                 if(v3d->persp==V3D_CAMOB) {
629                         v3d->camzoom+= 10;
630                         if(v3d->camzoom>300) v3d->camzoom= 300;
631                 }
632                 else if(v3d->dist> 0.001*v3d->grid) v3d->dist*=.83333f;
633         }
634         
635         ED_region_tag_redraw(CTX_wm_region(C));
636         
637         return OPERATOR_FINISHED;
638 }
639
640 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
641 {
642         int delta= RNA_int_get(op->ptr, "delta");
643
644         if(delta) {
645                 viewzoom_exec(C, op);
646         }
647         else {
648                 /* makes op->customdata */
649                 viewops_data(C, op, event);
650                 
651                 /* add temp handler */
652                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
653                 
654                 return OPERATOR_RUNNING_MODAL;
655         }
656         return OPERATOR_FINISHED;
657 }
658
659
660 void ED_VIEW3D_OT_viewzoom(wmOperatorType *ot)
661 {
662         
663         /* identifiers */
664         ot->name= "Rotate view";
665         ot->idname= "ED_VIEW3D_OT_viewzoom";
666         
667         /* api callbacks */
668         ot->invoke= viewzoom_invoke;
669         ot->exec= viewzoom_exec;
670         ot->modal= viewzoom_modal;
671         ot->poll= ED_operator_areaactive;
672         
673         RNA_def_property(ot->srna, "delta", PROP_INT, PROP_NONE);
674 }
675
676 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
677 {
678         ScrArea *sa= CTX_wm_area(C);
679         ARegion *ar= CTX_wm_region(C);
680         View3D *v3d= sa->spacedata.first;
681         Scene *scene= CTX_data_scene(C);
682         Base *base;
683
684         int center= RNA_boolean_get(op->ptr, "center");
685         
686         float size, min[3], max[3], afm[3];
687         int ok= 1, onedone=0;
688
689         if(center) {
690                 min[0]= min[1]= min[2]= 0.0f;
691                 max[0]= max[1]= max[2]= 0.0f;
692         }
693         else {
694                 INIT_MINMAX(min, max);
695         }
696         
697         for(base= scene->base.first; base; base= base->next) {
698                 if(base->lay & v3d->lay) {
699                         onedone= 1;
700                         minmax_object(base->object, min, max);
701                 }
702         }
703         if(!onedone) return OPERATOR_FINISHED; /* TODO - should this be cancel? */
704         
705         afm[0]= (max[0]-min[0]);
706         afm[1]= (max[1]-min[1]);
707         afm[2]= (max[2]-min[2]);
708         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
709         if(size==0.0) ok= 0;
710                 
711         if(ok) {
712                 float new_dist;
713                 float new_ofs[3];
714                 
715                 new_dist = size;
716                 new_ofs[0]= -(min[0]+max[0])/2.0f;
717                 new_ofs[1]= -(min[1]+max[1])/2.0f;
718                 new_ofs[2]= -(min[2]+max[2])/2.0f;
719                 
720                 // correction for window aspect ratio
721                 if(ar->winy>2 && ar->winx>2) {
722                         size= (float)ar->winx/(float)ar->winy;
723                         if(size<1.0) size= 1.0f/size;
724                         new_dist*= size;
725                 }
726                 
727                 if (v3d->persp==V3D_CAMOB && v3d->camera) {
728                         /* switch out of camera view */
729                         float orig_lens= v3d->lens;
730                         
731                         v3d->persp= V3D_PERSP;
732                         v3d->dist= 0.0;
733                         view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
734                         smooth_view(v3d, new_ofs, NULL, &new_dist, &orig_lens); /* TODO - this dosnt work yet */
735                         
736                 } else {
737                         if(v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP;
738                         smooth_view(v3d, new_ofs, NULL, &new_dist, NULL); /* TODO - this dosnt work yet */
739                 }
740         }
741 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
742
743         ED_region_tag_redraw(ar);
744
745         return OPERATOR_FINISHED;
746 }
747
748 void ED_VIEW3D_OT_viewhome(wmOperatorType *ot)
749 {
750
751         /* identifiers */
752         ot->name= "View home";
753         ot->idname= "ED_VIEW3D_OT_viewhome";
754
755         /* api callbacks */
756         ot->exec= viewhome_exec;
757         ot->poll= ED_operator_areaactive;
758
759         RNA_def_property(ot->srna, "center", PROP_BOOLEAN, PROP_NONE);
760 }
761
762 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
763 {       
764         ScrArea *sa= CTX_wm_area(C);
765         ARegion *ar= CTX_wm_region(C);
766         View3D *v3d= sa->spacedata.first;
767         Scene *scene= CTX_data_scene(C);
768         Object *ob= OBACT;
769         float size, min[3], max[3], afm[3];
770         int ok=0;
771
772         /* SMOOTHVIEW */
773         float new_ofs[3];
774         float new_dist;
775
776         INIT_MINMAX(min, max);
777
778         if (G.f & G_WEIGHTPAINT) {
779                 /* hardcoded exception, we look for the one selected armature */
780                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
781                 Base *base;
782                 for(base=scene->base.first; base; base= base->next) {
783                         if(TESTBASELIB(v3d, base)) {
784                                 if(base->object->type==OB_ARMATURE)
785                                         if(base->object->flag & OB_POSEMODE)
786                                                 break;
787                         }
788                 }
789                 if(base)
790                         ob= base->object;
791         }
792
793
794         if(G.obedit) {
795 // XXX          ok = minmax_verts(min, max);    /* only selected */
796         }
797         else if(ob && (ob->flag & OB_POSEMODE)) {
798                 if(ob->pose) {
799                         bArmature *arm= ob->data;
800                         bPoseChannel *pchan;
801                         float vec[3];
802
803                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
804                                 if(pchan->bone->flag & BONE_SELECTED) {
805                                         if(pchan->bone->layer & arm->layer) {
806                                                 ok= 1;
807                                                 VECCOPY(vec, pchan->pose_head);
808                                                 Mat4MulVecfl(ob->obmat, vec);
809                                                 DO_MINMAX(vec, min, max);
810                                                 VECCOPY(vec, pchan->pose_tail);
811                                                 Mat4MulVecfl(ob->obmat, vec);
812                                                 DO_MINMAX(vec, min, max);
813                                         }
814                                 }
815                         }
816                 }
817         }
818         else if (FACESEL_PAINT_TEST) {
819 // XXX          ok= minmax_tface(min, max);
820         }
821         else if (G.f & G_PARTICLEEDIT) {
822 // XXX          ok= PE_minmax(min, max);
823         }
824         else {
825                 Base *base= FIRSTBASE;
826                 while(base) {
827                         if(TESTBASE(v3d, base))  {
828                                 minmax_object(base->object, min, max);
829                                 /* account for duplis */
830                                 minmax_object_duplis(base->object, min, max);
831
832                                 ok= 1;
833                         }
834                         base= base->next;
835                 }
836         }
837
838         if(ok==0) return OPERATOR_FINISHED;
839
840         afm[0]= (max[0]-min[0]);
841         afm[1]= (max[1]-min[1]);
842         afm[2]= (max[2]-min[2]);
843         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
844
845         if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
846
847         new_ofs[0]= -(min[0]+max[0])/2.0f;
848         new_ofs[1]= -(min[1]+max[1])/2.0f;
849         new_ofs[2]= -(min[2]+max[2])/2.0f;
850
851         new_dist = size;
852
853         /* correction for window aspect ratio */
854         if(ar->winy>2 && ar->winx>2) {
855                 size= (float)ar->winx/(float)ar->winy;
856                 if(size<1.0f) size= 1.0f/size;
857                 new_dist*= size;
858         }
859
860         v3d->cursor[0]= -new_ofs[0];
861         v3d->cursor[1]= -new_ofs[1];
862         v3d->cursor[2]= -new_ofs[2];
863
864         if (v3d->persp==V3D_CAMOB && v3d->camera) {
865                 float orig_lens= v3d->lens;
866
867                 v3d->persp=V3D_PERSP;
868                 v3d->dist= 0.0f;
869                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
870                 smooth_view(v3d, new_ofs, NULL, &new_dist, &orig_lens);
871         } else {
872                 if(v3d->persp==V3D_CAMOB)
873                         v3d->persp= V3D_PERSP;
874
875                 smooth_view(v3d, new_ofs, NULL, &new_dist, NULL);
876         }
877
878 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
879
880         ED_region_tag_redraw(ar);
881
882         return OPERATOR_FINISHED;
883 }
884
885 void ED_VIEW3D_OT_viewcenter(wmOperatorType *ot)
886 {
887
888         /* identifiers */
889         ot->name= "View center";
890         ot->idname= "ED_VIEW3D_OT_viewcenter";
891
892         /* api callbacks */
893         ot->exec= viewcenter_exec;
894         ot->poll= ED_operator_areaactive;
895 }
896
897 /* ********************* set clipping operator ****************** */
898
899 static int view3d_clipping_exec(bContext *C, wmOperator *op)
900 {
901         ScrArea *sa= CTX_wm_area(C);
902         View3D *v3d= sa->spacedata.first;
903         rcti rect;
904         double mvmatrix[16];
905         double projmatrix[16];
906         double xs, ys, p[3];
907         GLint viewport[4];
908         short val;
909         
910         rect.xmin= RNA_int_get(op->ptr, "xmin");
911         rect.ymin= RNA_int_get(op->ptr, "ymin");
912         rect.xmax= RNA_int_get(op->ptr, "xmax");
913         rect.ymax= RNA_int_get(op->ptr, "ymax");
914         
915         v3d->flag |= V3D_CLIPPING;
916         v3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
917         
918         /* note; otherwise opengl won't work */
919         view3d_operator_needs_opengl(C);
920         
921         /* Get the matrices needed for gluUnProject */
922         glGetIntegerv(GL_VIEWPORT, viewport);
923         glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
924         glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
925         
926         /* near zero floating point values can give issues with gluUnProject
927                 in side view on some implementations */
928         if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
929         if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
930         
931         /* Set up viewport so that gluUnProject will give correct values */
932         viewport[0] = 0;
933         viewport[1] = 0;
934         
935         /* four clipping planes and bounding volume */
936         /* first do the bounding volume */
937         for(val=0; val<4; val++) {
938                 
939                 xs= (val==0||val==3)?rect.xmin:rect.xmax;
940                 ys= (val==0||val==1)?rect.ymin:rect.ymax;
941                 
942                 gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
943                 VECCOPY(v3d->clipbb->vec[val], p);
944                 
945                 gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
946                 VECCOPY(v3d->clipbb->vec[4+val], p);
947         }
948         
949         /* then plane equations */
950         for(val=0; val<4; val++) {
951                 
952                 CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
953                                           v3d->clip[val]); 
954                 
955                 v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0] 
956                         - v3d->clip[val][1]*v3d->clipbb->vec[val][1] 
957                         - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
958         }
959         return OPERATOR_FINISHED;
960 }
961
962 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
963 {
964         ScrArea *sa= CTX_wm_area(C);
965         View3D *v3d= sa->spacedata.first;
966         
967         if(v3d->flag & V3D_CLIPPING) {
968                 v3d->flag &= ~V3D_CLIPPING;
969                 ED_area_tag_redraw(sa);
970                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
971                 v3d->clipbb= NULL;
972                 return OPERATOR_FINISHED;
973         }
974         else {
975                 return WM_border_select_invoke(C, op, event);
976         }
977 }
978
979 /* toggles */
980 void ED_VIEW3D_OT_clipping(wmOperatorType *ot)
981 {
982         
983         /* identifiers */
984         ot->name= "Border Select";
985         ot->idname= "ED_VIEW3D_OT_clipping";
986         
987         /* api callbacks */
988         ot->invoke= view3d_clipping_invoke;
989         ot->exec= view3d_clipping_exec;
990         ot->modal= WM_border_select_modal;
991         
992         ot->poll= ED_operator_areaactive;
993         
994         /* rna */
995         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
996         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
997         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
998         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
999 }
1000
1001 /* ********************************************************* */
1002
1003 void set_render_border(Scene *scene, ARegion *ar, View3D *v3d)
1004 {
1005         rcti rect;
1006         short val;
1007         
1008         val= 0; // XXX get_border(&rect, 3);
1009         if(val) {
1010                 rctf vb;
1011                 
1012                 calc_viewborder(scene, ar, v3d, &vb);
1013                 
1014                 scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1015                 scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1016                 scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1017                 scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1018                 
1019                 CLAMP(scene->r.border.xmin, 0.0, 1.0);
1020                 CLAMP(scene->r.border.ymin, 0.0, 1.0);
1021                 CLAMP(scene->r.border.xmax, 0.0, 1.0);
1022                 CLAMP(scene->r.border.ymax, 0.0, 1.0);
1023                 
1024                 /* drawing a border surrounding the entire camera view switches off border rendering
1025                         * or the border covers no pixels */
1026                 if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1027                          scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1028                         (scene->r.border.xmin == scene->r.border.xmax ||
1029                          scene->r.border.ymin == scene->r.border.ymax ))
1030                 {
1031                         scene->r.mode &= ~R_BORDER;
1032                 } else {
1033                         scene->r.mode |= R_BORDER;
1034                 }
1035         }
1036 }
1037
1038 void view3d_border_zoom(Scene *scene, ARegion *ar, View3D *v3d)
1039 {
1040         
1041         /* Zooms in on a border drawn by the user */
1042         rcti rect;
1043         short val;
1044         float dvec[3], vb[2], xscale, yscale, scale;
1045         
1046         
1047         /* SMOOTHVIEW */
1048         float new_dist;
1049         float new_ofs[3];
1050         
1051         /* ZBuffer depth vars */
1052         bglMats mats;
1053         float depth, depth_close= MAXFLOAT;
1054         int had_depth = 0;
1055         double cent[2],  p[3];
1056         int xs, ys;
1057         
1058         /* Get the border input */
1059         val = 0; // XXX get_border(&rect, 3);
1060         if(!val) return;
1061         
1062         /* Get Z Depths, needed for perspective, nice for ortho */
1063         bgl_get_mats(&mats);
1064         draw_depth(scene, ar, v3d, NULL);
1065         
1066         /* force updating */
1067         if (v3d->depths) {
1068                 had_depth = 1;
1069                 v3d->depths->damaged = 1;
1070         }
1071         
1072         view3d_update_depths(ar, v3d);
1073         
1074         /* Constrain rect to depth bounds */
1075         if (rect.xmin < 0) rect.xmin = 0;
1076         if (rect.ymin < 0) rect.ymin = 0;
1077         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1078         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;          
1079         
1080         /* Find the closest Z pixel */
1081         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1082                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1083                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1084                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1085                                 if (depth_close > depth) {
1086                                         depth_close = depth;
1087                                 }
1088                         }
1089                 }
1090         }
1091         
1092         if (had_depth==0) {
1093                 MEM_freeN(v3d->depths->depths);
1094                 v3d->depths->depths = NULL;
1095         }
1096         v3d->depths->damaged = 1;
1097         
1098         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1099         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1100         
1101         if (v3d->persp==V3D_PERSP) {
1102                 double p_corner[3];
1103                 
1104                 /* no depths to use, we cant do anything! */
1105                 if (depth_close==MAXFLOAT) 
1106                         return;
1107                 
1108                 /* convert border to 3d coordinates */
1109                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) || 
1110                         (       !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])))
1111                         return;
1112                 
1113                 dvec[0] = p[0]-p_corner[0];
1114                 dvec[1] = p[1]-p_corner[1];
1115                 dvec[2] = p[2]-p_corner[2];
1116                 
1117                 new_dist = VecLength(dvec);
1118                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5; 
1119                 
1120                 new_ofs[0] = -p[0];
1121                 new_ofs[1] = -p[1];
1122                 new_ofs[2] = -p[2];
1123                 
1124         } else { /* othographic */
1125                 /* find the current window width and height */
1126                 vb[0] = ar->winx;
1127                 vb[1] = ar->winy;
1128                 
1129                 new_dist = v3d->dist;
1130                 
1131                 /* convert the drawn rectangle into 3d space */
1132                 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1133                         new_ofs[0] = -p[0];
1134                         new_ofs[1] = -p[1];
1135                         new_ofs[2] = -p[2];
1136                 } else {
1137                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1138                         new_ofs[0] = v3d->ofs[0];
1139                         new_ofs[1] = v3d->ofs[1];
1140                         new_ofs[2] = v3d->ofs[2];
1141                         
1142                         initgrabz(v3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1143                         
1144                         window_to_3d(ar, v3d, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1145                         /* center the view to the center of the rectangle */
1146                         VecSubf(new_ofs, new_ofs, dvec);
1147                 }
1148                 
1149                 /* work out the ratios, so that everything selected fits when we zoom */
1150                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1151                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1152                 scale = (xscale >= yscale)?xscale:yscale;
1153                 
1154                 /* zoom in as required, or as far as we can go */
1155                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1156         }
1157         
1158         smooth_view(v3d, new_ofs, NULL, &new_dist, NULL);
1159 }
1160
1161
1162
1163 /* ************************* below the line! *********************** */
1164
1165
1166 /* XXX todo Zooms in on a border drawn by the user */
1167 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
1168 {
1169         rcti rect;
1170         /* ZBuffer depth vars */
1171         bglMats mats;
1172         float depth, depth_close= MAXFLOAT;
1173         int had_depth = 0;
1174         double cent[2],  p[3];
1175         int xs, ys;
1176         
1177         // XXX          getmouseco_areawin(mval);
1178         
1179         // XXX  persp(PERSP_VIEW);
1180         
1181         rect.xmax = mval[0] + 4;
1182         rect.ymax = mval[1] + 4;
1183         
1184         rect.xmin = mval[0] - 4;
1185         rect.ymin = mval[1] - 4;
1186         
1187         /* Get Z Depths, needed for perspective, nice for ortho */
1188         bgl_get_mats(&mats);
1189         draw_depth(scene, ar, v3d, NULL);
1190         
1191         /* force updating */
1192         if (v3d->depths) {
1193                 had_depth = 1;
1194                 v3d->depths->damaged = 1;
1195         }
1196         
1197         view3d_update_depths(ar, v3d);
1198         
1199         /* Constrain rect to depth bounds */
1200         if (rect.xmin < 0) rect.xmin = 0;
1201         if (rect.ymin < 0) rect.ymin = 0;
1202         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1203         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;          
1204         
1205         /* Find the closest Z pixel */
1206         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1207                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1208                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1209                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1210                                 if (depth_close > depth) {
1211                                         depth_close = depth;
1212                                 }
1213                         }
1214                 }
1215         }
1216         
1217         if (depth_close==MAXFLOAT)
1218                 return 0;
1219         
1220         if (had_depth==0) {
1221                 MEM_freeN(v3d->depths->depths);
1222                 v3d->depths->depths = NULL;
1223         }
1224         v3d->depths->damaged = 1;
1225         
1226         cent[0] = (double)mval[0];
1227         cent[1] = (double)mval[1];
1228         
1229         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
1230                 return 0;
1231         
1232         mouse_worldloc[0] = (float)p[0];
1233         mouse_worldloc[1] = (float)p[1];
1234         mouse_worldloc[2] = (float)p[2];
1235         return 1;
1236 }
1237
1238
1239
1240 /* ********************* NDOF ************************ */
1241 /* note: this code is confusing and unclear... (ton) */
1242 /* **************************************************** */
1243
1244 // ndof scaling will be moved to user setting.
1245 // In the mean time this is just a place holder.
1246
1247 // Note: scaling in the plugin and ghostwinlay.c
1248 // should be removed. With driver default setting,
1249 // each axis returns approx. +-200 max deflection.
1250
1251 // The values I selected are based on the older
1252 // polling i/f. With event i/f, the sensistivity
1253 // can be increased for improved response from
1254 // small deflections of the device input.
1255
1256
1257 // lukep notes : i disagree on the range.
1258 // the normal 3Dconnection driver give +/-400
1259 // on defaut range in other applications
1260 // and up to +/- 1000 if set to maximum
1261 // because i remove the scaling by delta,
1262 // which was a bad idea as it depend of the system
1263 // speed and os, i changed the scaling values, but 
1264 // those are still not ok
1265
1266
1267 float ndof_axis_scale[6] = {
1268         +0.01,  // Tx
1269         +0.01,  // Tz
1270         +0.01,  // Ty
1271         +0.0015,        // Rx
1272         +0.0015,        // Rz
1273         +0.0015 // Ry
1274 };
1275
1276 void filterNDOFvalues(float *sbval)
1277 {
1278         int i=0;
1279         float max  = 0.0;
1280         
1281         for (i =0; i<6;i++)
1282                 if (fabs(sbval[i]) > max)
1283                         max = fabs(sbval[i]);
1284         for (i =0; i<6;i++)
1285                 if (fabs(sbval[i]) != max )
1286                         sbval[i]=0.0;
1287 }
1288
1289 // statics for controlling v3d->dist corrections.
1290 // viewmoveNDOF zeros and adjusts v3d->ofs.
1291 // viewmove restores based on dz_flag state.
1292
1293 int dz_flag = 0;
1294 float m_dist;
1295
1296 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
1297 {
1298     int i;
1299     float phi;
1300     float dval[7];
1301         // static fval[6] for low pass filter; device input vector is dval[6]
1302         static float fval[6];
1303     float tvec[3],rvec[3];
1304     float q1[4];
1305         float mat[3][3];
1306         float upvec[3];
1307
1308
1309     /*----------------------------------------------------
1310          * sometimes this routine is called from headerbuttons
1311      * viewmove needs to refresh the screen
1312      */
1313 // XXX  areawinset(ar->win);
1314
1315
1316         // fetch the current state of the ndof device
1317 // XXX  getndof(dval);
1318
1319         if (v3d->ndoffilter)
1320                 filterNDOFvalues(fval);
1321
1322         // Scale input values
1323
1324 //      if(dval[6] == 0) return; // guard against divide by zero
1325
1326         for(i=0;i<6;i++) {
1327
1328                 // user scaling
1329                 dval[i] = dval[i] * ndof_axis_scale[i];
1330         }
1331
1332
1333         // low pass filter with zero crossing reset
1334
1335         for(i=0;i<6;i++) {
1336                 if((dval[i] * fval[i]) >= 0)
1337                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
1338                 else
1339                         fval[i] = 0;
1340         }
1341
1342
1343         // force perspective mode. This is a hack and is
1344         // incomplete. It doesn't actually effect the view
1345         // until the first draw and doesn't update the menu
1346         // to reflect persp mode.
1347
1348         v3d->persp = V3D_PERSP;
1349
1350
1351         // Correct the distance jump if v3d->dist != 0
1352
1353         // This is due to a side effect of the original
1354         // mouse view rotation code. The rotation point is
1355         // set a distance in front of the viewport to
1356         // make rotating with the mouse look better.
1357         // The distance effect is written at a low level
1358         // in the view management instead of the mouse
1359         // view function. This means that all other view
1360         // movement devices must subtract this from their
1361         // view transformations.
1362
1363         if(v3d->dist != 0.0) {
1364                 dz_flag = 1;
1365                 m_dist = v3d->dist;
1366                 upvec[0] = upvec[1] = 0;
1367                 upvec[2] = v3d->dist;
1368                 Mat3CpyMat4(mat, v3d->viewinv);
1369                 Mat3MulVecfl(mat, upvec);
1370                 VecSubf(v3d->ofs, v3d->ofs, upvec);
1371                 v3d->dist = 0.0;
1372         }
1373
1374
1375         // Apply rotation
1376         // Rotations feel relatively faster than translations only in fly mode, so
1377         // we have no choice but to fix that here (not in the plugins)
1378         rvec[0] = -0.5 * dval[3];
1379         rvec[1] = -0.5 * dval[4];
1380         rvec[2] = -0.5 * dval[5];
1381
1382         // rotate device x and y by view z
1383
1384         Mat3CpyMat4(mat, v3d->viewinv);
1385         mat[2][2] = 0.0f;
1386         Mat3MulVecfl(mat, rvec);
1387
1388         // rotate the view
1389
1390         phi = Normalize(rvec);
1391         if(phi != 0) {
1392                 VecRotToQuat(rvec,phi,q1);
1393                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
1394         }
1395
1396
1397         // Apply translation
1398
1399         tvec[0] = dval[0];
1400         tvec[1] = dval[1];
1401         tvec[2] = -dval[2];
1402
1403         // the next three lines rotate the x and y translation coordinates
1404         // by the current z axis angle
1405
1406         Mat3CpyMat4(mat, v3d->viewinv);
1407         mat[2][2] = 0.0f;
1408         Mat3MulVecfl(mat, tvec);
1409
1410         // translate the view
1411
1412         VecSubf(v3d->ofs, v3d->ofs, tvec);
1413
1414
1415         /*----------------------------------------------------
1416      * refresh the screen XXX
1417       */
1418
1419         // update render preview window
1420
1421 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
1422 }
1423
1424 void viewmoveNDOF(Scene *scene, View3D *v3d, int mode)
1425 {
1426     float fval[7];
1427     float dvec[3];
1428     float sbadjust = 1.0f;
1429     float len;
1430         short use_sel = 0;
1431         Object *ob = OBACT;
1432     float m[3][3];
1433     float m_inv[3][3];
1434     float xvec[3] = {1,0,0};
1435     float yvec[3] = {0,-1,0};
1436     float zvec[3] = {0,0,1};
1437         float phi, si;
1438     float q1[4];
1439     float obofs[3];
1440     float reverse;
1441     //float diff[4];
1442     float d, curareaX, curareaY;
1443     float mat[3][3];
1444     float upvec[3];
1445
1446     /* Sensitivity will control how fast the view rotates.  The value was
1447      * obtained experimentally by tweaking until the author didn't get dizzy watching.
1448      * Perhaps this should be a configurable user parameter. 
1449      */
1450     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
1451     float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
1452     float zsens = 0.3f;   /* zoom sensitivity */
1453
1454     const float minZoom = -30.0f;
1455     const float maxZoom = 300.0f;
1456
1457         //reset view type
1458         v3d->view = 0;
1459 //printf("passing here \n");
1460 //
1461         if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1462                 use_sel = 1;
1463         }
1464
1465     if((dz_flag)||v3d->dist==0) {
1466                 dz_flag = 0;
1467                 v3d->dist = m_dist;
1468                 upvec[0] = upvec[1] = 0;
1469                 upvec[2] = v3d->dist;
1470                 Mat3CpyMat4(mat, v3d->viewinv);
1471                 Mat3MulVecfl(mat, upvec);
1472                 VecAddf(v3d->ofs, v3d->ofs, upvec);
1473         }
1474
1475     /*----------------------------------------------------
1476          * sometimes this routine is called from headerbuttons
1477      * viewmove needs to refresh the screen
1478      */
1479 // XXX  areawinset(curarea->win);
1480
1481     /*----------------------------------------------------
1482      * record how much time has passed. clamp at 10 Hz
1483      * pretend the previous frame occured at the clamped time 
1484      */
1485 //    now = PIL_check_seconds_timer();
1486  //   frametime = (now - prevTime);
1487  //   if (frametime > 0.1f){        /* if more than 1/10s */
1488  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
1489 //    }
1490 //    prevTime = now;
1491  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
1492
1493     /* fetch the current state of the ndof device & enforce dominant mode if selected */
1494 // XXX    getndof(fval);
1495         if (v3d->ndoffilter)
1496                 filterNDOFvalues(fval);
1497         
1498         
1499     // put scaling back here, was previously in ghostwinlay
1500     fval[0] = fval[0] * (1.0f/600.0f);
1501     fval[1] = fval[1] * (1.0f/600.0f);
1502     fval[2] = fval[2] * (1.0f/1100.0f);
1503     fval[3] = fval[3] * 0.00005f;
1504     fval[4] =-fval[4] * 0.00005f;
1505     fval[5] = fval[5] * 0.00005f;
1506     fval[6] = fval[6] / 1000000.0f;
1507                         
1508     // scale more if not in perspective mode
1509     if (v3d->persp == V3D_ORTHO) {
1510         fval[0] = fval[0] * 0.05f;
1511         fval[1] = fval[1] * 0.05f;
1512         fval[2] = fval[2] * 0.05f;
1513         fval[3] = fval[3] * 0.9f;
1514         fval[4] = fval[4] * 0.9f;
1515         fval[5] = fval[5] * 0.9f;
1516         zsens *= 8;
1517     }
1518                         
1519         
1520     /* set object offset */
1521         if (ob) {
1522                 obofs[0] = -ob->obmat[3][0];
1523                 obofs[1] = -ob->obmat[3][1];
1524                 obofs[2] = -ob->obmat[3][2];
1525         }
1526         else {
1527                 VECCOPY(obofs, v3d->ofs);
1528         }
1529
1530     /* calc an adjustment based on distance from camera
1531        disabled per patch 14402 */
1532      d = 1.0f;
1533
1534 /*    if (ob) {
1535         VecSubf(diff, obofs, v3d->ofs);
1536         d = VecLength(diff);
1537     }
1538 */
1539
1540     reverse = (v3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1541
1542     /*----------------------------------------------------
1543      * ndof device pan 
1544      */
1545     psens *= 1.0f + d;
1546     curareaX = sbadjust * psens * fval[0];
1547     curareaY = sbadjust * psens * fval[1];
1548     dvec[0] = curareaX * v3d->persinv[0][0] + curareaY * v3d->persinv[1][0];
1549     dvec[1] = curareaX * v3d->persinv[0][1] + curareaY * v3d->persinv[1][1];
1550     dvec[2] = curareaX * v3d->persinv[0][2] + curareaY * v3d->persinv[1][2];
1551     VecAddf(v3d->ofs, v3d->ofs, dvec);
1552
1553     /*----------------------------------------------------
1554      * ndof device dolly 
1555      */
1556     len = zsens * sbadjust * fval[2];
1557
1558     if (v3d->persp==V3D_CAMOB) {
1559         if(v3d->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1560             v3d->camzoom+= 10.0f * -len;
1561         }
1562         if (v3d->camzoom < minZoom) v3d->camzoom = minZoom;
1563         else if (v3d->camzoom > maxZoom) v3d->camzoom = maxZoom;
1564     }
1565     else if ((v3d->dist> 0.001*v3d->grid) && (v3d->dist<10.0*v3d->far)) {
1566         v3d->dist*=(1.0 + len);
1567     }
1568
1569
1570     /*----------------------------------------------------
1571      * ndof device turntable
1572      * derived from the turntable code in viewmove
1573      */
1574
1575     /* Get the 3x3 matrix and its inverse from the quaternion */
1576     QuatToMat3(v3d->viewquat, m);
1577     Mat3Inv(m_inv,m);
1578
1579     /* Determine the direction of the x vector (for rotating up and down) */
1580     /* This can likely be compuated directly from the quaternion. */
1581     Mat3MulVecfl(m_inv,xvec);
1582     Mat3MulVecfl(m_inv,yvec);
1583     Mat3MulVecfl(m_inv,zvec);
1584
1585     /* Perform the up/down rotation */
1586     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1587     si = sin(phi);
1588     q1[0] = cos(phi);
1589     q1[1] = si * xvec[0];
1590     q1[2] = si * xvec[1];
1591     q1[3] = si * xvec[2];
1592     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1593
1594     if (use_sel) {
1595         QuatConj(q1); /* conj == inv for unit quat */
1596         VecSubf(v3d->ofs, v3d->ofs, obofs);
1597         QuatMulVecf(q1, v3d->ofs);
1598         VecAddf(v3d->ofs, v3d->ofs, obofs);
1599     }
1600
1601     /* Perform the orbital rotation */
1602     /* Perform the orbital rotation 
1603        If the seen Up axis is parallel to the zoom axis, rotation should be
1604        achieved with a pure Roll motion (no Spin) on the device. When you start 
1605        to tilt, moving from Top to Side view, Spinning will increasingly become 
1606        more relevant while the Roll component will decrease. When a full 
1607        Side view is reached, rotations around the world's Up axis are achieved
1608        with a pure Spin-only motion.  In other words the control of the spinning
1609        around the world's Up axis should move from the device's Spin axis to the
1610        device's Roll axis depending on the orientation of the world's Up axis 
1611        relative to the screen. */
1612     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
1613     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
1614     q1[0] = cos(phi);
1615     q1[1] = q1[2] = 0.0;
1616     q1[3] = sin(phi);
1617     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1618
1619     if (use_sel) {
1620         QuatConj(q1);
1621         VecSubf(v3d->ofs, v3d->ofs, obofs);
1622         QuatMulVecf(q1, v3d->ofs);
1623         VecAddf(v3d->ofs, v3d->ofs, obofs);
1624     }
1625
1626     /*----------------------------------------------------
1627      * refresh the screen
1628      */
1629 // XXX    scrarea_do_windraw(curarea);
1630 }
1631
1632
1633
1634