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