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