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