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_space_api.h"
73 #include "ED_screen.h"
74 #include "ED_types.h"
75
76 #include "UI_interface.h"
77 #include "UI_resources.h"
78 #include "UI_view2d.h"
79
80 #include "PIL_time.h" /* smoothview */
81
82 #include "view3d_intern.h"      // own include
83
84 /* ********************** view3d_edit: view manipulations ********************* */
85
86 /* ************************** init for view ops **********************************/
87
88 typedef struct ViewOpsData {
89         ARegion *ar;
90         View3D *v3d;
91
92         float oldquat[4];
93         float trackvec[3];
94         float ofs[3], obofs[3];
95         float reverse, dist0;
96
97         int origx, origy, oldx, oldy;
98         int origkey;
99
100 } ViewOpsData;
101
102 #define TRACKBALLSIZE  (1.1)
103
104 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
105 {
106         float x, y, radius, d, z, t;
107
108         radius= TRACKBALLSIZE;
109
110         /* normalize x and y */
111         x= (rect->xmax + rect->xmin)/2 - mx;
112         x/= (float)((rect->xmax - rect->xmin)/4);
113         y= (rect->ymax + rect->ymin)/2 - my;
114         y/= (float)((rect->ymax - rect->ymin)/2);
115
116         d = sqrt(x*x + y*y);
117         if (d < radius*M_SQRT1_2)       /* Inside sphere */
118                 z = sqrt(radius*radius - d*d);
119         else
120         {                       /* On hyperbola */
121                 t = radius / M_SQRT2;
122                 z = t*t / d;
123         }
124
125         vec[0]= x;
126         vec[1]= y;
127         vec[2]= -z;             /* yah yah! */
128 }
129
130
131 static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
132 {
133         ScrArea *sa= CTX_wm_area(C);
134         View3D *v3d= sa->spacedata.first;
135         ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
136
137         /* store data */
138         op->customdata= vod;
139         vod->ar= CTX_wm_region(C);
140         vod->v3d= v3d;
141         vod->dist0= v3d->dist;
142         QUATCOPY(vod->oldquat, v3d->viewquat);
143         vod->origx= vod->oldx= event->x;
144         vod->origy= vod->oldy= event->y;
145         vod->origkey= event->type;
146
147         calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
148
149         initgrabz(v3d, -v3d->ofs[0], -v3d->ofs[1], -v3d->ofs[2]);
150
151         vod->reverse= 1.0f;
152         if (v3d->persmat[2][1] < 0.0f)
153                 vod->reverse= -1.0f;
154
155 }
156
157 /* ************************** viewrotate **********************************/
158
159 static const float thres = 0.93f; //cos(20 deg);
160
161 #define COS45 0.70710678118654746
162 #define SIN45 COS45
163
164 static float snapquats[39][6] = {
165         /*{q0, q1, q3, q4, view, oposite_direction}*/
166 {COS45, -SIN45, 0.0, 0.0, 1, 0},  //front
167 {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back
168 {1.0, 0.0, 0.0, 0.0, 7, 0},       //top
169 {0.0, -1.0, 0.0, 0.0, 7, 1},      //bottom
170 {0.5, -0.5, -0.5, -0.5, 3, 0},    //left
171 {0.5, -0.5, 0.5, 0.5, 3, 1},      //right
172
173         /* some more 45 deg snaps */
174 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
175 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
176 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
177 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
178 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
179 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
180 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
181 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
182 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
183 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
184 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
185 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
186 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
187 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
188 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
189 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
190 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
191 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
192 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
193 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
194 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
195 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
196 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
197 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
198 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
199 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
200 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
201 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
202 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
203 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
204 {-COS45, 0.0, 0.0, SIN45, 0, 0},
205 {COS45, 0.0, 0.0, SIN45, 0, 0},
206 {0.0, 0.0, 0.0, 1.0, 0, 0}
207 };
208
209
210 static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl)
211 {
212         View3D *v3d= vod->v3d;
213         int use_sel= 0; /* XXX */
214
215         v3d->view= 0; /* need to reset everytime because of view snapping */
216
217         if (U.flag & USER_TRACKBALL) {
218                 float phi, si, q1[4], dvec[3], newvec[3];
219
220                 calctrackballvec(&vod->ar->winrct, x, y, newvec);
221
222                 VecSubf(dvec, newvec, vod->trackvec);
223
224                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
225                 si/= (2.0*TRACKBALLSIZE);
226
227                 Crossf(q1+1, vod->trackvec, newvec);
228                 Normalize(q1+1);
229
230                 /* Allow for rotation beyond the interval
231                         * [-pi, pi] */
232                 while (si > 1.0)
233                         si -= 2.0;
234
235                 /* This relation is used instead of
236                         * phi = asin(si) so that the angle
237                         * of rotation is linearly proportional
238                         * to the distance that the mouse is
239                         * dragged. */
240                 phi = si * M_PI / 2.0;
241
242                 si= sin(phi);
243                 q1[0]= cos(phi);
244                 q1[1]*= si;
245                 q1[2]*= si;
246                 q1[3]*= si;
247                 QuatMul(v3d->viewquat, q1, vod->oldquat);
248
249                 if (use_sel) {
250                         /* compute the post multiplication quat, to rotate the offset correctly */
251                         QUATCOPY(q1, vod->oldquat);
252                         QuatConj(q1);
253                         QuatMul(q1, q1, v3d->viewquat);
254
255                         QuatConj(q1); /* conj == inv for unit quat */
256                         VECCOPY(v3d->ofs, vod->ofs);
257                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
258                         QuatMulVecf(q1, v3d->ofs);
259                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
260                 }
261         }
262         else {
263                 /* New turntable view code by John Aughey */
264                 float si, phi, q1[4];
265                 float m[3][3];
266                 float m_inv[3][3];
267                 float xvec[3] = {1,0,0};
268                 /* Sensitivity will control how fast the viewport rotates.  0.0035 was
269                         obtained experimentally by looking at viewport rotation sensitivities
270                         on other modeling programs. */
271                 /* Perhaps this should be a configurable user parameter. */
272                 const float sensitivity = 0.0035;
273
274                 /* Get the 3x3 matrix and its inverse from the quaternion */
275                 QuatToMat3(v3d->viewquat, m);
276                 Mat3Inv(m_inv,m);
277
278                 /* Determine the direction of the x vector (for rotating up and down) */
279                 /* This can likely be compuated directly from the quaternion. */
280                 Mat3MulVecfl(m_inv,xvec);
281
282                 /* Perform the up/down rotation */
283                 phi = sensitivity * -(y - vod->oldy);
284                 si = sin(phi);
285                 q1[0] = cos(phi);
286                 q1[1] = si * xvec[0];
287                 q1[2] = si * xvec[1];
288                 q1[3] = si * xvec[2];
289                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
290
291                 if (use_sel) {
292                         QuatConj(q1); /* conj == inv for unit quat */
293                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
294                         QuatMulVecf(q1, v3d->ofs);
295                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
296                 }
297
298                 /* Perform the orbital rotation */
299                 phi = sensitivity * vod->reverse * (x - vod->oldx);
300                 q1[0] = cos(phi);
301                 q1[1] = q1[2] = 0.0;
302                 q1[3] = sin(phi);
303                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
304
305                 if (use_sel) {
306                         QuatConj(q1);
307                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
308                         QuatMulVecf(q1, v3d->ofs);
309                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
310                 }
311         }
312
313         /* check for view snap */
314         if (ctrl){
315                 int i;
316                 float viewmat[3][3];
317
318
319                 QuatToMat3(v3d->viewquat, viewmat);
320
321                 for (i = 0 ; i < 39; i++){
322                         float snapmat[3][3];
323                         float view = (int)snapquats[i][4];
324                         float oposite_dir = (int)snapquats[i][5];
325
326                         QuatToMat3(snapquats[i], snapmat);
327
328                         if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
329                                 (Inpf(snapmat[1], viewmat[1]) > thres) &&
330                                 (Inpf(snapmat[2], viewmat[2]) > thres)){
331
332                                 QUATCOPY(v3d->viewquat, snapquats[i]);
333
334                                 v3d->view = view;
335                                 if (view){
336                                         if (oposite_dir){
337                                                 v3d->flag2 |= V3D_OPP_DIRECTION_NAME;
338                                         }else{
339                                                 v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME;
340                                         }
341                                 }
342
343                                 break;
344                         }
345                 }
346         }
347         vod->oldx= x;
348         vod->oldy= y;
349
350         ED_region_tag_redraw(vod->ar);
351 }
352
353 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
354 {
355         ViewOpsData *vod= op->customdata;
356
357         /* execute the events */
358         switch(event->type) {
359                 case MOUSEMOVE:
360                         viewrotate_apply(vod, event->x, event->y, event->ctrl);
361                         break;
362
363                 default:
364                         if(event->type==vod->origkey && event->val==0) {
365
366                                 MEM_freeN(vod);
367                                 op->customdata= NULL;
368
369                                 return OPERATOR_FINISHED;
370                         }
371         }
372
373         return OPERATOR_RUNNING_MODAL;
374 }
375
376 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
377 {
378         ViewOpsData *vod;
379
380         /* makes op->customdata */
381         viewops_data(C, op, event);
382         vod= op->customdata;
383
384         /* switch from camera view when: */
385         if(vod->v3d->persp != V3D_PERSP) {
386
387                 if (U.uiflag & USER_AUTOPERSP)
388                         vod->v3d->persp= V3D_PERSP;
389                 else if(vod->v3d->persp==V3D_CAMOB)
390                         vod->v3d->persp= V3D_PERSP;
391                 ED_region_tag_redraw(vod->ar);
392         }
393
394         /* add temp handler */
395         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
396
397         return OPERATOR_RUNNING_MODAL;
398 }
399
400
401 void VIEW3D_OT_viewrotate(wmOperatorType *ot)
402 {
403
404         /* identifiers */
405         ot->name= "Rotate view";
406         ot->idname= "VIEW3D_OT_viewrotate";
407
408         /* api callbacks */
409         ot->invoke= viewrotate_invoke;
410         ot->modal= viewrotate_modal;
411         ot->poll= ED_operator_view3d_active;
412 }
413
414 /* ************************ viewmove ******************************** */
415
416 static void viewmove_apply(ViewOpsData *vod, int x, int y)
417 {
418         if(vod->v3d->persp==V3D_CAMOB) {
419                 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
420
421                 vod->v3d->camdx += (vod->oldx - x)/(max);
422                 vod->v3d->camdy += (vod->oldy - y)/(max);
423                 CLAMP(vod->v3d->camdx, -1.0f, 1.0f);
424                 CLAMP(vod->v3d->camdy, -1.0f, 1.0f);
425 // XXX          preview3d_event= 0;
426         }
427         else {
428                 float dvec[3];
429
430                 window_to_3d(vod->ar, vod->v3d, dvec, x-vod->oldx, y-vod->oldy);
431                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, dvec);
432         }
433
434         vod->oldx= x;
435         vod->oldy= y;
436
437         ED_region_tag_redraw(vod->ar);
438 }
439
440
441 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
442 {
443         ViewOpsData *vod= op->customdata;
444
445         /* execute the events */
446         switch(event->type) {
447                 case MOUSEMOVE:
448                         viewmove_apply(vod, event->x, event->y);
449                         break;
450
451                 default:
452                         if(event->type==vod->origkey && event->val==0) {
453
454                                 MEM_freeN(vod);
455                                 op->customdata= NULL;
456
457                                 return OPERATOR_FINISHED;
458                         }
459         }
460
461         return OPERATOR_RUNNING_MODAL;
462 }
463
464 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
465 {
466         /* makes op->customdata */
467         viewops_data(C, op, event);
468
469         /* add temp handler */
470         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
471
472         return OPERATOR_RUNNING_MODAL;
473 }
474
475
476 void VIEW3D_OT_viewmove(wmOperatorType *ot)
477 {
478
479         /* identifiers */
480         ot->name= "Rotate view";
481         ot->idname= "VIEW3D_OT_viewmove";
482
483         /* api callbacks */
484         ot->invoke= viewmove_invoke;
485         ot->modal= viewmove_modal;
486         ot->poll= ED_operator_view3d_active;
487 }
488
489 /* ************************ viewzoom ******************************** */
490
491 static void view_zoom_mouseloc(ARegion *ar, View3D *v3d, float dfac, int mx, int my)
492 {
493         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
494                 float dvec[3];
495                 float tvec[3];
496                 float tpos[3];
497                 float new_dist;
498                 short vb[2], mouseloc[2];
499
500                 mouseloc[0]= mx - ar->winrct.xmin;
501                 mouseloc[1]= my - ar->winrct.ymin;
502
503                 /* find the current window width and height */
504                 vb[0] = ar->winx;
505                 vb[1] = ar->winy;
506
507                 tpos[0] = -v3d->ofs[0];
508                 tpos[1] = -v3d->ofs[1];
509                 tpos[2] = -v3d->ofs[2];
510
511                 /* Project cursor position into 3D space */
512                 initgrabz(v3d, tpos[0], tpos[1], tpos[2]);
513                 window_to_3d(ar, v3d, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
514
515                 /* Calculate view target position for dolly */
516                 tvec[0] = -(tpos[0] + dvec[0]);
517                 tvec[1] = -(tpos[1] + dvec[1]);
518                 tvec[2] = -(tpos[2] + dvec[2]);
519
520                 /* Offset to target position and dolly */
521                 new_dist = v3d->dist * dfac;
522
523                 VECCOPY(v3d->ofs, tvec);
524                 v3d->dist = new_dist;
525
526                 /* Calculate final offset */
527                 dvec[0] = tvec[0] + dvec[0] * dfac;
528                 dvec[1] = tvec[1] + dvec[1] * dfac;
529                 dvec[2] = tvec[2] + dvec[2] * dfac;
530
531                 VECCOPY(v3d->ofs, dvec);
532         } else {
533                 v3d->dist *= dfac;
534         }
535 }
536
537
538 static void viewzoom_apply(ViewOpsData *vod, int x, int y)
539 {
540         float zfac=1.0;
541
542         if(U.viewzoom==USER_ZOOM_CONT) {
543                 // oldstyle zoom
544                 zfac = 1.0+(float)(vod->origx - x + vod->origy - y)/1000.0;
545         }
546         else if(U.viewzoom==USER_ZOOM_SCALE) {
547                 int ctr[2], len1, len2;
548                 // method which zooms based on how far you move the mouse
549
550                 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
551                 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
552
553                 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
554                 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
555
556                 zfac = vod->dist0 * ((float)len2/len1) / vod->v3d->dist;
557         }
558         else {  /* USER_ZOOM_DOLLY */
559                 float len1 = (vod->ar->winrct.ymax - y) + 5;
560                 float len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
561                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->v3d->dist;
562         }
563
564         if(zfac != 1.0 && zfac*vod->v3d->dist > 0.001*vod->v3d->grid &&
565                                 zfac*vod->v3d->dist < 10.0*vod->v3d->far)
566                 view_zoom_mouseloc(vod->ar, vod->v3d, zfac, vod->oldx, vod->oldy);
567
568
569         if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->v3d->persp==V3D_PERSP)) {
570                 float upvec[3], mat[3][3];
571
572                 /* Secret apricot feature, translate the view when in continues mode */
573                 upvec[0] = upvec[1] = 0.0f;
574                 upvec[2] = (vod->dist0 - vod->v3d->dist) * vod->v3d->grid;
575                 vod->v3d->dist = vod->dist0;
576                 Mat3CpyMat4(mat, vod->v3d->viewinv);
577                 Mat3MulVecfl(mat, upvec);
578                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, upvec);
579         } else {
580                 /* these limits are in toets.c too */
581                 if(vod->v3d->dist<0.001*vod->v3d->grid) vod->v3d->dist= 0.001*vod->v3d->grid;
582                 if(vod->v3d->dist>10.0*vod->v3d->far) vod->v3d->dist=10.0*vod->v3d->far;
583         }
584
585 // XXX  if(vod->v3d->persp==V3D_ORTHO || vod->v3d->persp==V3D_CAMOB) preview3d_event= 0;
586
587         ED_region_tag_redraw(vod->ar);
588 }
589
590
591 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
592 {
593         ViewOpsData *vod= op->customdata;
594
595         /* execute the events */
596         switch(event->type) {
597                 case MOUSEMOVE:
598                         viewzoom_apply(vod, event->x, event->y);
599                         break;
600
601                 default:
602                         if(event->type==vod->origkey && event->val==0) {
603
604                                 MEM_freeN(vod);
605                                 op->customdata= NULL;
606
607                                 return OPERATOR_FINISHED;
608                         }
609         }
610
611         return OPERATOR_RUNNING_MODAL;
612 }
613
614 static int viewzoom_exec(bContext *C, wmOperator *op)
615 {
616         ScrArea *sa= CTX_wm_area(C);
617         View3D *v3d= sa->spacedata.first;
618         int delta= RNA_int_get(op->ptr, "delta");
619
620         if(delta < 0) {
621                 /* this min and max is also in viewmove() */
622                 if(v3d->persp==V3D_CAMOB) {
623                         v3d->camzoom-= 10;
624                         if(v3d->camzoom<-30) v3d->camzoom= -30;
625                 }
626                 else if(v3d->dist<10.0*v3d->far) v3d->dist*=1.2f;
627         }
628         else {
629                 if(v3d->persp==V3D_CAMOB) {
630                         v3d->camzoom+= 10;
631                         if(v3d->camzoom>300) v3d->camzoom= 300;
632                 }
633                 else if(v3d->dist> 0.001*v3d->grid) v3d->dist*=.83333f;
634         }
635
636         ED_region_tag_redraw(CTX_wm_region(C));
637
638         return OPERATOR_FINISHED;
639 }
640
641 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
642 {
643         int delta= RNA_int_get(op->ptr, "delta");
644
645         if(delta) {
646                 viewzoom_exec(C, op);
647         }
648         else {
649                 /* makes op->customdata */
650                 viewops_data(C, op, event);
651
652                 /* add temp handler */
653                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
654
655                 return OPERATOR_RUNNING_MODAL;
656         }
657         return OPERATOR_FINISHED;
658 }
659
660
661 void VIEW3D_OT_viewzoom(wmOperatorType *ot)
662 {
663         /* identifiers */
664         ot->name= "Rotate view";
665         ot->idname= "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_view3d_active;
672
673         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
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) {
728                         v3d->persp= V3D_PERSP;
729                         smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL); 
730                 }
731         }
732 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
733
734         return OPERATOR_FINISHED;
735 }
736
737 void VIEW3D_OT_viewhome(wmOperatorType *ot)
738 {
739         /* identifiers */
740         ot->name= "View home";
741         ot->idname= "VIEW3D_OT_viewhome";
742
743         /* api callbacks */
744         ot->exec= viewhome_exec;
745         ot->poll= ED_operator_view3d_active;
746
747         RNA_def_boolean(ot->srna, "center", 0, "Center", "");
748 }
749
750 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
751 {
752         ScrArea *sa= CTX_wm_area(C);
753         ARegion *ar= CTX_wm_region(C);
754         View3D *v3d= sa->spacedata.first;
755         Scene *scene= CTX_data_scene(C);
756         Object *ob= OBACT;
757         Object *obedit= CTX_data_edit_object(C);
758         float size, min[3], max[3], afm[3];
759         int ok=0;
760
761         /* SMOOTHVIEW */
762         float new_ofs[3];
763         float new_dist;
764
765         INIT_MINMAX(min, max);
766
767         if (G.f & G_WEIGHTPAINT) {
768                 /* hardcoded exception, we look for the one selected armature */
769                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
770                 Base *base;
771                 for(base=scene->base.first; base; base= base->next) {
772                         if(TESTBASELIB(v3d, base)) {
773                                 if(base->object->type==OB_ARMATURE)
774                                         if(base->object->flag & OB_POSEMODE)
775                                                 break;
776                         }
777                 }
778                 if(base)
779                         ob= base->object;
780         }
781
782
783         if(obedit) {
784 // XXX          ok = minmax_verts(min, max);    /* only selected */
785         }
786         else if(ob && (ob->flag & OB_POSEMODE)) {
787                 if(ob->pose) {
788                         bArmature *arm= ob->data;
789                         bPoseChannel *pchan;
790                         float vec[3];
791
792                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
793                                 if(pchan->bone->flag & BONE_SELECTED) {
794                                         if(pchan->bone->layer & arm->layer) {
795                                                 ok= 1;
796                                                 VECCOPY(vec, pchan->pose_head);
797                                                 Mat4MulVecfl(ob->obmat, vec);
798                                                 DO_MINMAX(vec, min, max);
799                                                 VECCOPY(vec, pchan->pose_tail);
800                                                 Mat4MulVecfl(ob->obmat, vec);
801                                                 DO_MINMAX(vec, min, max);
802                                         }
803                                 }
804                         }
805                 }
806         }
807         else if (FACESEL_PAINT_TEST) {
808 // XXX          ok= minmax_tface(min, max);
809         }
810         else if (G.f & G_PARTICLEEDIT) {
811 // XXX          ok= PE_minmax(min, max);
812         }
813         else {
814                 Base *base= FIRSTBASE;
815                 while(base) {
816                         if(TESTBASE(v3d, base))  {
817                                 minmax_object(base->object, min, max);
818                                 /* account for duplis */
819                                 minmax_object_duplis(scene, base->object, min, max);
820
821                                 ok= 1;
822                         }
823                         base= base->next;
824                 }
825         }
826
827         if(ok==0) return OPERATOR_FINISHED;
828
829         afm[0]= (max[0]-min[0]);
830         afm[1]= (max[1]-min[1]);
831         afm[2]= (max[2]-min[2]);
832         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
833
834         if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
835
836         new_ofs[0]= -(min[0]+max[0])/2.0f;
837         new_ofs[1]= -(min[1]+max[1])/2.0f;
838         new_ofs[2]= -(min[2]+max[2])/2.0f;
839
840         new_dist = size;
841
842         /* correction for window aspect ratio */
843         if(ar->winy>2 && ar->winx>2) {
844                 size= (float)ar->winx/(float)ar->winy;
845                 if(size<1.0f) size= 1.0f/size;
846                 new_dist*= size;
847         }
848
849         v3d->cursor[0]= -new_ofs[0];
850         v3d->cursor[1]= -new_ofs[1];
851         v3d->cursor[2]= -new_ofs[2];
852
853         if (v3d->persp==V3D_CAMOB) {
854                 v3d->persp= V3D_PERSP;
855                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
856         } 
857         else {
858                 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
859         }
860
861 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
862
863         return OPERATOR_FINISHED;
864 }
865 void VIEW3D_OT_viewcenter(wmOperatorType *ot)
866 {
867
868         /* identifiers */
869         ot->name= "View center";
870         ot->idname= "VIEW3D_OT_viewcenter";
871
872         /* api callbacks */
873         ot->exec= viewcenter_exec;
874         ot->poll= ED_operator_view3d_active;
875 }
876
877 /* ********************* Set render border operator ****************** */
878
879 static int render_border_exec(bContext *C, wmOperator *op)
880 {
881         ScrArea *sa= CTX_wm_area(C);
882         ARegion *ar= CTX_wm_region(C);
883         View3D *v3d= sa->spacedata.first;
884         Scene *scene= CTX_data_scene(C);
885         
886         rcti rect;
887         rctf vb;
888         
889         /* get border select values using rna */
890         rect.xmin= RNA_int_get(op->ptr, "xmin");
891         rect.ymin= RNA_int_get(op->ptr, "ymin");
892         rect.xmax= RNA_int_get(op->ptr, "xmax");
893         rect.ymax= RNA_int_get(op->ptr, "ymax");
894         
895         /* calculate range */
896         calc_viewborder(scene, ar, v3d, &vb);
897
898         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
899         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
900         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
901         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
902         
903         /* actually set border */       
904         CLAMP(scene->r.border.xmin, 0.0, 1.0);
905         CLAMP(scene->r.border.ymin, 0.0, 1.0);
906         CLAMP(scene->r.border.xmax, 0.0, 1.0);
907         CLAMP(scene->r.border.ymax, 0.0, 1.0);
908                 
909         /* drawing a border surrounding the entire camera view switches off border rendering
910          * or the border covers no pixels */
911         if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
912                 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
913            (scene->r.border.xmin == scene->r.border.xmax ||
914                 scene->r.border.ymin == scene->r.border.ymax ))
915         {
916                 scene->r.mode &= ~R_BORDER;
917         } else {
918                 scene->r.mode |= R_BORDER;
919         }
920         
921         return OPERATOR_FINISHED;
922
923 }
924
925 static int view3d_render_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
926 {
927         ScrArea *sa= CTX_wm_area(C);
928         View3D *v3d= sa->spacedata.first;
929         
930         /* if not in camera view do not exec the operator*/
931         if (v3d->persp == V3D_CAMOB) return WM_border_select_invoke(C, op, event);      
932         else return OPERATOR_PASS_THROUGH;
933 }
934
935 void VIEW3D_OT_render_border(wmOperatorType *ot)
936 {
937         /* identifiers */
938         ot->name= "Set Render Border";
939         ot->idname= "VIEW3D_OT_render_border";
940
941         /* api callbacks */
942         ot->invoke= view3d_render_border_invoke;
943         ot->exec= render_border_exec;
944         ot->modal= WM_border_select_modal;
945         
946         ot->poll= ED_operator_view3d_active;
947         
948         /* rna */
949         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
950         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
951         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
952         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
953
954 }
955 /* ********************* Border Zoom operator ****************** */
956
957 static int view3d_border_zoom_exec(bContext *C, wmOperator *op)
958 {
959         ScrArea *sa= CTX_wm_area(C);
960         ARegion *ar= CTX_wm_region(C);
961         View3D *v3d= sa->spacedata.first;
962         Scene *scene= CTX_data_scene(C);
963         
964         /* Zooms in on a border drawn by the user */
965         rcti rect;
966         float dvec[3], vb[2], xscale, yscale, scale;
967
968         /* SMOOTHVIEW */
969         float new_dist;
970         float new_ofs[3];
971
972         /* ZBuffer depth vars */
973         bglMats mats;
974         float depth, depth_close= MAXFLOAT;
975         int had_depth = 0;
976         double cent[2],  p[3];
977         int xs, ys;
978         
979         /* note; otherwise opengl won't work */
980         view3d_operator_needs_opengl(C);
981         
982         /* get border select values using rna */
983         rect.xmin= RNA_int_get(op->ptr, "xmin");
984         rect.ymin= RNA_int_get(op->ptr, "ymin");
985         rect.xmax= RNA_int_get(op->ptr, "xmax");
986         rect.ymax= RNA_int_get(op->ptr, "ymax");
987         
988         /* Get Z Depths, needed for perspective, nice for ortho */
989         bgl_get_mats(&mats);
990         draw_depth(scene, ar, v3d, NULL);
991
992         /* force updating */
993         if (v3d->depths) {
994                 had_depth = 1;
995                 v3d->depths->damaged = 1;
996         }
997
998         view3d_update_depths(ar, v3d);
999
1000         /* Constrain rect to depth bounds */
1001         if (rect.xmin < 0) rect.xmin = 0;
1002         if (rect.ymin < 0) rect.ymin = 0;
1003         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1004         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;
1005
1006         /* Find the closest Z pixel */
1007         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1008                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1009                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1010                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1011                                 if (depth_close > depth) {
1012                                         depth_close = depth;
1013                                 }
1014                         }
1015                 }
1016         }
1017
1018         if (had_depth==0) {
1019                 MEM_freeN(v3d->depths->depths);
1020                 v3d->depths->depths = NULL;
1021         }
1022         v3d->depths->damaged = 1;
1023
1024         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1025         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1026
1027         if (v3d->persp==V3D_PERSP) {
1028                 double p_corner[3];
1029
1030                 /* no depths to use, we cant do anything! */
1031                 if (depth_close==MAXFLOAT)
1032                         return OPERATOR_CANCELLED;
1033
1034                 /* convert border to 3d coordinates */
1035                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1036                         (       !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])))
1037                         return OPERATOR_CANCELLED;
1038
1039                 dvec[0] = p[0]-p_corner[0];
1040                 dvec[1] = p[1]-p_corner[1];
1041                 dvec[2] = p[2]-p_corner[2];
1042
1043                 new_dist = VecLength(dvec);
1044                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1045
1046                 new_ofs[0] = -p[0];
1047                 new_ofs[1] = -p[1];
1048                 new_ofs[2] = -p[2];
1049
1050         } else { /* othographic */
1051                 /* find the current window width and height */
1052                 vb[0] = ar->winx;
1053                 vb[1] = ar->winy;
1054
1055                 new_dist = v3d->dist;
1056
1057                 /* convert the drawn rectangle into 3d space */
1058                 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1059                         new_ofs[0] = -p[0];
1060                         new_ofs[1] = -p[1];
1061                         new_ofs[2] = -p[2];
1062                 } else {
1063                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1064                         new_ofs[0] = v3d->ofs[0];
1065                         new_ofs[1] = v3d->ofs[1];
1066                         new_ofs[2] = v3d->ofs[2];
1067
1068                         initgrabz(v3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1069
1070                         window_to_3d(ar, v3d, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1071                         /* center the view to the center of the rectangle */
1072                         VecSubf(new_ofs, new_ofs, dvec);
1073                 }
1074
1075                 /* work out the ratios, so that everything selected fits when we zoom */
1076                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1077                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1078                 scale = (xscale >= yscale)?xscale:yscale;
1079
1080                 /* zoom in as required, or as far as we can go */
1081                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1082         }
1083
1084         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1085         
1086         return OPERATOR_FINISHED;
1087 }
1088 static int view3d_border_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
1089 {
1090         ScrArea *sa= CTX_wm_area(C);
1091         View3D *v3d= sa->spacedata.first;
1092         
1093         /* if in camera view do not exec the operator so we do not conflict with set render border*/
1094         if (v3d->persp != V3D_CAMOB) return WM_border_select_invoke(C, op, event);      
1095         else return OPERATOR_PASS_THROUGH;
1096 }
1097 void VIEW3D_OT_border_zoom(wmOperatorType *ot)
1098 {
1099         
1100         /* identifiers */
1101         ot->name= "Border Zoom";
1102         ot->idname= "VIEW3D_OT_border_zoom";
1103
1104         /* api callbacks */
1105         ot->invoke= view3d_border_zoom_invoke;
1106         ot->exec= view3d_border_zoom_exec;
1107         ot->modal= WM_border_select_modal;
1108         
1109         ot->poll= ED_operator_view3d_active;
1110         
1111         /* rna */
1112         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1113         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1114         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1115         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1116
1117 }
1118 /* ********************* Changing view operator ****************** */
1119
1120 static EnumPropertyItem prop_view_items[] = {
1121         {V3D_VIEW_FRONT, "FRONT", "Front", "View From the Front"},
1122         {V3D_VIEW_BACK, "BACK", "Back", "View From the Back"},
1123         {V3D_VIEW_LEFT, "LEFT", "Left", "View From the Left"},
1124         {V3D_VIEW_RIGHT, "RIGHT", "Right", "View From the Right"},
1125         {V3D_VIEW_TOP, "TOP", "Top", "View From the Top"},
1126         {V3D_VIEW_BOTTOM, "BOTTOM", "Bottom", "View From the Bottom"},
1127         {V3D_VIEW_PERSPORTHO, "PERSPORTHO", "Persp-Ortho", "Switch between Perspecive and Orthographic View"},
1128         {V3D_VIEW_CAMERA, "CAMERA", "Camera", "View From the active amera"},
1129         {V3D_VIEW_STEPLEFT, "STEPLEFT", "Step Left", "Step the view around to the Left"},
1130         {V3D_VIEW_STEPRIGHT, "STEPRIGHT", "Step Right", "Step the view around to the Right"},
1131         {V3D_VIEW_STEPUP, "STEPUP", "Step Up", "Step the view Up"},
1132         {V3D_VIEW_STEPDOWN, "STEPDOWN", "Step Down", "Step the view Down"},
1133         {V3D_VIEW_PANLEFT, "PANLEFT", "Pan Left", "Pan the view to the Left"},
1134         {V3D_VIEW_PANRIGHT, "PANRIGHT", "Pan Right", "Pan the view to the Right"},
1135         {V3D_VIEW_PANUP, "PANUP", "Pan Up", "Pan the view Up"},
1136         {V3D_VIEW_PANDOWN, "PANDOWN", "Pan Down", "Pan the view Down"},
1137         {0, NULL, NULL, NULL}};
1138
1139 static void axis_set_view(bContext *C, View3D *v3d, float q1, float q2, float q3, float q4, short view, int perspo)
1140 {
1141         float new_quat[4];
1142         new_quat[0]= q1; new_quat[1]= q2;
1143         new_quat[2]= q3; new_quat[3]= q4;
1144         v3d->view=0;
1145
1146         v3d->view= view;
1147         
1148         if (v3d->persp==V3D_CAMOB && v3d->camera) {
1149
1150                 if (U.uiflag & USER_AUTOPERSP) v3d->persp= V3D_ORTHO;
1151                 else if(v3d->persp==V3D_CAMOB) v3d->persp= perspo;
1152
1153                 smooth_view(C, v3d->camera, NULL, v3d->ofs, new_quat, NULL, NULL); 
1154         } 
1155         else {
1156
1157                 if (U.uiflag & USER_AUTOPERSP) v3d->persp= V3D_ORTHO;
1158                 else if(v3d->persp==V3D_CAMOB) v3d->persp= perspo;
1159
1160                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1161         }
1162
1163 }
1164
1165
1166 static int viewnumpad_exec(bContext *C, wmOperator *op)
1167 {
1168         ScrArea *sa= CTX_wm_area(C);
1169         ARegion *ar= CTX_wm_region(C);
1170         View3D *v3d= sa->spacedata.first;
1171         Scene *scene= CTX_data_scene(C);
1172         float phi, si, q1[4], vec[3];
1173         static int perspo=V3D_PERSP;
1174         int viewnum;
1175
1176         viewnum = RNA_enum_get(op->ptr, "view");
1177
1178         /* Use this to test if we started out with a camera */
1179
1180         /* Indicate that this view is inverted,
1181          * but only if it actually _was_ inverted (jobbe) */
1182         if (viewnum == V3D_VIEW_BOTTOM || viewnum == V3D_VIEW_BACK || viewnum == V3D_VIEW_LEFT)
1183                 v3d->flag2 |= V3D_OPP_DIRECTION_NAME;
1184         else if (viewnum != V3D_VIEW_PERSPORTHO)
1185                         v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME;
1186
1187         switch (viewnum) {
1188                 case V3D_VIEW_BOTTOM :
1189                         axis_set_view(C, v3d, 0.0, -1.0, 0.0, 0.0, 7, perspo);
1190                         break;
1191
1192                 case V3D_VIEW_BACK:
1193                         axis_set_view(C, v3d, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), 1, perspo);
1194                         break;
1195
1196                 case V3D_VIEW_LEFT:
1197                         axis_set_view(C, v3d, 0.5, -0.5, 0.5, 0.5, 3, perspo);
1198                         break;
1199
1200                 case V3D_VIEW_TOP:
1201                         axis_set_view(C, v3d, 1.0, 0.0, 0.0, 0.0, 7, perspo);
1202                         break;
1203
1204                 case V3D_VIEW_FRONT:
1205                         axis_set_view(C, v3d, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, 1, perspo);
1206                         break;
1207
1208                 case V3D_VIEW_RIGHT:
1209                         axis_set_view(C, v3d, 0.5, -0.5, -0.5, -0.5, 3, perspo);
1210                         break;
1211
1212                 case V3D_VIEW_PERSPORTHO:
1213
1214                         if(v3d->persp!=V3D_ORTHO) 
1215                                 v3d->persp=V3D_ORTHO;
1216                         else v3d->persp=V3D_PERSP;
1217
1218                         ED_region_tag_redraw(ar);
1219                         break;
1220
1221                 case V3D_VIEW_CAMERA:
1222                         /* lastview -  */
1223
1224                         if(v3d->persp != V3D_CAMOB) {
1225                                 /* store settings of current view before allowing overwriting with camera view */
1226                                 QUATCOPY(v3d->lviewquat, v3d->viewquat);
1227                                 v3d->lview= v3d->view;
1228                                 v3d->lpersp= v3d->persp;
1229                                 
1230 #if 0
1231                                 if(G.qual==LR_ALTKEY) {
1232                                         if(oldcamera && is_an_active_object(oldcamera)) {
1233                                                 v3d->camera= oldcamera;
1234                                         }
1235                                         handle_view3d_lock();
1236                                 }
1237 #endif
1238                                 
1239                                 if(BASACT) {
1240                                         /* check both G.vd as G.scene cameras */
1241                                         if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1242                                                 v3d->camera= OBACT;
1243                                                 /*handle_view3d_lock();*/
1244                                         }
1245                                 }
1246                                 
1247                                 if(v3d->camera==NULL) {
1248                                         v3d->camera= scene_find_camera(scene);
1249                                         /*handle_view3d_lock();*/
1250                                 }
1251                                 v3d->persp= V3D_CAMOB;
1252                                 smooth_view(C, NULL, v3d->camera, v3d->ofs, v3d->viewquat, &v3d->dist, &v3d->lens);
1253                                 
1254                         }
1255                         else{
1256                                 /* return to settings of last view */
1257                                 /* does smooth_view too */
1258                                 axis_set_view(C, v3d, v3d->lviewquat[0], v3d->lviewquat[1], v3d->lviewquat[2], v3d->lviewquat[3], v3d->lview, v3d->lpersp);
1259                         }
1260                         break;
1261
1262                 case V3D_VIEW_STEPLEFT:
1263                 case V3D_VIEW_STEPRIGHT:
1264                 case V3D_VIEW_STEPUP:
1265                 case V3D_VIEW_STEPDOWN:
1266
1267                         if(v3d->persp != V3D_CAMOB) {
1268                                 if(viewnum == V3D_VIEW_STEPLEFT || viewnum == V3D_VIEW_STEPRIGHT) {
1269                                         /* z-axis */
1270                                         phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1271                                         if(viewnum == V3D_VIEW_STEPRIGHT) phi= -phi;
1272                                         si= (float)sin(phi);
1273                                         q1[0]= (float)cos(phi);
1274                                         q1[1]= q1[2]= 0.0;
1275                                         q1[3]= si;
1276                                         QuatMul(v3d->viewquat, v3d->viewquat, q1);
1277                                         v3d->view= 0;
1278                                 }
1279                                 if(viewnum == V3D_VIEW_STEPDOWN || viewnum == V3D_VIEW_STEPUP) {
1280                                         /* horizontal axis */
1281                                         VECCOPY(q1+1, v3d->viewinv[0]);
1282
1283                                         Normalize(q1+1);
1284                                         phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1285                                         if(viewnum == V3D_VIEW_STEPDOWN) phi= -phi;
1286                                         si= (float)sin(phi);
1287                                         q1[0]= (float)cos(phi);
1288                                         q1[1]*= si;
1289                                         q1[2]*= si;
1290                                         q1[3]*= si;
1291                                         QuatMul(v3d->viewquat, v3d->viewquat, q1);
1292                                         v3d->view= 0;
1293                                 }
1294                                 ED_region_tag_redraw(ar);
1295                         }
1296                         break;
1297
1298                 case V3D_VIEW_PANRIGHT:
1299                 case V3D_VIEW_PANLEFT:
1300                 case V3D_VIEW_PANUP:
1301                 case V3D_VIEW_PANDOWN:
1302
1303                         initgrabz(v3d, 0.0, 0.0, 0.0);
1304
1305                         if(viewnum == V3D_VIEW_PANRIGHT) window_to_3d(ar, v3d, vec, -32, 0);
1306                         else if(viewnum == V3D_VIEW_PANLEFT) window_to_3d(ar, v3d, vec, 32, 0);
1307                         else if(viewnum == V3D_VIEW_PANUP) window_to_3d(ar, v3d, vec, 0, -25);
1308                         else if(viewnum == V3D_VIEW_PANDOWN) window_to_3d(ar, v3d, vec, 0, 25);
1309                         v3d->ofs[0]+= vec[0];
1310                         v3d->ofs[1]+= vec[1];
1311                         v3d->ofs[2]+= vec[2];
1312
1313                         ED_region_tag_redraw(ar);
1314                         break;
1315
1316                 default :
1317                         break;
1318         }
1319
1320         if(v3d->persp != V3D_CAMOB) perspo= v3d->persp;
1321
1322         return OPERATOR_FINISHED;
1323 }
1324
1325
1326 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1327 {
1328         /* identifiers */
1329         ot->name= "View numpad";
1330         ot->idname= "VIEW3D_OT_viewnumpad";
1331
1332         /* api callbacks */
1333         ot->exec= viewnumpad_exec;
1334         ot->poll= ED_operator_view3d_active;
1335         ot->flag= OPTYPE_REGISTER;
1336
1337         RNA_def_enum(ot->srna, "view", prop_view_items, 0, "View", "");
1338 }
1339
1340 /* ********************* set clipping operator ****************** */
1341
1342 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1343 {
1344         ScrArea *sa= CTX_wm_area(C);
1345         View3D *v3d= sa->spacedata.first;
1346         rcti rect;
1347         double mvmatrix[16];
1348         double projmatrix[16];
1349         double xs, ys, p[3];
1350         GLint viewport[4];
1351         short val;
1352
1353         rect.xmin= RNA_int_get(op->ptr, "xmin");
1354         rect.ymin= RNA_int_get(op->ptr, "ymin");
1355         rect.xmax= RNA_int_get(op->ptr, "xmax");
1356         rect.ymax= RNA_int_get(op->ptr, "ymax");
1357
1358         v3d->flag |= V3D_CLIPPING;
1359         v3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1360
1361         /* note; otherwise opengl won't work */
1362         view3d_operator_needs_opengl(C);
1363
1364         /* Get the matrices needed for gluUnProject */
1365         glGetIntegerv(GL_VIEWPORT, viewport);
1366         glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
1367         glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
1368
1369         /* near zero floating point values can give issues with gluUnProject
1370                 in side view on some implementations */
1371         if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
1372         if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
1373
1374         /* Set up viewport so that gluUnProject will give correct values */
1375         viewport[0] = 0;
1376         viewport[1] = 0;
1377
1378         /* four clipping planes and bounding volume */
1379         /* first do the bounding volume */
1380         for(val=0; val<4; val++) {
1381
1382                 xs= (val==0||val==3)?rect.xmin:rect.xmax;
1383                 ys= (val==0||val==1)?rect.ymin:rect.ymax;
1384
1385                 gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1386                 VECCOPY(v3d->clipbb->vec[val], p);
1387
1388                 gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1389                 VECCOPY(v3d->clipbb->vec[4+val], p);
1390         }
1391
1392         /* then plane equations */
1393         for(val=0; val<4; val++) {
1394
1395                 CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
1396                                           v3d->clip[val]);
1397
1398                 v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0]
1399                         - v3d->clip[val][1]*v3d->clipbb->vec[val][1]
1400                         - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
1401         }
1402         return OPERATOR_FINISHED;
1403 }
1404
1405 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
1406 {
1407         ScrArea *sa= CTX_wm_area(C);
1408         View3D *v3d= sa->spacedata.first;
1409
1410         if(v3d->flag & V3D_CLIPPING) {
1411                 v3d->flag &= ~V3D_CLIPPING;
1412                 ED_area_tag_redraw(sa);
1413                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
1414                 v3d->clipbb= NULL;
1415                 return OPERATOR_FINISHED;
1416         }
1417         else {
1418                 return WM_border_select_invoke(C, op, event);
1419         }
1420 }
1421
1422 /* toggles */
1423 void VIEW3D_OT_clipping(wmOperatorType *ot)
1424 {
1425
1426         /* identifiers */
1427         ot->name= "Border Select";
1428         ot->idname= "VIEW3D_OT_clipping";
1429
1430         /* api callbacks */
1431         ot->invoke= view3d_clipping_invoke;
1432         ot->exec= view3d_clipping_exec;
1433         ot->modal= WM_border_select_modal;
1434
1435         ot->poll= ED_operator_view3d_active;
1436
1437         /* rna */
1438         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1439         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1440         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1441         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1442 }
1443
1444 /* ********************* draw type operator ****************** */
1445
1446 static int view3d_drawtype_exec(bContext *C, wmOperator *op)
1447 {
1448         ScrArea *sa= CTX_wm_area(C);
1449         View3D *v3d= sa->spacedata.first;
1450         int dt, dt_alt;
1451
1452         dt  = RNA_int_get(op->ptr, "draw_type");
1453         dt_alt = RNA_int_get(op->ptr, "draw_type_alternate");
1454         
1455         if (dt_alt != -1)
1456         {
1457                 if (v3d->drawtype == dt)
1458                 {
1459                         v3d->drawtype = dt_alt;
1460                 }
1461                 else
1462                 {
1463                         v3d->drawtype = dt;
1464                 }
1465         }
1466         else
1467         {
1468                 v3d->drawtype = dt;
1469         }
1470
1471         ED_area_tag_redraw(sa);
1472         
1473         return OPERATOR_FINISHED;
1474 }
1475
1476 static int view3d_drawtype_invoke(bContext *C, wmOperator *op, wmEvent *event)
1477 {
1478         return view3d_drawtype_exec(C, op);
1479 }
1480
1481 /* toggles */
1482 void VIEW3D_OT_drawtype(wmOperatorType *ot)
1483 {
1484         /* identifiers */
1485         ot->name= "Change draw type";
1486         ot->idname= "VIEW3D_OT_drawtype";
1487
1488         /* api callbacks */
1489         ot->invoke= view3d_drawtype_invoke;
1490         ot->exec= view3d_drawtype_exec;
1491
1492         ot->poll= ED_operator_view3d_active;
1493
1494         /* rna XXX should become enum */
1495         RNA_def_int(ot->srna, "draw_type", 0, INT_MIN, INT_MAX, "Draw Type", "", INT_MIN, INT_MAX);
1496         RNA_def_int(ot->srna, "draw_type_alternate", -1, INT_MIN, INT_MAX, "Draw Type Alternate", "", INT_MIN, INT_MAX);
1497 }
1498
1499 /* ***************** 3d cursor cursor op ******************* */
1500
1501 /* mx my in region coords */
1502 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
1503 {
1504         Scene *scene= CTX_data_scene(C);
1505         ARegion *ar= CTX_wm_region(C);
1506         View3D *v3d= CTX_wm_view3d(C);
1507         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
1508         short mx, my, mval[2];
1509 //      short ctrl= 0; // XXX
1510         
1511         fp= give_cursor(scene, v3d);
1512         
1513 //      if(obedit && ctrl) lr_click= 1;
1514         VECCOPY(oldcurs, fp);
1515         
1516         mx= event->x - ar->winrct.xmin;
1517         my= event->y - ar->winrct.ymin;
1518         project_short_noclip(ar, v3d, fp, mval);
1519         
1520         initgrabz(v3d, fp[0], fp[1], fp[2]);
1521         
1522         if(mval[0]!=IS_CLIPPED) {
1523                 
1524                 window_to_3d(ar, v3d, dvec, mval[0]-mx, mval[1]-my);
1525                 VecSubf(fp, fp, dvec);
1526         }
1527         else {
1528                 
1529                 dx= ((float)(mx-(ar->winx/2)))*v3d->zfac/(ar->winx/2);
1530                 dy= ((float)(my-(ar->winy/2)))*v3d->zfac/(ar->winy/2);
1531                 
1532                 fz= v3d->persmat[0][3]*fp[0]+ v3d->persmat[1][3]*fp[1]+ v3d->persmat[2][3]*fp[2]+ v3d->persmat[3][3];
1533                 fz= fz/v3d->zfac;
1534                 
1535                 fp[0]= (v3d->persinv[0][0]*dx + v3d->persinv[1][0]*dy+ v3d->persinv[2][0]*fz)-v3d->ofs[0];
1536                 fp[1]= (v3d->persinv[0][1]*dx + v3d->persinv[1][1]*dy+ v3d->persinv[2][1]*fz)-v3d->ofs[1];
1537                 fp[2]= (v3d->persinv[0][2]*dx + v3d->persinv[1][2]*dy+ v3d->persinv[2][2]*fz)-v3d->ofs[2];
1538         }
1539         
1540 //      if(lr_click) {
1541                 // XXX          if(obedit->type==OB_MESH) add_click_mesh();
1542                 //              else if ELEM(obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
1543                 //              else if (obedit->type==OB_ARMATURE) addvert_armature();
1544 //              VECCOPY(fp, oldcurs);
1545 //      }
1546         // XXX notifier for scene */
1547         ED_region_tag_redraw(ar);
1548         
1549         /* prevent other mouse ops to fail */
1550         return OPERATOR_PASS_THROUGH;
1551 }
1552
1553 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
1554 {
1555         
1556         /* identifiers */
1557         ot->name= "Set 3D Cursor";
1558         ot->idname= "VIEW3D_OT_cursor3d";
1559         
1560         /* api callbacks */
1561         ot->invoke= set_3dcursor_invoke;
1562         
1563         ot->poll= ED_operator_view3d_active;
1564         
1565         /* rna later */
1566
1567 }
1568
1569
1570 /* ************************* below the line! *********************** */
1571
1572
1573 /* XXX todo Zooms in on a border drawn by the user */
1574 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
1575 {
1576         rcti rect;
1577         /* ZBuffer depth vars */
1578         bglMats mats;
1579         float depth, depth_close= MAXFLOAT;
1580         int had_depth = 0;
1581         double cent[2],  p[3];
1582         int xs, ys;
1583
1584         // XXX          getmouseco_areawin(mval);
1585
1586         // XXX  persp(PERSP_VIEW);
1587
1588         rect.xmax = mval[0] + 4;
1589         rect.ymax = mval[1] + 4;
1590
1591         rect.xmin = mval[0] - 4;
1592         rect.ymin = mval[1] - 4;
1593
1594         /* Get Z Depths, needed for perspective, nice for ortho */
1595         bgl_get_mats(&mats);
1596         draw_depth(scene, ar, v3d, NULL);
1597
1598         /* force updating */
1599         if (v3d->depths) {
1600                 had_depth = 1;
1601                 v3d->depths->damaged = 1;
1602         }
1603
1604         view3d_update_depths(ar, v3d);
1605
1606         /* Constrain rect to depth bounds */
1607         if (rect.xmin < 0) rect.xmin = 0;
1608         if (rect.ymin < 0) rect.ymin = 0;
1609         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1610         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;
1611
1612         /* Find the closest Z pixel */
1613         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1614                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1615                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1616                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1617                                 if (depth_close > depth) {
1618                                         depth_close = depth;
1619                                 }
1620                         }
1621                 }
1622         }
1623
1624         if (depth_close==MAXFLOAT)
1625                 return 0;
1626
1627         if (had_depth==0) {
1628                 MEM_freeN(v3d->depths->depths);
1629                 v3d->depths->depths = NULL;
1630         }
1631         v3d->depths->damaged = 1;
1632
1633         cent[0] = (double)mval[0];
1634         cent[1] = (double)mval[1];
1635
1636         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
1637                 return 0;
1638
1639         mouse_worldloc[0] = (float)p[0];
1640         mouse_worldloc[1] = (float)p[1];
1641         mouse_worldloc[2] = (float)p[2];
1642         return 1;
1643 }
1644
1645
1646
1647 /* ********************* NDOF ************************ */
1648 /* note: this code is confusing and unclear... (ton) */
1649 /* **************************************************** */
1650
1651 // ndof scaling will be moved to user setting.
1652 // In the mean time this is just a place holder.
1653
1654 // Note: scaling in the plugin and ghostwinlay.c
1655 // should be removed. With driver default setting,
1656 // each axis returns approx. +-200 max deflection.
1657
1658 // The values I selected are based on the older
1659 // polling i/f. With event i/f, the sensistivity
1660 // can be increased for improved response from
1661 // small deflections of the device input.
1662
1663
1664 // lukep notes : i disagree on the range.
1665 // the normal 3Dconnection driver give +/-400
1666 // on defaut range in other applications
1667 // and up to +/- 1000 if set to maximum
1668 // because i remove the scaling by delta,
1669 // which was a bad idea as it depend of the system
1670 // speed and os, i changed the scaling values, but
1671 // those are still not ok
1672
1673
1674 float ndof_axis_scale[6] = {
1675         +0.01,  // Tx
1676         +0.01,  // Tz
1677         +0.01,  // Ty
1678         +0.0015,        // Rx
1679         +0.0015,        // Rz
1680         +0.0015 // Ry
1681 };
1682
1683 void filterNDOFvalues(float *sbval)
1684 {
1685         int i=0;
1686         float max  = 0.0;
1687
1688         for (i =0; i<6;i++)
1689                 if (fabs(sbval[i]) > max)
1690                         max = fabs(sbval[i]);
1691         for (i =0; i<6;i++)
1692                 if (fabs(sbval[i]) != max )
1693                         sbval[i]=0.0;
1694 }
1695
1696 // statics for controlling v3d->dist corrections.
1697 // viewmoveNDOF zeros and adjusts v3d->ofs.
1698 // viewmove restores based on dz_flag state.
1699
1700 int dz_flag = 0;
1701 float m_dist;
1702
1703 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
1704 {
1705     int i;
1706     float phi;
1707     float dval[7];
1708         // static fval[6] for low pass filter; device input vector is dval[6]
1709         static float fval[6];
1710     float tvec[3],rvec[3];
1711     float q1[4];
1712         float mat[3][3];
1713         float upvec[3];
1714
1715
1716     /*----------------------------------------------------
1717          * sometimes this routine is called from headerbuttons
1718      * viewmove needs to refresh the screen
1719      */
1720 // XXX  areawinset(ar->win);
1721
1722
1723         // fetch the current state of the ndof device
1724 // XXX  getndof(dval);
1725
1726         if (v3d->ndoffilter)
1727                 filterNDOFvalues(fval);
1728
1729         // Scale input values
1730
1731 //      if(dval[6] == 0) return; // guard against divide by zero
1732
1733         for(i=0;i<6;i++) {
1734
1735                 // user scaling
1736                 dval[i] = dval[i] * ndof_axis_scale[i];
1737         }
1738
1739
1740         // low pass filter with zero crossing reset
1741
1742         for(i=0;i<6;i++) {
1743                 if((dval[i] * fval[i]) >= 0)
1744                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
1745                 else
1746                         fval[i] = 0;
1747         }
1748
1749
1750         // force perspective mode. This is a hack and is
1751         // incomplete. It doesn't actually effect the view
1752         // until the first draw and doesn't update the menu
1753         // to reflect persp mode.
1754
1755         v3d->persp = V3D_PERSP;
1756
1757
1758         // Correct the distance jump if v3d->dist != 0
1759
1760         // This is due to a side effect of the original
1761         // mouse view rotation code. The rotation point is
1762         // set a distance in front of the viewport to
1763         // make rotating with the mouse look better.
1764         // The distance effect is written at a low level
1765         // in the view management instead of the mouse
1766         // view function. This means that all other view
1767         // movement devices must subtract this from their
1768         // view transformations.
1769
1770         if(v3d->dist != 0.0) {
1771                 dz_flag = 1;
1772                 m_dist = v3d->dist;
1773                 upvec[0] = upvec[1] = 0;
1774                 upvec[2] = v3d->dist;
1775                 Mat3CpyMat4(mat, v3d->viewinv);
1776                 Mat3MulVecfl(mat, upvec);
1777                 VecSubf(v3d->ofs, v3d->ofs, upvec);
1778                 v3d->dist = 0.0;
1779         }
1780
1781
1782         // Apply rotation
1783         // Rotations feel relatively faster than translations only in fly mode, so
1784         // we have no choice but to fix that here (not in the plugins)
1785         rvec[0] = -0.5 * dval[3];
1786         rvec[1] = -0.5 * dval[4];
1787         rvec[2] = -0.5 * dval[5];
1788
1789         // rotate device x and y by view z
1790
1791         Mat3CpyMat4(mat, v3d->viewinv);
1792         mat[2][2] = 0.0f;
1793         Mat3MulVecfl(mat, rvec);
1794
1795         // rotate the view
1796
1797         phi = Normalize(rvec);
1798         if(phi != 0) {
1799                 VecRotToQuat(rvec,phi,q1);
1800                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
1801         }
1802
1803
1804         // Apply translation
1805
1806         tvec[0] = dval[0];
1807         tvec[1] = dval[1];
1808         tvec[2] = -dval[2];
1809
1810         // the next three lines rotate the x and y translation coordinates
1811         // by the current z axis angle
1812
1813         Mat3CpyMat4(mat, v3d->viewinv);
1814         mat[2][2] = 0.0f;
1815         Mat3MulVecfl(mat, tvec);
1816
1817         // translate the view
1818
1819         VecSubf(v3d->ofs, v3d->ofs, tvec);
1820
1821
1822         /*----------------------------------------------------
1823      * refresh the screen XXX
1824       */
1825
1826         // update render preview window
1827
1828 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
1829 }
1830
1831 void viewmoveNDOF(Scene *scene, View3D *v3d, int mode)
1832 {
1833     float fval[7];
1834     float dvec[3];
1835     float sbadjust = 1.0f;
1836     float len;
1837         short use_sel = 0;
1838         Object *ob = OBACT;
1839     float m[3][3];
1840     float m_inv[3][3];
1841     float xvec[3] = {1,0,0};
1842     float yvec[3] = {0,-1,0};
1843     float zvec[3] = {0,0,1};
1844         float phi, si;
1845     float q1[4];
1846     float obofs[3];
1847     float reverse;
1848     //float diff[4];
1849     float d, curareaX, curareaY;
1850     float mat[3][3];
1851     float upvec[3];
1852
1853     /* Sensitivity will control how fast the view rotates.  The value was
1854      * obtained experimentally by tweaking until the author didn't get dizzy watching.
1855      * Perhaps this should be a configurable user parameter.
1856      */
1857     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
1858     float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
1859     float zsens = 0.3f;   /* zoom sensitivity */
1860
1861     const float minZoom = -30.0f;
1862     const float maxZoom = 300.0f;
1863
1864         //reset view type
1865         v3d->view = 0;
1866 //printf("passing here \n");
1867 //
1868         if (scene->obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1869                 use_sel = 1;
1870         }
1871
1872     if((dz_flag)||v3d->dist==0) {
1873                 dz_flag = 0;
1874                 v3d->dist = m_dist;
1875                 upvec[0] = upvec[1] = 0;
1876                 upvec[2] = v3d->dist;
1877                 Mat3CpyMat4(mat, v3d->viewinv);
1878                 Mat3MulVecfl(mat, upvec);
1879                 VecAddf(v3d->ofs, v3d->ofs, upvec);
1880         }
1881
1882     /*----------------------------------------------------
1883          * sometimes this routine is called from headerbuttons
1884      * viewmove needs to refresh the screen
1885      */
1886 // XXX  areawinset(curarea->win);
1887
1888     /*----------------------------------------------------
1889      * record how much time has passed. clamp at 10 Hz
1890      * pretend the previous frame occured at the clamped time
1891      */
1892 //    now = PIL_check_seconds_timer();
1893  //   frametime = (now - prevTime);
1894  //   if (frametime > 0.1f){        /* if more than 1/10s */
1895  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
1896 //    }
1897 //    prevTime = now;
1898  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
1899
1900     /* fetch the current state of the ndof device & enforce dominant mode if selected */
1901 // XXX    getndof(fval);
1902         if (v3d->ndoffilter)
1903                 filterNDOFvalues(fval);
1904
1905
1906     // put scaling back here, was previously in ghostwinlay
1907     fval[0] = fval[0] * (1.0f/600.0f);
1908     fval[1] = fval[1] * (1.0f/600.0f);
1909     fval[2] = fval[2] * (1.0f/1100.0f);
1910     fval[3] = fval[3] * 0.00005f;
1911     fval[4] =-fval[4] * 0.00005f;
1912     fval[5] = fval[5] * 0.00005f;
1913     fval[6] = fval[6] / 1000000.0f;
1914
1915     // scale more if not in perspective mode
1916     if (v3d->persp == V3D_ORTHO) {
1917         fval[0] = fval[0] * 0.05f;
1918         fval[1] = fval[1] * 0.05f;
1919         fval[2] = fval[2] * 0.05f;
1920         fval[3] = fval[3] * 0.9f;
1921         fval[4] = fval[4] * 0.9f;
1922         fval[5] = fval[5] * 0.9f;
1923         zsens *= 8;
1924     }
1925
1926
1927     /* set object offset */
1928         if (ob) {
1929                 obofs[0] = -ob->obmat[3][0];
1930                 obofs[1] = -ob->obmat[3][1];
1931                 obofs[2] = -ob->obmat[3][2];
1932         }
1933         else {
1934                 VECCOPY(obofs, v3d->ofs);
1935         }
1936
1937     /* calc an adjustment based on distance from camera
1938        disabled per patch 14402 */
1939      d = 1.0f;
1940
1941 /*    if (ob) {
1942         VecSubf(diff, obofs, v3d->ofs);
1943         d = VecLength(diff);
1944     }
1945 */
1946
1947     reverse = (v3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1948
1949     /*----------------------------------------------------
1950      * ndof device pan
1951      */
1952     psens *= 1.0f + d;
1953     curareaX = sbadjust * psens * fval[0];
1954     curareaY = sbadjust * psens * fval[1];
1955     dvec[0] = curareaX * v3d->persinv[0][0] + curareaY * v3d->persinv[1][0];
1956     dvec[1] = curareaX * v3d->persinv[0][1] + curareaY * v3d->persinv[1][1];
1957     dvec[2] = curareaX * v3d->persinv[0][2] + curareaY * v3d->persinv[1][2];
1958     VecAddf(v3d->ofs, v3d->ofs, dvec);
1959
1960     /*----------------------------------------------------
1961      * ndof device dolly
1962      */
1963     len = zsens * sbadjust * fval[2];
1964
1965     if (v3d->persp==V3D_CAMOB) {
1966         if(v3d->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1967             v3d->camzoom+= 10.0f * -len;
1968         }
1969         if (v3d->camzoom < minZoom) v3d->camzoom = minZoom;
1970         else if (v3d->camzoom > maxZoom) v3d->camzoom = maxZoom;
1971     }
1972     else if ((v3d->dist> 0.001*v3d->grid) && (v3d->dist<10.0*v3d->far)) {
1973         v3d->dist*=(1.0 + len);
1974     }
1975
1976
1977     /*----------------------------------------------------
1978      * ndof device turntable
1979      * derived from the turntable code in viewmove
1980      */
1981
1982     /* Get the 3x3 matrix and its inverse from the quaternion */
1983     QuatToMat3(v3d->viewquat, m);
1984     Mat3Inv(m_inv,m);
1985
1986     /* Determine the direction of the x vector (for rotating up and down) */
1987     /* This can likely be compuated directly from the quaternion. */
1988     Mat3MulVecfl(m_inv,xvec);
1989     Mat3MulVecfl(m_inv,yvec);
1990     Mat3MulVecfl(m_inv,zvec);
1991
1992     /* Perform the up/down rotation */
1993     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1994     si = sin(phi);
1995     q1[0] = cos(phi);
1996     q1[1] = si * xvec[0];
1997     q1[2] = si * xvec[1];
1998     q1[3] = si * xvec[2];
1999     QuatMul(v3d->viewquat, v3d->viewquat, q1);
2000
2001     if (use_sel) {
2002         QuatConj(q1); /* conj == inv for unit quat */
2003         VecSubf(v3d->ofs, v3d->ofs, obofs);
2004         QuatMulVecf(q1, v3d->ofs);
2005         VecAddf(v3d->ofs, v3d->ofs, obofs);
2006     }
2007
2008     /* Perform the orbital rotation */
2009     /* Perform the orbital rotation
2010        If the seen Up axis is parallel to the zoom axis, rotation should be
2011        achieved with a pure Roll motion (no Spin) on the device. When you start
2012        to tilt, moving from Top to Side view, Spinning will increasingly become
2013        more relevant while the Roll component will decrease. When a full
2014        Side view is reached, rotations around the world's Up axis are achieved
2015        with a pure Spin-only motion.  In other words the control of the spinning
2016        around the world's Up axis should move from the device's Spin axis to the
2017        device's Roll axis depending on the orientation of the world's Up axis
2018        relative to the screen. */
2019     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
2020     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
2021     q1[0] = cos(phi);
2022     q1[1] = q1[2] = 0.0;
2023     q1[3] = sin(phi);
2024     QuatMul(v3d->viewquat, v3d->viewquat, q1);
2025
2026     if (use_sel) {
2027         QuatConj(q1);
2028         VecSubf(v3d->ofs, v3d->ofs, obofs);
2029         QuatMulVecf(q1, v3d->ofs);
2030         VecAddf(v3d->ofs, v3d->ofs, obofs);
2031     }
2032
2033     /*----------------------------------------------------
2034      * refresh the screen
2035      */
2036 // XXX    scrarea_do_windraw(curarea);
2037 }
2038
2039
2040
2041