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_camera_types.h"
36 #include "DNA_lamp_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_space_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_screen_types.h"
41 #include "DNA_userdef_types.h"
42 #include "DNA_view3d_types.h"
43 #include "DNA_world_types.h"
44
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_arithb.h"
49 #include "BLI_rand.h"
50
51 #include "BKE_action.h"
52 #include "BKE_context.h"
53 #include "BKE_object.h"
54 #include "BKE_global.h"
55 #include "BKE_scene.h"
56 #include "BKE_screen.h"
57 #include "BKE_utildefines.h"
58
59 #include "RE_pipeline.h"        // make_stars
60
61 #include "BIF_gl.h"
62 #include "BIF_retopo.h"
63
64 #include "WM_api.h"
65 #include "WM_types.h"
66
67 #include "ED_screen.h"
68 #include "ED_types.h"
69
70 #include "UI_interface.h"
71 #include "UI_resources.h"
72 #include "UI_view2d.h"
73
74 #include "PIL_time.h" /* smoothview */
75
76 #include "view3d_intern.h"      // own include
77
78 /* ********************** view3d_edit: view manipulations ********************* */
79
80 /* ************************** init for view ops **********************************/
81
82 typedef struct ViewOpsData {
83         ARegion *ar;
84         View3D *v3d;
85         
86         float oldquat[4];
87         float trackvec[3];
88         float ofs[3], obofs[3];
89         float reverse, dist0;
90         
91         int origx, origy, oldx, oldy;
92         
93 } ViewOpsData;
94
95 #define TRACKBALLSIZE  (1.1)
96
97 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
98 {
99         float x, y, radius, d, z, t;
100         
101         radius= TRACKBALLSIZE;
102         
103         /* normalize x and y */
104         x= (rect->xmax + rect->xmin)/2 - mx;
105         x/= (float)((rect->xmax - rect->xmin)/4);
106         y= (rect->ymax + rect->ymin)/2 - my;
107         y/= (float)((rect->ymax - rect->ymin)/2);
108         
109         d = sqrt(x*x + y*y);
110         if (d < radius*M_SQRT1_2)       /* Inside sphere */
111                 z = sqrt(radius*radius - d*d);
112         else
113         {                       /* On hyperbola */
114                 t = radius / M_SQRT2;
115                 z = t*t / d;
116         }
117
118         vec[0]= x;
119         vec[1]= y;
120         vec[2]= -z;             /* yah yah! */
121 }
122
123
124 static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
125 {
126         ScrArea *sa= CTX_wm_area(C);
127         View3D *v3d= sa->spacedata.first;
128         ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
129         
130         /* store data */
131         op->customdata= vod;
132         vod->ar= CTX_wm_region(C);
133         vod->v3d= v3d;
134         vod->dist0= v3d->dist;
135         QUATCOPY(vod->oldquat, v3d->viewquat);
136         vod->origx= vod->oldx= event->x;
137         vod->origy= vod->oldy= event->y;
138         
139         calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
140         
141         initgrabz(v3d, -v3d->ofs[0], -v3d->ofs[1], -v3d->ofs[2]);
142         
143         vod->reverse= 1.0f;
144         if (v3d->persmat[2][1] < 0.0f)
145                 vod->reverse= -1.0f;
146         
147 }       
148
149 /* ************************** viewrotate **********************************/
150
151 static const float thres = 0.93f; //cos(20 deg);
152
153 #define COS45 0.70710678118654746
154 #define SIN45 COS45
155
156 static float snapquats[39][6] = {
157         /*{q0, q1, q3, q4, view, oposite_direction}*/
158 {COS45, -SIN45, 0.0, 0.0, 1, 0},  //front
159 {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back
160 {1.0, 0.0, 0.0, 0.0, 7, 0},       //top
161 {0.0, -1.0, 0.0, 0.0, 7, 1},      //bottom
162 {0.5, -0.5, -0.5, -0.5, 3, 0},    //left
163 {0.5, -0.5, 0.5, 0.5, 3, 1},      //right
164         
165         /* some more 45 deg snaps */
166 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
167 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
168 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
169 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
170 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
171 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
172 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
173 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
174 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
175 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
176 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
177 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
178 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
179 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
180 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
181 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
182 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
183 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
184 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
185 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
186 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
187 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
188 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
189 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
190 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
191 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
192 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
193 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
194 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
195 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
196 {-COS45, 0.0, 0.0, SIN45, 0, 0},
197 {COS45, 0.0, 0.0, SIN45, 0, 0},
198 {0.0, 0.0, 0.0, 1.0, 0, 0}
199 };
200
201
202 static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl)
203 {
204         View3D *v3d= vod->v3d;
205         int use_sel= 0; /* XXX */
206         
207         v3d->view= 0; /* need to reset everytime because of view snapping */
208         
209         if (U.flag & USER_TRACKBALL) {
210                 float phi, si, q1[4], dvec[3], newvec[3];
211                 
212                 calctrackballvec(&vod->ar->winrct, x, y, newvec);
213         
214                 VecSubf(dvec, newvec, vod->trackvec);
215         
216                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
217                 si/= (2.0*TRACKBALLSIZE);
218         
219                 Crossf(q1+1, vod->trackvec, newvec);
220                 Normalize(q1+1);
221                 
222                 /* Allow for rotation beyond the interval
223                         * [-pi, pi] */
224                 while (si > 1.0)
225                         si -= 2.0;
226                 
227                 /* This relation is used instead of
228                         * phi = asin(si) so that the angle
229                         * of rotation is linearly proportional
230                         * to the distance that the mouse is
231                         * dragged. */
232                 phi = si * M_PI / 2.0;
233                 
234                 si= sin(phi);
235                 q1[0]= cos(phi);
236                 q1[1]*= si;
237                 q1[2]*= si;
238                 q1[3]*= si;     
239                 QuatMul(v3d->viewquat, q1, vod->oldquat);
240                 
241                 if (use_sel) {
242                         /* compute the post multiplication quat, to rotate the offset correctly */
243                         QUATCOPY(q1, vod->oldquat);
244                         QuatConj(q1);
245                         QuatMul(q1, q1, v3d->viewquat);
246                         
247                         QuatConj(q1); /* conj == inv for unit quat */
248                         VECCOPY(v3d->ofs, vod->ofs);
249                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
250                         QuatMulVecf(q1, v3d->ofs);
251                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
252                 }
253         } 
254         else {
255                 /* New turntable view code by John Aughey */
256                 float si, phi, q1[4];
257                 float m[3][3];
258                 float m_inv[3][3];
259                 float xvec[3] = {1,0,0};
260                 /* Sensitivity will control how fast the viewport rotates.  0.0035 was
261                         obtained experimentally by looking at viewport rotation sensitivities
262                         on other modeling programs. */
263                 /* Perhaps this should be a configurable user parameter. */
264                 const float sensitivity = 0.0035;
265                 
266                 /* Get the 3x3 matrix and its inverse from the quaternion */
267                 QuatToMat3(v3d->viewquat, m);
268                 Mat3Inv(m_inv,m);
269                 
270                 /* Determine the direction of the x vector (for rotating up and down) */
271                 /* This can likely be compuated directly from the quaternion. */
272                 Mat3MulVecfl(m_inv,xvec);
273                 
274                 /* Perform the up/down rotation */
275                 phi = sensitivity * -(y - vod->oldy);
276                 si = sin(phi);
277                 q1[0] = cos(phi);
278                 q1[1] = si * xvec[0];
279                 q1[2] = si * xvec[1];
280                 q1[3] = si * xvec[2];
281                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
282                 
283                 if (use_sel) {
284                         QuatConj(q1); /* conj == inv for unit quat */
285                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
286                         QuatMulVecf(q1, v3d->ofs);
287                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
288                 }
289                 
290                 /* Perform the orbital rotation */
291                 phi = sensitivity * vod->reverse * (x - vod->oldx);
292                 q1[0] = cos(phi);
293                 q1[1] = q1[2] = 0.0;
294                 q1[3] = sin(phi);
295                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
296                 
297                 if (use_sel) {
298                         QuatConj(q1);
299                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
300                         QuatMulVecf(q1, v3d->ofs);
301                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
302                 }
303         }
304         
305         /* check for view snap */
306         if (ctrl){
307                 int i;
308                 float viewmat[3][3];
309                 
310                 
311                 QuatToMat3(v3d->viewquat, viewmat);
312                 
313                 for (i = 0 ; i < 39; i++){
314                         float snapmat[3][3];
315                         float view = (int)snapquats[i][4];
316                         float oposite_dir = (int)snapquats[i][5];
317                         
318                         QuatToMat3(snapquats[i], snapmat);
319                         
320                         if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
321                                 (Inpf(snapmat[1], viewmat[1]) > thres) &&
322                                 (Inpf(snapmat[2], viewmat[2]) > thres)){
323                                 
324                                 QUATCOPY(v3d->viewquat, snapquats[i]);
325                                 
326                                 v3d->view = view;
327                                 if (view){
328                                         if (oposite_dir){
329                                                 v3d->flag2 |= V3D_OPP_DIRECTION_NAME;
330                                         }else{
331                                                 v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME;
332                                         }
333                                 }
334                                 
335                                 break;
336                         }
337                 }
338         }
339         vod->oldx= x;
340         vod->oldy= y;
341
342         ED_region_tag_redraw(vod->ar);
343 }
344
345 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
346 {
347
348         /* execute the events */
349         switch(event->type) {
350                 case MOUSEMOVE:
351                         viewrotate_apply(op->customdata, event->x, event->y, event->ctrl);
352                         break;
353                         
354                 case MIDDLEMOUSE:
355                         if(event->val==0) {
356                                 
357                                 MEM_freeN(op->customdata);
358                                 op->customdata= NULL;
359                                 
360                                 return OPERATOR_FINISHED;
361                         }
362                         break;
363         }
364         
365         return OPERATOR_RUNNING_MODAL;
366 }
367
368 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
369 {
370         ViewOpsData *vod;
371         
372         /* makes op->customdata */
373         viewops_data(C, op, event);
374         vod= op->customdata;
375         
376         /* switch from camera view when: */
377         if(vod->v3d->persp != V3D_PERSP) {
378                 
379                 if (U.uiflag & USER_AUTOPERSP) 
380                         vod->v3d->persp= V3D_PERSP;
381                 else if(vod->v3d->persp==V3D_CAMOB)
382                         vod->v3d->persp= V3D_PERSP;
383                 ED_region_tag_redraw(vod->ar);
384         }
385         
386         /* add temp handler */
387         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
388         
389         return OPERATOR_RUNNING_MODAL;
390 }
391
392
393 void ED_VIEW3D_OT_viewrotate(wmOperatorType *ot)
394 {
395         
396         /* identifiers */
397         ot->name= "Rotate view";
398         ot->idname= "ED_VIEW3D_OT_viewrotate";
399         
400         /* api callbacks */
401         ot->invoke= viewrotate_invoke;
402         ot->modal= viewrotate_modal;
403 }
404
405 /* ************************ viewmove ******************************** */
406
407 static void viewmove_apply(ViewOpsData *vod, int x, int y)
408 {
409         if(vod->v3d->persp==V3D_CAMOB) {
410                 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
411                 
412                 vod->v3d->camdx += (vod->oldx - x)/(max);
413                 vod->v3d->camdy += (vod->oldy - y)/(max);
414                 CLAMP(vod->v3d->camdx, -1.0f, 1.0f);
415                 CLAMP(vod->v3d->camdy, -1.0f, 1.0f);
416 // XXX          preview3d_event= 0;
417         }
418         else {
419                 float dvec[3];
420                 
421                 window_to_3d(vod->ar, vod->v3d, dvec, x-vod->oldx, y-vod->oldy);
422                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, dvec);
423         }
424         
425         vod->oldx= x;
426         vod->oldy= y;
427         
428         ED_region_tag_redraw(vod->ar);
429 }
430
431
432 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
433 {       
434         /* execute the events */
435         switch(event->type) {
436                 case MOUSEMOVE:
437                         viewmove_apply(op->customdata, event->x, event->y);
438                         break;
439                         
440                 case MIDDLEMOUSE:
441                         if(event->val==0) {
442                                 
443                                 MEM_freeN(op->customdata);
444                                 op->customdata= NULL;
445                                 
446                                 return OPERATOR_FINISHED;
447                         }
448                         break;
449         }
450         
451         return OPERATOR_RUNNING_MODAL;
452 }
453
454 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
455 {
456         /* makes op->customdata */
457         viewops_data(C, op, event);
458         
459         /* add temp handler */
460         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
461         
462         return OPERATOR_RUNNING_MODAL;
463 }
464
465
466 void ED_VIEW3D_OT_viewmove(wmOperatorType *ot)
467 {
468         
469         /* identifiers */
470         ot->name= "Rotate view";
471         ot->idname= "ED_VIEW3D_OT_viewmove";
472         
473         /* api callbacks */
474         ot->invoke= viewmove_invoke;
475         ot->modal= viewmove_modal;
476 }
477
478 /* ************************ viewzoom ******************************** */
479
480 static void view_zoom_mouseloc(ARegion *ar, View3D *v3d, float dfac, int mx, int my)
481 {
482         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
483                 float dvec[3];
484                 float tvec[3];
485                 float tpos[3];
486                 float new_dist;
487                 short vb[2], mouseloc[2];
488                 
489                 mouseloc[0]= mx - ar->winrct.xmin;
490                 mouseloc[1]= my - ar->winrct.ymin;
491                 
492                 /* find the current window width and height */
493                 vb[0] = ar->winx;
494                 vb[1] = ar->winy;
495                 
496                 tpos[0] = -v3d->ofs[0];
497                 tpos[1] = -v3d->ofs[1];
498                 tpos[2] = -v3d->ofs[2];
499                 
500                 /* Project cursor position into 3D space */
501                 initgrabz(v3d, tpos[0], tpos[1], tpos[2]);
502                 window_to_3d(ar, v3d, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
503                 
504                 /* Calculate view target position for dolly */
505                 tvec[0] = -(tpos[0] + dvec[0]);
506                 tvec[1] = -(tpos[1] + dvec[1]);
507                 tvec[2] = -(tpos[2] + dvec[2]);
508                 
509                 /* Offset to target position and dolly */
510                 new_dist = v3d->dist * dfac;
511                 
512                 VECCOPY(v3d->ofs, tvec);
513                 v3d->dist = new_dist;
514                 
515                 /* Calculate final offset */
516                 dvec[0] = tvec[0] + dvec[0] * dfac;
517                 dvec[1] = tvec[1] + dvec[1] * dfac;
518                 dvec[2] = tvec[2] + dvec[2] * dfac;
519                 
520                 VECCOPY(v3d->ofs, dvec);
521         } else {
522                 v3d->dist *= dfac;
523         }
524 }
525
526
527 static void viewzoom_apply(ViewOpsData *vod, int x, int y)
528 {
529         float zfac=1.0;
530
531         if(U.viewzoom==USER_ZOOM_CONT) {
532                 // oldstyle zoom
533                 zfac = 1.0+(float)(vod->origx - x + vod->origy - y)/1000.0;
534         }
535         else if(U.viewzoom==USER_ZOOM_SCALE) {
536                 int ctr[2], len1, len2;
537                 // method which zooms based on how far you move the mouse
538                 
539                 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
540                 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
541                 
542                 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
543                 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
544                 
545                 zfac = vod->dist0 * ((float)len2/len1) / vod->v3d->dist;
546         }
547         else {  /* USER_ZOOM_DOLLY */
548                 float len1 = (vod->ar->winrct.ymax - y) + 5;
549                 float len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
550                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->v3d->dist;
551         }
552
553         if(zfac != 1.0 && zfac*vod->v3d->dist > 0.001*vod->v3d->grid && 
554                                 zfac*vod->v3d->dist < 10.0*vod->v3d->far)
555                 view_zoom_mouseloc(vod->ar, vod->v3d, zfac, vod->oldx, vod->oldy);
556
557
558         if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->v3d->persp==V3D_PERSP)) {
559                 float upvec[3], mat[3][3];
560                 
561                 /* Secret apricot feature, translate the view when in continues mode */
562                 upvec[0] = upvec[1] = 0.0f;
563                 upvec[2] = (vod->dist0 - vod->v3d->dist) * vod->v3d->grid;
564                 vod->v3d->dist = vod->dist0;
565                 Mat3CpyMat4(mat, vod->v3d->viewinv);
566                 Mat3MulVecfl(mat, upvec);
567                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, upvec);
568         } else {
569                 /* these limits are in toets.c too */
570                 if(vod->v3d->dist<0.001*vod->v3d->grid) vod->v3d->dist= 0.001*vod->v3d->grid;
571                 if(vod->v3d->dist>10.0*vod->v3d->far) vod->v3d->dist=10.0*vod->v3d->far;
572         }
573
574 // XXX  if(vod->v3d->persp==V3D_ORTHO || vod->v3d->persp==V3D_CAMOB) preview3d_event= 0;
575         
576         ED_region_tag_redraw(vod->ar);
577 }
578
579
580 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
581 {       
582         /* execute the events */
583         switch(event->type) {
584                 case MOUSEMOVE:
585                         viewzoom_apply(op->customdata, event->x, event->y);
586                         break;
587                         
588                 case MIDDLEMOUSE:
589                         if(event->val==0) {
590                                 
591                                 MEM_freeN(op->customdata);
592                                 op->customdata= NULL;
593                                 
594                                 return OPERATOR_FINISHED;
595                         }
596                         break;
597         }
598         
599         return OPERATOR_RUNNING_MODAL;
600 }
601
602 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
603 {
604         /* makes op->customdata */
605         viewops_data(C, op, event);
606         
607         /* add temp handler */
608         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
609         
610         return OPERATOR_RUNNING_MODAL;
611 }
612
613
614 void ED_VIEW3D_OT_viewzoom(wmOperatorType *ot)
615 {
616         
617         /* identifiers */
618         ot->name= "Rotate view";
619         ot->idname= "ED_VIEW3D_OT_viewzoom";
620         
621         /* api callbacks */
622         ot->invoke= viewzoom_invoke;
623         ot->modal= viewzoom_modal;
624 }
625
626 /* ************************* below the line! *********************** */
627
628
629 /* XXX todo Zooms in on a border drawn by the user */
630 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
631 {
632         rcti rect;
633         /* ZBuffer depth vars */
634         bglMats mats;
635         float depth, depth_close= MAXFLOAT;
636         int had_depth = 0;
637         double cent[2],  p[3];
638         int xs, ys;
639         
640         // XXX          getmouseco_areawin(mval);
641         
642         // XXX  persp(PERSP_VIEW);
643         
644         rect.xmax = mval[0] + 4;
645         rect.ymax = mval[1] + 4;
646         
647         rect.xmin = mval[0] - 4;
648         rect.ymin = mval[1] - 4;
649         
650         /* Get Z Depths, needed for perspective, nice for ortho */
651         bgl_get_mats(&mats);
652         draw_depth(scene, ar, v3d, NULL);
653         
654         /* force updating */
655         if (v3d->depths) {
656                 had_depth = 1;
657                 v3d->depths->damaged = 1;
658         }
659         
660         view3d_update_depths(ar, v3d);
661         
662         /* Constrain rect to depth bounds */
663         if (rect.xmin < 0) rect.xmin = 0;
664         if (rect.ymin < 0) rect.ymin = 0;
665         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
666         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;          
667         
668         /* Find the closest Z pixel */
669         for (xs=rect.xmin; xs < rect.xmax; xs++) {
670                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
671                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
672                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
673                                 if (depth_close > depth) {
674                                         depth_close = depth;
675                                 }
676                         }
677                 }
678         }
679         
680         if (depth_close==MAXFLOAT)
681                 return 0;
682         
683         if (had_depth==0) {
684                 MEM_freeN(v3d->depths->depths);
685                 v3d->depths->depths = NULL;
686         }
687         v3d->depths->damaged = 1;
688         
689         cent[0] = (double)mval[0];
690         cent[1] = (double)mval[1];
691         
692         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
693                 return 0;
694         
695         mouse_worldloc[0] = (float)p[0];
696         mouse_worldloc[1] = (float)p[1];
697         mouse_worldloc[2] = (float)p[2];
698         return 1;
699 }
700
701
702
703 /* ********************* NDOF ************************ */
704 /* note: this code is confusing and unclear... (ton) */
705 /* **************************************************** */
706
707 // ndof scaling will be moved to user setting.
708 // In the mean time this is just a place holder.
709
710 // Note: scaling in the plugin and ghostwinlay.c
711 // should be removed. With driver default setting,
712 // each axis returns approx. +-200 max deflection.
713
714 // The values I selected are based on the older
715 // polling i/f. With event i/f, the sensistivity
716 // can be increased for improved response from
717 // small deflections of the device input.
718
719
720 // lukep notes : i disagree on the range.
721 // the normal 3Dconnection driver give +/-400
722 // on defaut range in other applications
723 // and up to +/- 1000 if set to maximum
724 // because i remove the scaling by delta,
725 // which was a bad idea as it depend of the system
726 // speed and os, i changed the scaling values, but 
727 // those are still not ok
728
729
730 float ndof_axis_scale[6] = {
731         +0.01,  // Tx
732         +0.01,  // Tz
733         +0.01,  // Ty
734         +0.0015,        // Rx
735         +0.0015,        // Rz
736         +0.0015 // Ry
737 };
738
739 void filterNDOFvalues(float *sbval)
740 {
741         int i=0;
742         float max  = 0.0;
743         
744         for (i =0; i<6;i++)
745                 if (fabs(sbval[i]) > max)
746                         max = fabs(sbval[i]);
747         for (i =0; i<6;i++)
748                 if (fabs(sbval[i]) != max )
749                         sbval[i]=0.0;
750 }
751
752 // statics for controlling v3d->dist corrections.
753 // viewmoveNDOF zeros and adjusts v3d->ofs.
754 // viewmove restores based on dz_flag state.
755
756 int dz_flag = 0;
757 float m_dist;
758
759 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
760 {
761     int i;
762     float phi;
763     float dval[7];
764         // static fval[6] for low pass filter; device input vector is dval[6]
765         static float fval[6];
766     float tvec[3],rvec[3];
767     float q1[4];
768         float mat[3][3];
769         float upvec[3];
770
771
772     /*----------------------------------------------------
773          * sometimes this routine is called from headerbuttons
774      * viewmove needs to refresh the screen
775      */
776 // XXX  areawinset(ar->win);
777
778
779         // fetch the current state of the ndof device
780 // XXX  getndof(dval);
781
782         if (v3d->ndoffilter)
783                 filterNDOFvalues(fval);
784
785         // Scale input values
786
787 //      if(dval[6] == 0) return; // guard against divide by zero
788
789         for(i=0;i<6;i++) {
790
791                 // user scaling
792                 dval[i] = dval[i] * ndof_axis_scale[i];
793         }
794
795
796         // low pass filter with zero crossing reset
797
798         for(i=0;i<6;i++) {
799                 if((dval[i] * fval[i]) >= 0)
800                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
801                 else
802                         fval[i] = 0;
803         }
804
805
806         // force perspective mode. This is a hack and is
807         // incomplete. It doesn't actually effect the view
808         // until the first draw and doesn't update the menu
809         // to reflect persp mode.
810
811         v3d->persp = V3D_PERSP;
812
813
814         // Correct the distance jump if v3d->dist != 0
815
816         // This is due to a side effect of the original
817         // mouse view rotation code. The rotation point is
818         // set a distance in front of the viewport to
819         // make rotating with the mouse look better.
820         // The distance effect is written at a low level
821         // in the view management instead of the mouse
822         // view function. This means that all other view
823         // movement devices must subtract this from their
824         // view transformations.
825
826         if(v3d->dist != 0.0) {
827                 dz_flag = 1;
828                 m_dist = v3d->dist;
829                 upvec[0] = upvec[1] = 0;
830                 upvec[2] = v3d->dist;
831                 Mat3CpyMat4(mat, v3d->viewinv);
832                 Mat3MulVecfl(mat, upvec);
833                 VecSubf(v3d->ofs, v3d->ofs, upvec);
834                 v3d->dist = 0.0;
835         }
836
837
838         // Apply rotation
839         // Rotations feel relatively faster than translations only in fly mode, so
840         // we have no choice but to fix that here (not in the plugins)
841         rvec[0] = -0.5 * dval[3];
842         rvec[1] = -0.5 * dval[4];
843         rvec[2] = -0.5 * dval[5];
844
845         // rotate device x and y by view z
846
847         Mat3CpyMat4(mat, v3d->viewinv);
848         mat[2][2] = 0.0f;
849         Mat3MulVecfl(mat, rvec);
850
851         // rotate the view
852
853         phi = Normalize(rvec);
854         if(phi != 0) {
855                 VecRotToQuat(rvec,phi,q1);
856                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
857         }
858
859
860         // Apply translation
861
862         tvec[0] = dval[0];
863         tvec[1] = dval[1];
864         tvec[2] = -dval[2];
865
866         // the next three lines rotate the x and y translation coordinates
867         // by the current z axis angle
868
869         Mat3CpyMat4(mat, v3d->viewinv);
870         mat[2][2] = 0.0f;
871         Mat3MulVecfl(mat, tvec);
872
873         // translate the view
874
875         VecSubf(v3d->ofs, v3d->ofs, tvec);
876
877
878         /*----------------------------------------------------
879      * refresh the screen XXX
880       */
881
882         // update render preview window
883
884 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
885 }
886
887 void viewmoveNDOF(Scene *scene, View3D *v3d, int mode)
888 {
889     float fval[7];
890     float dvec[3];
891     float sbadjust = 1.0f;
892     float len;
893         short use_sel = 0;
894         Object *ob = OBACT;
895     float m[3][3];
896     float m_inv[3][3];
897     float xvec[3] = {1,0,0};
898     float yvec[3] = {0,-1,0};
899     float zvec[3] = {0,0,1};
900         float phi, si;
901     float q1[4];
902     float obofs[3];
903     float reverse;
904     //float diff[4];
905     float d, curareaX, curareaY;
906     float mat[3][3];
907     float upvec[3];
908
909     /* Sensitivity will control how fast the view rotates.  The value was
910      * obtained experimentally by tweaking until the author didn't get dizzy watching.
911      * Perhaps this should be a configurable user parameter. 
912      */
913     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
914     float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
915     float zsens = 0.3f;   /* zoom sensitivity */
916
917     const float minZoom = -30.0f;
918     const float maxZoom = 300.0f;
919
920         //reset view type
921         v3d->view = 0;
922 //printf("passing here \n");
923 //
924         if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
925                 use_sel = 1;
926         }
927
928     if((dz_flag)||v3d->dist==0) {
929                 dz_flag = 0;
930                 v3d->dist = m_dist;
931                 upvec[0] = upvec[1] = 0;
932                 upvec[2] = v3d->dist;
933                 Mat3CpyMat4(mat, v3d->viewinv);
934                 Mat3MulVecfl(mat, upvec);
935                 VecAddf(v3d->ofs, v3d->ofs, upvec);
936         }
937
938     /*----------------------------------------------------
939          * sometimes this routine is called from headerbuttons
940      * viewmove needs to refresh the screen
941      */
942 // XXX  areawinset(curarea->win);
943
944     /*----------------------------------------------------
945      * record how much time has passed. clamp at 10 Hz
946      * pretend the previous frame occured at the clamped time 
947      */
948 //    now = PIL_check_seconds_timer();
949  //   frametime = (now - prevTime);
950  //   if (frametime > 0.1f){        /* if more than 1/10s */
951  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
952 //    }
953 //    prevTime = now;
954  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
955
956     /* fetch the current state of the ndof device & enforce dominant mode if selected */
957 // XXX    getndof(fval);
958         if (v3d->ndoffilter)
959                 filterNDOFvalues(fval);
960         
961         
962     // put scaling back here, was previously in ghostwinlay
963     fval[0] = fval[0] * (1.0f/600.0f);
964     fval[1] = fval[1] * (1.0f/600.0f);
965     fval[2] = fval[2] * (1.0f/1100.0f);
966     fval[3] = fval[3] * 0.00005f;
967     fval[4] =-fval[4] * 0.00005f;
968     fval[5] = fval[5] * 0.00005f;
969     fval[6] = fval[6] / 1000000.0f;
970                         
971     // scale more if not in perspective mode
972     if (v3d->persp == V3D_ORTHO) {
973         fval[0] = fval[0] * 0.05f;
974         fval[1] = fval[1] * 0.05f;
975         fval[2] = fval[2] * 0.05f;
976         fval[3] = fval[3] * 0.9f;
977         fval[4] = fval[4] * 0.9f;
978         fval[5] = fval[5] * 0.9f;
979         zsens *= 8;
980     }
981                         
982         
983     /* set object offset */
984         if (ob) {
985                 obofs[0] = -ob->obmat[3][0];
986                 obofs[1] = -ob->obmat[3][1];
987                 obofs[2] = -ob->obmat[3][2];
988         }
989         else {
990                 VECCOPY(obofs, v3d->ofs);
991         }
992
993     /* calc an adjustment based on distance from camera
994        disabled per patch 14402 */
995      d = 1.0f;
996
997 /*    if (ob) {
998         VecSubf(diff, obofs, v3d->ofs);
999         d = VecLength(diff);
1000     }
1001 */
1002
1003     reverse = (v3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1004
1005     /*----------------------------------------------------
1006      * ndof device pan 
1007      */
1008     psens *= 1.0f + d;
1009     curareaX = sbadjust * psens * fval[0];
1010     curareaY = sbadjust * psens * fval[1];
1011     dvec[0] = curareaX * v3d->persinv[0][0] + curareaY * v3d->persinv[1][0];
1012     dvec[1] = curareaX * v3d->persinv[0][1] + curareaY * v3d->persinv[1][1];
1013     dvec[2] = curareaX * v3d->persinv[0][2] + curareaY * v3d->persinv[1][2];
1014     VecAddf(v3d->ofs, v3d->ofs, dvec);
1015
1016     /*----------------------------------------------------
1017      * ndof device dolly 
1018      */
1019     len = zsens * sbadjust * fval[2];
1020
1021     if (v3d->persp==V3D_CAMOB) {
1022         if(v3d->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1023             v3d->camzoom+= 10.0f * -len;
1024         }
1025         if (v3d->camzoom < minZoom) v3d->camzoom = minZoom;
1026         else if (v3d->camzoom > maxZoom) v3d->camzoom = maxZoom;
1027     }
1028     else if ((v3d->dist> 0.001*v3d->grid) && (v3d->dist<10.0*v3d->far)) {
1029         v3d->dist*=(1.0 + len);
1030     }
1031
1032
1033     /*----------------------------------------------------
1034      * ndof device turntable
1035      * derived from the turntable code in viewmove
1036      */
1037
1038     /* Get the 3x3 matrix and its inverse from the quaternion */
1039     QuatToMat3(v3d->viewquat, m);
1040     Mat3Inv(m_inv,m);
1041
1042     /* Determine the direction of the x vector (for rotating up and down) */
1043     /* This can likely be compuated directly from the quaternion. */
1044     Mat3MulVecfl(m_inv,xvec);
1045     Mat3MulVecfl(m_inv,yvec);
1046     Mat3MulVecfl(m_inv,zvec);
1047
1048     /* Perform the up/down rotation */
1049     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1050     si = sin(phi);
1051     q1[0] = cos(phi);
1052     q1[1] = si * xvec[0];
1053     q1[2] = si * xvec[1];
1054     q1[3] = si * xvec[2];
1055     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1056
1057     if (use_sel) {
1058         QuatConj(q1); /* conj == inv for unit quat */
1059         VecSubf(v3d->ofs, v3d->ofs, obofs);
1060         QuatMulVecf(q1, v3d->ofs);
1061         VecAddf(v3d->ofs, v3d->ofs, obofs);
1062     }
1063
1064     /* Perform the orbital rotation */
1065     /* Perform the orbital rotation 
1066        If the seen Up axis is parallel to the zoom axis, rotation should be
1067        achieved with a pure Roll motion (no Spin) on the device. When you start 
1068        to tilt, moving from Top to Side view, Spinning will increasingly become 
1069        more relevant while the Roll component will decrease. When a full 
1070        Side view is reached, rotations around the world's Up axis are achieved
1071        with a pure Spin-only motion.  In other words the control of the spinning
1072        around the world's Up axis should move from the device's Spin axis to the
1073        device's Roll axis depending on the orientation of the world's Up axis 
1074        relative to the screen. */
1075     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
1076     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
1077     q1[0] = cos(phi);
1078     q1[1] = q1[2] = 0.0;
1079     q1[3] = sin(phi);
1080     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1081
1082     if (use_sel) {
1083         QuatConj(q1);
1084         VecSubf(v3d->ofs, v3d->ofs, obofs);
1085         QuatMulVecf(q1, v3d->ofs);
1086         VecAddf(v3d->ofs, v3d->ofs, obofs);
1087     }
1088
1089     /*----------------------------------------------------
1090      * refresh the screen
1091      */
1092 // XXX    scrarea_do_windraw(curarea);
1093 }
1094
1095
1096
1097