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