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