2.5
[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_scene.h"
58 #include "BKE_screen.h"
59 #include "BKE_utildefines.h"
60
61 #include "RE_pipeline.h"        // make_stars
62
63 #include "BIF_gl.h"
64 #include "BIF_retopo.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68
69 #include "RNA_access.h"
70 #include "RNA_define.h"
71
72 #include "ED_screen.h"
73 #include "ED_types.h"
74
75 #include "UI_interface.h"
76 #include "UI_resources.h"
77 #include "UI_view2d.h"
78
79 #include "PIL_time.h" /* smoothview */
80
81 #include "view3d_intern.h"      // own include
82
83 /* ********************** view3d_edit: view manipulations ********************* */
84
85 /* ************************** init for view ops **********************************/
86
87 typedef struct ViewOpsData {
88         ARegion *ar;
89         View3D *v3d;
90
91         float oldquat[4];
92         float trackvec[3];
93         float ofs[3], obofs[3];
94         float reverse, dist0;
95
96         int origx, origy, oldx, oldy;
97         int origkey;
98
99 } ViewOpsData;
100
101 #define TRACKBALLSIZE  (1.1)
102
103 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
104 {
105         float x, y, radius, d, z, t;
106
107         radius= TRACKBALLSIZE;
108
109         /* normalize x and y */
110         x= (rect->xmax + rect->xmin)/2 - mx;
111         x/= (float)((rect->xmax - rect->xmin)/4);
112         y= (rect->ymax + rect->ymin)/2 - my;
113         y/= (float)((rect->ymax - rect->ymin)/2);
114
115         d = sqrt(x*x + y*y);
116         if (d < radius*M_SQRT1_2)       /* Inside sphere */
117                 z = sqrt(radius*radius - d*d);
118         else
119         {                       /* On hyperbola */
120                 t = radius / M_SQRT2;
121                 z = t*t / d;
122         }
123
124         vec[0]= x;
125         vec[1]= y;
126         vec[2]= -z;             /* yah yah! */
127 }
128
129
130 static void viewops_data(bContext *C, wmOperator *op, wmEvent *event)
131 {
132         ScrArea *sa= CTX_wm_area(C);
133         View3D *v3d= sa->spacedata.first;
134         ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
135
136         /* store data */
137         op->customdata= vod;
138         vod->ar= CTX_wm_region(C);
139         vod->v3d= v3d;
140         vod->dist0= v3d->dist;
141         QUATCOPY(vod->oldquat, v3d->viewquat);
142         vod->origx= vod->oldx= event->x;
143         vod->origy= vod->oldy= event->y;
144         vod->origkey= event->type;
145
146         calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
147
148         initgrabz(v3d, -v3d->ofs[0], -v3d->ofs[1], -v3d->ofs[2]);
149
150         vod->reverse= 1.0f;
151         if (v3d->persmat[2][1] < 0.0f)
152                 vod->reverse= -1.0f;
153
154 }
155
156 /* ************************** viewrotate **********************************/
157
158 static const float thres = 0.93f; //cos(20 deg);
159
160 #define COS45 0.70710678118654746
161 #define SIN45 COS45
162
163 static float snapquats[39][6] = {
164         /*{q0, q1, q3, q4, view, oposite_direction}*/
165 {COS45, -SIN45, 0.0, 0.0, 1, 0},  //front
166 {0.0, 0.0, -SIN45, -SIN45, 1, 1}, //back
167 {1.0, 0.0, 0.0, 0.0, 7, 0},       //top
168 {0.0, -1.0, 0.0, 0.0, 7, 1},      //bottom
169 {0.5, -0.5, -0.5, -0.5, 3, 0},    //left
170 {0.5, -0.5, 0.5, 0.5, 3, 1},      //right
171
172         /* some more 45 deg snaps */
173 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
174 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
175 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
176 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
177 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
178 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
179 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
180 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
181 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
182 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
183 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
184 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
185 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
186 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
187 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
188 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
189 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
190 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
191 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
192 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
193 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
194 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
195 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
196 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
197 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
198 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
199 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
200 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
201 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
202 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
203 {-COS45, 0.0, 0.0, SIN45, 0, 0},
204 {COS45, 0.0, 0.0, SIN45, 0, 0},
205 {0.0, 0.0, 0.0, 1.0, 0, 0}
206 };
207
208
209 static void viewrotate_apply(ViewOpsData *vod, int x, int y, int ctrl)
210 {
211         View3D *v3d= vod->v3d;
212         int use_sel= 0; /* XXX */
213
214         v3d->view= 0; /* need to reset everytime because of view snapping */
215
216         if (U.flag & USER_TRACKBALL) {
217                 float phi, si, q1[4], dvec[3], newvec[3];
218
219                 calctrackballvec(&vod->ar->winrct, x, y, newvec);
220
221                 VecSubf(dvec, newvec, vod->trackvec);
222
223                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
224                 si/= (2.0*TRACKBALLSIZE);
225
226                 Crossf(q1+1, vod->trackvec, newvec);
227                 Normalize(q1+1);
228
229                 /* Allow for rotation beyond the interval
230                         * [-pi, pi] */
231                 while (si > 1.0)
232                         si -= 2.0;
233
234                 /* This relation is used instead of
235                         * phi = asin(si) so that the angle
236                         * of rotation is linearly proportional
237                         * to the distance that the mouse is
238                         * dragged. */
239                 phi = si * M_PI / 2.0;
240
241                 si= sin(phi);
242                 q1[0]= cos(phi);
243                 q1[1]*= si;
244                 q1[2]*= si;
245                 q1[3]*= si;
246                 QuatMul(v3d->viewquat, q1, vod->oldquat);
247
248                 if (use_sel) {
249                         /* compute the post multiplication quat, to rotate the offset correctly */
250                         QUATCOPY(q1, vod->oldquat);
251                         QuatConj(q1);
252                         QuatMul(q1, q1, v3d->viewquat);
253
254                         QuatConj(q1); /* conj == inv for unit quat */
255                         VECCOPY(v3d->ofs, vod->ofs);
256                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
257                         QuatMulVecf(q1, v3d->ofs);
258                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
259                 }
260         }
261         else {
262                 /* New turntable view code by John Aughey */
263                 float si, phi, q1[4];
264                 float m[3][3];
265                 float m_inv[3][3];
266                 float xvec[3] = {1,0,0};
267                 /* Sensitivity will control how fast the viewport rotates.  0.0035 was
268                         obtained experimentally by looking at viewport rotation sensitivities
269                         on other modeling programs. */
270                 /* Perhaps this should be a configurable user parameter. */
271                 const float sensitivity = 0.0035;
272
273                 /* Get the 3x3 matrix and its inverse from the quaternion */
274                 QuatToMat3(v3d->viewquat, m);
275                 Mat3Inv(m_inv,m);
276
277                 /* Determine the direction of the x vector (for rotating up and down) */
278                 /* This can likely be compuated directly from the quaternion. */
279                 Mat3MulVecfl(m_inv,xvec);
280
281                 /* Perform the up/down rotation */
282                 phi = sensitivity * -(y - vod->oldy);
283                 si = sin(phi);
284                 q1[0] = cos(phi);
285                 q1[1] = si * xvec[0];
286                 q1[2] = si * xvec[1];
287                 q1[3] = si * xvec[2];
288                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
289
290                 if (use_sel) {
291                         QuatConj(q1); /* conj == inv for unit quat */
292                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
293                         QuatMulVecf(q1, v3d->ofs);
294                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
295                 }
296
297                 /* Perform the orbital rotation */
298                 phi = sensitivity * vod->reverse * (x - vod->oldx);
299                 q1[0] = cos(phi);
300                 q1[1] = q1[2] = 0.0;
301                 q1[3] = sin(phi);
302                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
303
304                 if (use_sel) {
305                         QuatConj(q1);
306                         VecSubf(v3d->ofs, v3d->ofs, vod->obofs);
307                         QuatMulVecf(q1, v3d->ofs);
308                         VecAddf(v3d->ofs, v3d->ofs, vod->obofs);
309                 }
310         }
311
312         /* check for view snap */
313         if (ctrl){
314                 int i;
315                 float viewmat[3][3];
316
317
318                 QuatToMat3(v3d->viewquat, viewmat);
319
320                 for (i = 0 ; i < 39; i++){
321                         float snapmat[3][3];
322                         float view = (int)snapquats[i][4];
323                         float oposite_dir = (int)snapquats[i][5];
324
325                         QuatToMat3(snapquats[i], snapmat);
326
327                         if ((Inpf(snapmat[0], viewmat[0]) > thres) &&
328                                 (Inpf(snapmat[1], viewmat[1]) > thres) &&
329                                 (Inpf(snapmat[2], viewmat[2]) > thres)){
330
331                                 QUATCOPY(v3d->viewquat, snapquats[i]);
332
333                                 v3d->view = view;
334                                 if (view){
335                                         if (oposite_dir){
336                                                 v3d->flag2 |= V3D_OPP_DIRECTION_NAME;
337                                         }else{
338                                                 v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME;
339                                         }
340                                 }
341
342                                 break;
343                         }
344                 }
345         }
346         vod->oldx= x;
347         vod->oldy= y;
348
349         ED_region_tag_redraw(vod->ar);
350 }
351
352 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
353 {
354         ViewOpsData *vod= op->customdata;
355
356         /* execute the events */
357         switch(event->type) {
358                 case MOUSEMOVE:
359                         viewrotate_apply(vod, event->x, event->y, event->ctrl);
360                         break;
361
362                 default:
363                         if(event->type==vod->origkey && event->val==0) {
364
365                                 MEM_freeN(vod);
366                                 op->customdata= NULL;
367
368                                 return OPERATOR_FINISHED;
369                         }
370         }
371
372         return OPERATOR_RUNNING_MODAL;
373 }
374
375 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
376 {
377         ViewOpsData *vod;
378
379         /* makes op->customdata */
380         viewops_data(C, op, event);
381         vod= op->customdata;
382
383         /* switch from camera view when: */
384         if(vod->v3d->persp != V3D_PERSP) {
385
386                 if (U.uiflag & USER_AUTOPERSP)
387                         vod->v3d->persp= V3D_PERSP;
388                 else if(vod->v3d->persp==V3D_CAMOB)
389                         vod->v3d->persp= V3D_PERSP;
390                 ED_region_tag_redraw(vod->ar);
391         }
392
393         /* add temp handler */
394         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
395
396         return OPERATOR_RUNNING_MODAL;
397 }
398
399
400 void VIEW3D_OT_viewrotate(wmOperatorType *ot)
401 {
402
403         /* identifiers */
404         ot->name= "Rotate view";
405         ot->idname= "VIEW3D_OT_viewrotate";
406
407         /* api callbacks */
408         ot->invoke= viewrotate_invoke;
409         ot->modal= viewrotate_modal;
410         ot->poll= ED_operator_areaactive;
411 }
412
413 /* ************************ viewmove ******************************** */
414
415 static void viewmove_apply(ViewOpsData *vod, int x, int y)
416 {
417         if(vod->v3d->persp==V3D_CAMOB) {
418                 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
419
420                 vod->v3d->camdx += (vod->oldx - x)/(max);
421                 vod->v3d->camdy += (vod->oldy - y)/(max);
422                 CLAMP(vod->v3d->camdx, -1.0f, 1.0f);
423                 CLAMP(vod->v3d->camdy, -1.0f, 1.0f);
424 // XXX          preview3d_event= 0;
425         }
426         else {
427                 float dvec[3];
428
429                 window_to_3d(vod->ar, vod->v3d, dvec, x-vod->oldx, y-vod->oldy);
430                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, dvec);
431         }
432
433         vod->oldx= x;
434         vod->oldy= y;
435
436         ED_region_tag_redraw(vod->ar);
437 }
438
439
440 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
441 {
442         ViewOpsData *vod= op->customdata;
443
444         /* execute the events */
445         switch(event->type) {
446                 case MOUSEMOVE:
447                         viewmove_apply(vod, event->x, event->y);
448                         break;
449
450                 default:
451                         if(event->type==vod->origkey && event->val==0) {
452
453                                 MEM_freeN(vod);
454                                 op->customdata= NULL;
455
456                                 return OPERATOR_FINISHED;
457                         }
458         }
459
460         return OPERATOR_RUNNING_MODAL;
461 }
462
463 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
464 {
465         /* makes op->customdata */
466         viewops_data(C, op, event);
467
468         /* add temp handler */
469         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
470
471         return OPERATOR_RUNNING_MODAL;
472 }
473
474
475 void VIEW3D_OT_viewmove(wmOperatorType *ot)
476 {
477
478         /* identifiers */
479         ot->name= "Rotate view";
480         ot->idname= "VIEW3D_OT_viewmove";
481
482         /* api callbacks */
483         ot->invoke= viewmove_invoke;
484         ot->modal= viewmove_modal;
485         ot->poll= ED_operator_areaactive;
486 }
487
488 /* ************************ viewzoom ******************************** */
489
490 static void view_zoom_mouseloc(ARegion *ar, View3D *v3d, float dfac, int mx, int my)
491 {
492         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
493                 float dvec[3];
494                 float tvec[3];
495                 float tpos[3];
496                 float new_dist;
497                 short vb[2], mouseloc[2];
498
499                 mouseloc[0]= mx - ar->winrct.xmin;
500                 mouseloc[1]= my - ar->winrct.ymin;
501
502                 /* find the current window width and height */
503                 vb[0] = ar->winx;
504                 vb[1] = ar->winy;
505
506                 tpos[0] = -v3d->ofs[0];
507                 tpos[1] = -v3d->ofs[1];
508                 tpos[2] = -v3d->ofs[2];
509
510                 /* Project cursor position into 3D space */
511                 initgrabz(v3d, tpos[0], tpos[1], tpos[2]);
512                 window_to_3d(ar, v3d, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
513
514                 /* Calculate view target position for dolly */
515                 tvec[0] = -(tpos[0] + dvec[0]);
516                 tvec[1] = -(tpos[1] + dvec[1]);
517                 tvec[2] = -(tpos[2] + dvec[2]);
518
519                 /* Offset to target position and dolly */
520                 new_dist = v3d->dist * dfac;
521
522                 VECCOPY(v3d->ofs, tvec);
523                 v3d->dist = new_dist;
524
525                 /* Calculate final offset */
526                 dvec[0] = tvec[0] + dvec[0] * dfac;
527                 dvec[1] = tvec[1] + dvec[1] * dfac;
528                 dvec[2] = tvec[2] + dvec[2] * dfac;
529
530                 VECCOPY(v3d->ofs, dvec);
531         } else {
532                 v3d->dist *= dfac;
533         }
534 }
535
536
537 static void viewzoom_apply(ViewOpsData *vod, int x, int y)
538 {
539         float zfac=1.0;
540
541         if(U.viewzoom==USER_ZOOM_CONT) {
542                 // oldstyle zoom
543                 zfac = 1.0+(float)(vod->origx - x + vod->origy - y)/1000.0;
544         }
545         else if(U.viewzoom==USER_ZOOM_SCALE) {
546                 int ctr[2], len1, len2;
547                 // method which zooms based on how far you move the mouse
548
549                 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
550                 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
551
552                 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
553                 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
554
555                 zfac = vod->dist0 * ((float)len2/len1) / vod->v3d->dist;
556         }
557         else {  /* USER_ZOOM_DOLLY */
558                 float len1 = (vod->ar->winrct.ymax - y) + 5;
559                 float len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
560                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->v3d->dist;
561         }
562
563         if(zfac != 1.0 && zfac*vod->v3d->dist > 0.001*vod->v3d->grid &&
564                                 zfac*vod->v3d->dist < 10.0*vod->v3d->far)
565                 view_zoom_mouseloc(vod->ar, vod->v3d, zfac, vod->oldx, vod->oldy);
566
567
568         if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->v3d->persp==V3D_PERSP)) {
569                 float upvec[3], mat[3][3];
570
571                 /* Secret apricot feature, translate the view when in continues mode */
572                 upvec[0] = upvec[1] = 0.0f;
573                 upvec[2] = (vod->dist0 - vod->v3d->dist) * vod->v3d->grid;
574                 vod->v3d->dist = vod->dist0;
575                 Mat3CpyMat4(mat, vod->v3d->viewinv);
576                 Mat3MulVecfl(mat, upvec);
577                 VecAddf(vod->v3d->ofs, vod->v3d->ofs, upvec);
578         } else {
579                 /* these limits are in toets.c too */
580                 if(vod->v3d->dist<0.001*vod->v3d->grid) vod->v3d->dist= 0.001*vod->v3d->grid;
581                 if(vod->v3d->dist>10.0*vod->v3d->far) vod->v3d->dist=10.0*vod->v3d->far;
582         }
583
584 // XXX  if(vod->v3d->persp==V3D_ORTHO || vod->v3d->persp==V3D_CAMOB) preview3d_event= 0;
585
586         ED_region_tag_redraw(vod->ar);
587 }
588
589
590 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
591 {
592         ViewOpsData *vod= op->customdata;
593
594         /* execute the events */
595         switch(event->type) {
596                 case MOUSEMOVE:
597                         viewzoom_apply(vod, event->x, event->y);
598                         break;
599
600                 default:
601                         if(event->type==vod->origkey && event->val==0) {
602
603                                 MEM_freeN(vod);
604                                 op->customdata= NULL;
605
606                                 return OPERATOR_FINISHED;
607                         }
608         }
609
610         return OPERATOR_RUNNING_MODAL;
611 }
612
613 static int viewzoom_exec(bContext *C, wmOperator *op)
614 {
615         ScrArea *sa= CTX_wm_area(C);
616         View3D *v3d= sa->spacedata.first;
617         int delta= RNA_int_get(op->ptr, "delta");
618
619         if(delta < 0) {
620                 /* this min and max is also in viewmove() */
621                 if(v3d->persp==V3D_CAMOB) {
622                         v3d->camzoom-= 10;
623                         if(v3d->camzoom<-30) v3d->camzoom= -30;
624                 }
625                 else if(v3d->dist<10.0*v3d->far) v3d->dist*=1.2f;
626         }
627         else {
628                 if(v3d->persp==V3D_CAMOB) {
629                         v3d->camzoom+= 10;
630                         if(v3d->camzoom>300) v3d->camzoom= 300;
631                 }
632                 else if(v3d->dist> 0.001*v3d->grid) v3d->dist*=.83333f;
633         }
634
635         ED_region_tag_redraw(CTX_wm_region(C));
636
637         return OPERATOR_FINISHED;
638 }
639
640 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
641 {
642         int delta= RNA_int_get(op->ptr, "delta");
643
644         if(delta) {
645                 viewzoom_exec(C, op);
646         }
647         else {
648                 /* makes op->customdata */
649                 viewops_data(C, op, event);
650
651                 /* add temp handler */
652                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
653
654                 return OPERATOR_RUNNING_MODAL;
655         }
656         return OPERATOR_FINISHED;
657 }
658
659
660 void VIEW3D_OT_viewzoom(wmOperatorType *ot)
661 {
662
663         /* identifiers */
664         ot->name= "Rotate view";
665         ot->idname= "VIEW3D_OT_viewzoom";
666
667         /* api callbacks */
668         ot->invoke= viewzoom_invoke;
669         ot->exec= viewzoom_exec;
670         ot->modal= viewzoom_modal;
671         ot->poll= ED_operator_areaactive;
672
673         RNA_def_property(ot->srna, "delta", PROP_INT, PROP_NONE);
674 }
675
676 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
677 {
678         ScrArea *sa= CTX_wm_area(C);
679         ARegion *ar= CTX_wm_region(C);
680         View3D *v3d= sa->spacedata.first;
681         Scene *scene= CTX_data_scene(C);
682         Base *base;
683
684         int center= RNA_boolean_get(op->ptr, "center");
685
686         float size, min[3], max[3], afm[3];
687         int ok= 1, onedone=0;
688
689         if(center) {
690                 min[0]= min[1]= min[2]= 0.0f;
691                 max[0]= max[1]= max[2]= 0.0f;
692         }
693         else {
694                 INIT_MINMAX(min, max);
695         }
696
697         for(base= scene->base.first; base; base= base->next) {
698                 if(base->lay & v3d->lay) {
699                         onedone= 1;
700                         minmax_object(base->object, min, max);
701                 }
702         }
703         if(!onedone) return OPERATOR_FINISHED; /* TODO - should this be cancel? */
704
705         afm[0]= (max[0]-min[0]);
706         afm[1]= (max[1]-min[1]);
707         afm[2]= (max[2]-min[2]);
708         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
709         if(size==0.0) ok= 0;
710
711         if(ok) {
712                 float new_dist;
713                 float new_ofs[3];
714
715                 new_dist = size;
716                 new_ofs[0]= -(min[0]+max[0])/2.0f;
717                 new_ofs[1]= -(min[1]+max[1])/2.0f;
718                 new_ofs[2]= -(min[2]+max[2])/2.0f;
719
720                 // correction for window aspect ratio
721                 if(ar->winy>2 && ar->winx>2) {
722                         size= (float)ar->winx/(float)ar->winy;
723                         if(size<1.0) size= 1.0f/size;
724                         new_dist*= size;
725                 }
726
727                 if (v3d->persp==V3D_CAMOB) {
728                         v3d->persp= V3D_PERSP;
729                         smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL); 
730                 }
731         }
732 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
733
734         return OPERATOR_FINISHED;
735 }
736
737 void VIEW3D_OT_viewhome(wmOperatorType *ot)
738 {
739
740         /* identifiers */
741         ot->name= "View home";
742         ot->idname= "VIEW3D_OT_viewhome";
743
744         /* api callbacks */
745         ot->exec= viewhome_exec;
746         ot->poll= ED_operator_areaactive;
747
748         RNA_def_property(ot->srna, "center", PROP_BOOLEAN, PROP_NONE);
749 }
750
751 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
752 {
753         ScrArea *sa= CTX_wm_area(C);
754         ARegion *ar= CTX_wm_region(C);
755         View3D *v3d= sa->spacedata.first;
756         Scene *scene= CTX_data_scene(C);
757         Object *ob= OBACT;
758         float size, min[3], max[3], afm[3];
759         int ok=0;
760
761         /* SMOOTHVIEW */
762         float new_ofs[3];
763         float new_dist;
764
765         INIT_MINMAX(min, max);
766
767         if (G.f & G_WEIGHTPAINT) {
768                 /* hardcoded exception, we look for the one selected armature */
769                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
770                 Base *base;
771                 for(base=scene->base.first; base; base= base->next) {
772                         if(TESTBASELIB(v3d, base)) {
773                                 if(base->object->type==OB_ARMATURE)
774                                         if(base->object->flag & OB_POSEMODE)
775                                                 break;
776                         }
777                 }
778                 if(base)
779                         ob= base->object;
780         }
781
782
783         if(G.obedit) {
784 // XXX          ok = minmax_verts(min, max);    /* only selected */
785         }
786         else if(ob && (ob->flag & OB_POSEMODE)) {
787                 if(ob->pose) {
788                         bArmature *arm= ob->data;
789                         bPoseChannel *pchan;
790                         float vec[3];
791
792                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
793                                 if(pchan->bone->flag & BONE_SELECTED) {
794                                         if(pchan->bone->layer & arm->layer) {
795                                                 ok= 1;
796                                                 VECCOPY(vec, pchan->pose_head);
797                                                 Mat4MulVecfl(ob->obmat, vec);
798                                                 DO_MINMAX(vec, min, max);
799                                                 VECCOPY(vec, pchan->pose_tail);
800                                                 Mat4MulVecfl(ob->obmat, vec);
801                                                 DO_MINMAX(vec, min, max);
802                                         }
803                                 }
804                         }
805                 }
806         }
807         else if (FACESEL_PAINT_TEST) {
808 // XXX          ok= minmax_tface(min, max);
809         }
810         else if (G.f & G_PARTICLEEDIT) {
811 // XXX          ok= PE_minmax(min, max);
812         }
813         else {
814                 Base *base= FIRSTBASE;
815                 while(base) {
816                         if(TESTBASE(v3d, base))  {
817                                 minmax_object(base->object, min, max);
818                                 /* account for duplis */
819                                 minmax_object_duplis(base->object, min, max);
820
821                                 ok= 1;
822                         }
823                         base= base->next;
824                 }
825         }
826
827         if(ok==0) return OPERATOR_FINISHED;
828
829         afm[0]= (max[0]-min[0]);
830         afm[1]= (max[1]-min[1]);
831         afm[2]= (max[2]-min[2]);
832         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
833
834         if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
835
836         new_ofs[0]= -(min[0]+max[0])/2.0f;
837         new_ofs[1]= -(min[1]+max[1])/2.0f;
838         new_ofs[2]= -(min[2]+max[2])/2.0f;
839
840         new_dist = size;
841
842         /* correction for window aspect ratio */
843         if(ar->winy>2 && ar->winx>2) {
844                 size= (float)ar->winx/(float)ar->winy;
845                 if(size<1.0f) size= 1.0f/size;
846                 new_dist*= size;
847         }
848
849         v3d->cursor[0]= -new_ofs[0];
850         v3d->cursor[1]= -new_ofs[1];
851         v3d->cursor[2]= -new_ofs[2];
852
853         if (v3d->persp==V3D_CAMOB) {
854                 v3d->persp= V3D_PERSP;
855                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
856         } 
857         else {
858                 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
859         }
860
861 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
862
863         return OPERATOR_FINISHED;
864 }
865 void VIEW3D_OT_viewcenter(wmOperatorType *ot)
866 {
867
868         /* identifiers */
869         ot->name= "View center";
870         ot->idname= "VIEW3D_OT_viewcenter";
871
872         /* api callbacks */
873         ot->exec= viewcenter_exec;
874         ot->poll= ED_operator_areaactive;
875 }
876
877 /* ********************* Changing view operator ****************** */
878
879 static EnumPropertyItem prop_view_items[] = {
880         {V3D_VIEW_FRONT, "FRONT", "Front", "View From the Front"},
881         {V3D_VIEW_BACK, "BACK", "Back", "View From the Back"},
882         {V3D_VIEW_LEFT, "LEFT", "Left", "View From the Left"},
883         {V3D_VIEW_RIGHT, "RIGHT", "Right", "View From the Right"},
884         {V3D_VIEW_TOP, "TOP", "Top", "View From the Top"},
885         {V3D_VIEW_BOTTOM, "BOTTOM", "Bottom", "View From the Bottom"},
886         {V3D_VIEW_PERSPORTHO, "PERSPORTHO", "Persp-Ortho", "Switch between Perspecive and Orthographic View"},
887         {V3D_VIEW_CAMERA, "CAMERA", "Camera", "View From the active amera"},
888         {V3D_VIEW_STEPLEFT, "STEPLEFT", "Step Left", "Step the view around to the Left"},
889         {V3D_VIEW_STEPRIGHT, "STEPRIGHT", "Step Right", "Step the view around to the Right"},
890         {V3D_VIEW_STEPUP, "STEPUP", "Step Up", "Step the view Up"},
891         {V3D_VIEW_STEPDOWN, "STEPDOWN", "Step Down", "Step the view Down"},
892         {V3D_VIEW_PANLEFT, "PANLEFT", "Pan Left", "Pan the view to the Left"},
893         {V3D_VIEW_PANRIGHT, "PANRIGHT", "Pan Right", "Pan the view to the Right"},
894         {V3D_VIEW_PANUP, "PANUP", "Pan Up", "Pan the view Up"},
895         {V3D_VIEW_PANDOWN, "PANDOWN", "Pan Down", "Pan the view Down"},
896         {0, NULL, NULL, NULL}};
897
898 static void axis_set_view(bContext *C, View3D *v3d, float q1, float q2, float q3, float q4, short view, int perspo)
899 {
900         float new_quat[4];
901         new_quat[0]= q1; new_quat[1]= q2;
902         new_quat[2]= q3; new_quat[3]= q4;
903         v3d->view=0;
904
905         v3d->view= view;
906         
907         if (v3d->persp==V3D_CAMOB && v3d->camera) {
908
909                 if (U.uiflag & USER_AUTOPERSP) v3d->persp= V3D_ORTHO;
910                 else if(v3d->persp==V3D_CAMOB) v3d->persp= perspo;
911
912                 smooth_view(C, v3d->camera, NULL, v3d->ofs, new_quat, NULL, NULL); 
913         } 
914         else {
915
916                 if (U.uiflag & USER_AUTOPERSP) v3d->persp= V3D_ORTHO;
917                 else if(v3d->persp==V3D_CAMOB) v3d->persp= perspo;
918
919                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
920         }
921
922 }
923
924
925 static int viewnumpad_exec(bContext *C, wmOperator *op)
926 {
927         ScrArea *sa= CTX_wm_area(C);
928         ARegion *ar= CTX_wm_region(C);
929         View3D *v3d= sa->spacedata.first;
930         Scene *scene= CTX_data_scene(C);
931         float phi, si, q1[4], vec[3];
932         static int perspo=V3D_PERSP;
933         int viewnum;
934
935         viewnum = RNA_enum_get(op->ptr, "viewnum");
936
937         /* Use this to test if we started out with a camera */
938
939         /* Indicate that this view is inverted,
940          * but only if it actually _was_ inverted (jobbe) */
941         if (viewnum == V3D_VIEW_BOTTOM || viewnum == V3D_VIEW_BACK || viewnum == V3D_VIEW_LEFT)
942                 v3d->flag2 |= V3D_OPP_DIRECTION_NAME;
943         else if (viewnum != V3D_VIEW_PERSPORTHO)
944                         v3d->flag2 &= ~V3D_OPP_DIRECTION_NAME;
945
946         switch (viewnum) {
947                 case V3D_VIEW_BOTTOM :
948                         axis_set_view(C, v3d, 0.0, -1.0, 0.0, 0.0, 7, perspo);
949                         break;
950
951                 case V3D_VIEW_BACK:
952                         axis_set_view(C, v3d, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), 1, perspo);
953                         break;
954
955                 case V3D_VIEW_LEFT:
956                         axis_set_view(C, v3d, 0.5, -0.5, 0.5, 0.5, 3, perspo);
957                         break;
958
959                 case V3D_VIEW_TOP:
960                         axis_set_view(C, v3d, 1.0, 0.0, 0.0, 0.0, 7, perspo);
961                         break;
962
963                 case V3D_VIEW_FRONT:
964                         axis_set_view(C, v3d, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, 1, perspo);
965                         break;
966
967                 case V3D_VIEW_RIGHT:
968                         axis_set_view(C, v3d, 0.5, -0.5, -0.5, -0.5, 3, perspo);
969                         break;
970
971                 case V3D_VIEW_PERSPORTHO:
972
973                         if(v3d->persp!=V3D_ORTHO) 
974                                 v3d->persp=V3D_ORTHO;
975                         else v3d->persp=V3D_PERSP;
976
977                         ED_region_tag_redraw(ar);
978                         break;
979
980                 case V3D_VIEW_CAMERA:
981                         /* lastview -  */
982
983                         if(v3d->persp != V3D_CAMOB) {
984                                 /* store settings of current view before allowing overwriting with camera view */
985                                 QUATCOPY(v3d->lviewquat, v3d->viewquat);
986                                 v3d->lview= v3d->view;
987                                 v3d->lpersp= v3d->persp;
988                                 
989 #if 0
990                                 if(G.qual==LR_ALTKEY) {
991                                         if(oldcamera && is_an_active_object(oldcamera)) {
992                                                 v3d->camera= oldcamera;
993                                         }
994                                         handle_view3d_lock();
995                                 }
996 #endif
997                                 
998                                 if(BASACT) {
999                                         /* check both G.vd as G.scene cameras */
1000                                         if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1001                                                 v3d->camera= OBACT;
1002                                                 /*handle_view3d_lock();*/
1003                                         }
1004                                 }
1005                                 
1006                                 if(v3d->camera==NULL) {
1007                                         v3d->camera= scene_find_camera(scene);
1008                                         /*handle_view3d_lock();*/
1009                                 }
1010                                 v3d->persp= V3D_CAMOB;
1011                                 smooth_view(C, NULL, v3d->camera, v3d->ofs, v3d->viewquat, &v3d->dist, &v3d->lens);
1012                                 
1013                         }
1014                         else{
1015                                 /* return to settings of last view */
1016                                 /* does smooth_view too */
1017                                 axis_set_view(C, v3d, v3d->lviewquat[0], v3d->lviewquat[1], v3d->lviewquat[2], v3d->lviewquat[3], v3d->lview, v3d->lpersp);
1018                         }
1019                         break;
1020
1021                 case V3D_VIEW_STEPLEFT:
1022                 case V3D_VIEW_STEPRIGHT:
1023                 case V3D_VIEW_STEPUP:
1024                 case V3D_VIEW_STEPDOWN:
1025
1026                         if(v3d->persp != V3D_CAMOB) {
1027                                 if(viewnum == V3D_VIEW_STEPLEFT || viewnum == V3D_VIEW_STEPRIGHT) {
1028                                         /* z-axis */
1029                                         phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1030                                         if(viewnum == V3D_VIEW_STEPRIGHT) phi= -phi;
1031                                         si= (float)sin(phi);
1032                                         q1[0]= (float)cos(phi);
1033                                         q1[1]= q1[2]= 0.0;
1034                                         q1[3]= si;
1035                                         QuatMul(v3d->viewquat, v3d->viewquat, q1);
1036                                         v3d->view= 0;
1037                                 }
1038                                 if(viewnum == V3D_VIEW_STEPDOWN || viewnum == V3D_VIEW_STEPUP) {
1039                                         /* horizontal axis */
1040                                         VECCOPY(q1+1, v3d->viewinv[0]);
1041
1042                                         Normalize(q1+1);
1043                                         phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1044                                         if(viewnum == V3D_VIEW_STEPDOWN) phi= -phi;
1045                                         si= (float)sin(phi);
1046                                         q1[0]= (float)cos(phi);
1047                                         q1[1]*= si;
1048                                         q1[2]*= si;
1049                                         q1[3]*= si;
1050                                         QuatMul(v3d->viewquat, v3d->viewquat, q1);
1051                                         v3d->view= 0;
1052                                 }
1053                                 ED_region_tag_redraw(ar);
1054                         }
1055                         break;
1056
1057                 case V3D_VIEW_PANRIGHT:
1058                 case V3D_VIEW_PANLEFT:
1059                 case V3D_VIEW_PANUP:
1060                 case V3D_VIEW_PANDOWN:
1061
1062                         initgrabz(v3d, 0.0, 0.0, 0.0);
1063
1064                         if(viewnum == V3D_VIEW_PANRIGHT) window_to_3d(ar, v3d, vec, -32, 0);
1065                         else if(viewnum == V3D_VIEW_PANLEFT) window_to_3d(ar, v3d, vec, 32, 0);
1066                         else if(viewnum == V3D_VIEW_PANUP) window_to_3d(ar, v3d, vec, 0, -25);
1067                         else if(viewnum == V3D_VIEW_PANDOWN) window_to_3d(ar, v3d, vec, 0, 25);
1068                         v3d->ofs[0]+= vec[0];
1069                         v3d->ofs[1]+= vec[1];
1070                         v3d->ofs[2]+= vec[2];
1071
1072                         ED_region_tag_redraw(ar);
1073                         break;
1074
1075                 default :
1076                         break;
1077         }
1078
1079         if(v3d->persp != V3D_CAMOB) perspo= v3d->persp;
1080
1081         return OPERATOR_FINISHED;
1082 }
1083
1084
1085 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1086 {
1087
1088         PropertyRNA *prop;
1089
1090         /* identifiers */
1091         ot->name= "View numpad";
1092         ot->idname= "VIEW3D_OT_viewnumpad";
1093
1094         /* api callbacks */
1095         ot->exec= viewnumpad_exec;
1096         ot->poll= ED_operator_areaactive;
1097         ot->flag= OPTYPE_REGISTER;
1098
1099         prop = RNA_def_property(ot->srna, "viewnum", PROP_ENUM, PROP_NONE);
1100         RNA_def_property_enum_items(prop, prop_view_items);
1101 }
1102
1103 /* ********************* set clipping operator ****************** */
1104
1105 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1106 {
1107         ScrArea *sa= CTX_wm_area(C);
1108         View3D *v3d= sa->spacedata.first;
1109         rcti rect;
1110         double mvmatrix[16];
1111         double projmatrix[16];
1112         double xs, ys, p[3];
1113         GLint viewport[4];
1114         short val;
1115
1116         rect.xmin= RNA_int_get(op->ptr, "xmin");
1117         rect.ymin= RNA_int_get(op->ptr, "ymin");
1118         rect.xmax= RNA_int_get(op->ptr, "xmax");
1119         rect.ymax= RNA_int_get(op->ptr, "ymax");
1120
1121         v3d->flag |= V3D_CLIPPING;
1122         v3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1123
1124         /* note; otherwise opengl won't work */
1125         view3d_operator_needs_opengl(C);
1126
1127         /* Get the matrices needed for gluUnProject */
1128         glGetIntegerv(GL_VIEWPORT, viewport);
1129         glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
1130         glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
1131
1132         /* near zero floating point values can give issues with gluUnProject
1133                 in side view on some implementations */
1134         if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
1135         if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
1136
1137         /* Set up viewport so that gluUnProject will give correct values */
1138         viewport[0] = 0;
1139         viewport[1] = 0;
1140
1141         /* four clipping planes and bounding volume */
1142         /* first do the bounding volume */
1143         for(val=0; val<4; val++) {
1144
1145                 xs= (val==0||val==3)?rect.xmin:rect.xmax;
1146                 ys= (val==0||val==1)?rect.ymin:rect.ymax;
1147
1148                 gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1149                 VECCOPY(v3d->clipbb->vec[val], p);
1150
1151                 gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
1152                 VECCOPY(v3d->clipbb->vec[4+val], p);
1153         }
1154
1155         /* then plane equations */
1156         for(val=0; val<4; val++) {
1157
1158                 CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
1159                                           v3d->clip[val]);
1160
1161                 v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0]
1162                         - v3d->clip[val][1]*v3d->clipbb->vec[val][1]
1163                         - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
1164         }
1165         return OPERATOR_FINISHED;
1166 }
1167
1168 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
1169 {
1170         ScrArea *sa= CTX_wm_area(C);
1171         View3D *v3d= sa->spacedata.first;
1172
1173         if(v3d->flag & V3D_CLIPPING) {
1174                 v3d->flag &= ~V3D_CLIPPING;
1175                 ED_area_tag_redraw(sa);
1176                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
1177                 v3d->clipbb= NULL;
1178                 return OPERATOR_FINISHED;
1179         }
1180         else {
1181                 return WM_border_select_invoke(C, op, event);
1182         }
1183 }
1184
1185 /* toggles */
1186 void VIEW3D_OT_clipping(wmOperatorType *ot)
1187 {
1188
1189         /* identifiers */
1190         ot->name= "Border Select";
1191         ot->idname= "VIEW3D_OT_clipping";
1192
1193         /* api callbacks */
1194         ot->invoke= view3d_clipping_invoke;
1195         ot->exec= view3d_clipping_exec;
1196         ot->modal= WM_border_select_modal;
1197
1198         ot->poll= ED_operator_areaactive;
1199
1200         /* rna */
1201         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1202         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1203         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1204         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1205 }
1206
1207 /* ********************************************************* */
1208
1209 void set_render_border(Scene *scene, ARegion *ar, View3D *v3d)
1210 {
1211         rcti rect;
1212         short val;
1213
1214         val= 0; // XXX get_border(&rect, 3);
1215         if(val) {
1216                 rctf vb;
1217
1218                 calc_viewborder(scene, ar, v3d, &vb);
1219
1220                 scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1221                 scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1222                 scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1223                 scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1224
1225                 CLAMP(scene->r.border.xmin, 0.0, 1.0);
1226                 CLAMP(scene->r.border.ymin, 0.0, 1.0);
1227                 CLAMP(scene->r.border.xmax, 0.0, 1.0);
1228                 CLAMP(scene->r.border.ymax, 0.0, 1.0);
1229
1230                 /* drawing a border surrounding the entire camera view switches off border rendering
1231                         * or the border covers no pixels */
1232                 if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1233                          scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1234                         (scene->r.border.xmin == scene->r.border.xmax ||
1235                          scene->r.border.ymin == scene->r.border.ymax ))
1236                 {
1237                         scene->r.mode &= ~R_BORDER;
1238                 } else {
1239                         scene->r.mode |= R_BORDER;
1240                 }
1241         }
1242 }
1243
1244 void view3d_border_zoom(Scene *scene, ARegion *ar, View3D *v3d)
1245 {
1246
1247         /* Zooms in on a border drawn by the user */
1248         rcti rect;
1249         short val;
1250         float dvec[3], vb[2], xscale, yscale, scale;
1251
1252
1253         /* SMOOTHVIEW */
1254         float new_dist;
1255         float new_ofs[3];
1256
1257         /* ZBuffer depth vars */
1258         bglMats mats;
1259         float depth, depth_close= MAXFLOAT;
1260         int had_depth = 0;
1261         double cent[2],  p[3];
1262         int xs, ys;
1263
1264         /* Get the border input */
1265         val = 0; // XXX get_border(&rect, 3);
1266         if(!val) return;
1267
1268         /* Get Z Depths, needed for perspective, nice for ortho */
1269         bgl_get_mats(&mats);
1270         draw_depth(scene, ar, v3d, NULL);
1271
1272         /* force updating */
1273         if (v3d->depths) {
1274                 had_depth = 1;
1275                 v3d->depths->damaged = 1;
1276         }
1277
1278         view3d_update_depths(ar, v3d);
1279
1280         /* Constrain rect to depth bounds */
1281         if (rect.xmin < 0) rect.xmin = 0;
1282         if (rect.ymin < 0) rect.ymin = 0;
1283         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1284         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;
1285
1286         /* Find the closest Z pixel */
1287         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1288                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1289                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1290                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1291                                 if (depth_close > depth) {
1292                                         depth_close = depth;
1293                                 }
1294                         }
1295                 }
1296         }
1297
1298         if (had_depth==0) {
1299                 MEM_freeN(v3d->depths->depths);
1300                 v3d->depths->depths = NULL;
1301         }
1302         v3d->depths->damaged = 1;
1303
1304         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1305         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1306
1307         if (v3d->persp==V3D_PERSP) {
1308                 double p_corner[3];
1309
1310                 /* no depths to use, we cant do anything! */
1311                 if (depth_close==MAXFLOAT)
1312                         return;
1313
1314                 /* convert border to 3d coordinates */
1315                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1316                         (       !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])))
1317                         return;
1318
1319                 dvec[0] = p[0]-p_corner[0];
1320                 dvec[1] = p[1]-p_corner[1];
1321                 dvec[2] = p[2]-p_corner[2];
1322
1323                 new_dist = VecLength(dvec);
1324                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1325
1326                 new_ofs[0] = -p[0];
1327                 new_ofs[1] = -p[1];
1328                 new_ofs[2] = -p[2];
1329
1330         } else { /* othographic */
1331                 /* find the current window width and height */
1332                 vb[0] = ar->winx;
1333                 vb[1] = ar->winy;
1334
1335                 new_dist = v3d->dist;
1336
1337                 /* convert the drawn rectangle into 3d space */
1338                 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1339                         new_ofs[0] = -p[0];
1340                         new_ofs[1] = -p[1];
1341                         new_ofs[2] = -p[2];
1342                 } else {
1343                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1344                         new_ofs[0] = v3d->ofs[0];
1345                         new_ofs[1] = v3d->ofs[1];
1346                         new_ofs[2] = v3d->ofs[2];
1347
1348                         initgrabz(v3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1349
1350                         window_to_3d(ar, v3d, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1351                         /* center the view to the center of the rectangle */
1352                         VecSubf(new_ofs, new_ofs, dvec);
1353                 }
1354
1355                 /* work out the ratios, so that everything selected fits when we zoom */
1356                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1357                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1358                 scale = (xscale >= yscale)?xscale:yscale;
1359
1360                 /* zoom in as required, or as far as we can go */
1361                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1362         }
1363
1364         smooth_view(NULL, NULL, NULL, new_ofs, NULL, &new_dist, NULL); // XXX
1365 }
1366
1367
1368
1369 /* ************************* below the line! *********************** */
1370
1371
1372 /* XXX todo Zooms in on a border drawn by the user */
1373 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
1374 {
1375         rcti rect;
1376         /* ZBuffer depth vars */
1377         bglMats mats;
1378         float depth, depth_close= MAXFLOAT;
1379         int had_depth = 0;
1380         double cent[2],  p[3];
1381         int xs, ys;
1382
1383         // XXX          getmouseco_areawin(mval);
1384
1385         // XXX  persp(PERSP_VIEW);
1386
1387         rect.xmax = mval[0] + 4;
1388         rect.ymax = mval[1] + 4;
1389
1390         rect.xmin = mval[0] - 4;
1391         rect.ymin = mval[1] - 4;
1392
1393         /* Get Z Depths, needed for perspective, nice for ortho */
1394         bgl_get_mats(&mats);
1395         draw_depth(scene, ar, v3d, NULL);
1396
1397         /* force updating */
1398         if (v3d->depths) {
1399                 had_depth = 1;
1400                 v3d->depths->damaged = 1;
1401         }
1402
1403         view3d_update_depths(ar, v3d);
1404
1405         /* Constrain rect to depth bounds */
1406         if (rect.xmin < 0) rect.xmin = 0;
1407         if (rect.ymin < 0) rect.ymin = 0;
1408         if (rect.xmax >= v3d->depths->w) rect.xmax = v3d->depths->w-1;
1409         if (rect.ymax >= v3d->depths->h) rect.ymax = v3d->depths->h-1;
1410
1411         /* Find the closest Z pixel */
1412         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1413                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1414                         depth= v3d->depths->depths[ys*v3d->depths->w+xs];
1415                         if(depth < v3d->depths->depth_range[1] && depth > v3d->depths->depth_range[0]) {
1416                                 if (depth_close > depth) {
1417                                         depth_close = depth;
1418                                 }
1419                         }
1420                 }
1421         }
1422
1423         if (depth_close==MAXFLOAT)
1424                 return 0;
1425
1426         if (had_depth==0) {
1427                 MEM_freeN(v3d->depths->depths);
1428                 v3d->depths->depths = NULL;
1429         }
1430         v3d->depths->damaged = 1;
1431
1432         cent[0] = (double)mval[0];
1433         cent[1] = (double)mval[1];
1434
1435         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
1436                 return 0;
1437
1438         mouse_worldloc[0] = (float)p[0];
1439         mouse_worldloc[1] = (float)p[1];
1440         mouse_worldloc[2] = (float)p[2];
1441         return 1;
1442 }
1443
1444
1445
1446 /* ********************* NDOF ************************ */
1447 /* note: this code is confusing and unclear... (ton) */
1448 /* **************************************************** */
1449
1450 // ndof scaling will be moved to user setting.
1451 // In the mean time this is just a place holder.
1452
1453 // Note: scaling in the plugin and ghostwinlay.c
1454 // should be removed. With driver default setting,
1455 // each axis returns approx. +-200 max deflection.
1456
1457 // The values I selected are based on the older
1458 // polling i/f. With event i/f, the sensistivity
1459 // can be increased for improved response from
1460 // small deflections of the device input.
1461
1462
1463 // lukep notes : i disagree on the range.
1464 // the normal 3Dconnection driver give +/-400
1465 // on defaut range in other applications
1466 // and up to +/- 1000 if set to maximum
1467 // because i remove the scaling by delta,
1468 // which was a bad idea as it depend of the system
1469 // speed and os, i changed the scaling values, but
1470 // those are still not ok
1471
1472
1473 float ndof_axis_scale[6] = {
1474         +0.01,  // Tx
1475         +0.01,  // Tz
1476         +0.01,  // Ty
1477         +0.0015,        // Rx
1478         +0.0015,        // Rz
1479         +0.0015 // Ry
1480 };
1481
1482 void filterNDOFvalues(float *sbval)
1483 {
1484         int i=0;
1485         float max  = 0.0;
1486
1487         for (i =0; i<6;i++)
1488                 if (fabs(sbval[i]) > max)
1489                         max = fabs(sbval[i]);
1490         for (i =0; i<6;i++)
1491                 if (fabs(sbval[i]) != max )
1492                         sbval[i]=0.0;
1493 }
1494
1495 // statics for controlling v3d->dist corrections.
1496 // viewmoveNDOF zeros and adjusts v3d->ofs.
1497 // viewmove restores based on dz_flag state.
1498
1499 int dz_flag = 0;
1500 float m_dist;
1501
1502 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
1503 {
1504     int i;
1505     float phi;
1506     float dval[7];
1507         // static fval[6] for low pass filter; device input vector is dval[6]
1508         static float fval[6];
1509     float tvec[3],rvec[3];
1510     float q1[4];
1511         float mat[3][3];
1512         float upvec[3];
1513
1514
1515     /*----------------------------------------------------
1516          * sometimes this routine is called from headerbuttons
1517      * viewmove needs to refresh the screen
1518      */
1519 // XXX  areawinset(ar->win);
1520
1521
1522         // fetch the current state of the ndof device
1523 // XXX  getndof(dval);
1524
1525         if (v3d->ndoffilter)
1526                 filterNDOFvalues(fval);
1527
1528         // Scale input values
1529
1530 //      if(dval[6] == 0) return; // guard against divide by zero
1531
1532         for(i=0;i<6;i++) {
1533
1534                 // user scaling
1535                 dval[i] = dval[i] * ndof_axis_scale[i];
1536         }
1537
1538
1539         // low pass filter with zero crossing reset
1540
1541         for(i=0;i<6;i++) {
1542                 if((dval[i] * fval[i]) >= 0)
1543                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
1544                 else
1545                         fval[i] = 0;
1546         }
1547
1548
1549         // force perspective mode. This is a hack and is
1550         // incomplete. It doesn't actually effect the view
1551         // until the first draw and doesn't update the menu
1552         // to reflect persp mode.
1553
1554         v3d->persp = V3D_PERSP;
1555
1556
1557         // Correct the distance jump if v3d->dist != 0
1558
1559         // This is due to a side effect of the original
1560         // mouse view rotation code. The rotation point is
1561         // set a distance in front of the viewport to
1562         // make rotating with the mouse look better.
1563         // The distance effect is written at a low level
1564         // in the view management instead of the mouse
1565         // view function. This means that all other view
1566         // movement devices must subtract this from their
1567         // view transformations.
1568
1569         if(v3d->dist != 0.0) {
1570                 dz_flag = 1;
1571                 m_dist = v3d->dist;
1572                 upvec[0] = upvec[1] = 0;
1573                 upvec[2] = v3d->dist;
1574                 Mat3CpyMat4(mat, v3d->viewinv);
1575                 Mat3MulVecfl(mat, upvec);
1576                 VecSubf(v3d->ofs, v3d->ofs, upvec);
1577                 v3d->dist = 0.0;
1578         }
1579
1580
1581         // Apply rotation
1582         // Rotations feel relatively faster than translations only in fly mode, so
1583         // we have no choice but to fix that here (not in the plugins)
1584         rvec[0] = -0.5 * dval[3];
1585         rvec[1] = -0.5 * dval[4];
1586         rvec[2] = -0.5 * dval[5];
1587
1588         // rotate device x and y by view z
1589
1590         Mat3CpyMat4(mat, v3d->viewinv);
1591         mat[2][2] = 0.0f;
1592         Mat3MulVecfl(mat, rvec);
1593
1594         // rotate the view
1595
1596         phi = Normalize(rvec);
1597         if(phi != 0) {
1598                 VecRotToQuat(rvec,phi,q1);
1599                 QuatMul(v3d->viewquat, v3d->viewquat, q1);
1600         }
1601
1602
1603         // Apply translation
1604
1605         tvec[0] = dval[0];
1606         tvec[1] = dval[1];
1607         tvec[2] = -dval[2];
1608
1609         // the next three lines rotate the x and y translation coordinates
1610         // by the current z axis angle
1611
1612         Mat3CpyMat4(mat, v3d->viewinv);
1613         mat[2][2] = 0.0f;
1614         Mat3MulVecfl(mat, tvec);
1615
1616         // translate the view
1617
1618         VecSubf(v3d->ofs, v3d->ofs, tvec);
1619
1620
1621         /*----------------------------------------------------
1622      * refresh the screen XXX
1623       */
1624
1625         // update render preview window
1626
1627 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
1628 }
1629
1630 void viewmoveNDOF(Scene *scene, View3D *v3d, int mode)
1631 {
1632     float fval[7];
1633     float dvec[3];
1634     float sbadjust = 1.0f;
1635     float len;
1636         short use_sel = 0;
1637         Object *ob = OBACT;
1638     float m[3][3];
1639     float m_inv[3][3];
1640     float xvec[3] = {1,0,0};
1641     float yvec[3] = {0,-1,0};
1642     float zvec[3] = {0,0,1};
1643         float phi, si;
1644     float q1[4];
1645     float obofs[3];
1646     float reverse;
1647     //float diff[4];
1648     float d, curareaX, curareaY;
1649     float mat[3][3];
1650     float upvec[3];
1651
1652     /* Sensitivity will control how fast the view rotates.  The value was
1653      * obtained experimentally by tweaking until the author didn't get dizzy watching.
1654      * Perhaps this should be a configurable user parameter.
1655      */
1656     float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
1657     float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
1658     float zsens = 0.3f;   /* zoom sensitivity */
1659
1660     const float minZoom = -30.0f;
1661     const float maxZoom = 300.0f;
1662
1663         //reset view type
1664         v3d->view = 0;
1665 //printf("passing here \n");
1666 //
1667         if (G.obedit==NULL && ob && !(ob->flag & OB_POSEMODE)) {
1668                 use_sel = 1;
1669         }
1670
1671     if((dz_flag)||v3d->dist==0) {
1672                 dz_flag = 0;
1673                 v3d->dist = m_dist;
1674                 upvec[0] = upvec[1] = 0;
1675                 upvec[2] = v3d->dist;
1676                 Mat3CpyMat4(mat, v3d->viewinv);
1677                 Mat3MulVecfl(mat, upvec);
1678                 VecAddf(v3d->ofs, v3d->ofs, upvec);
1679         }
1680
1681     /*----------------------------------------------------
1682          * sometimes this routine is called from headerbuttons
1683      * viewmove needs to refresh the screen
1684      */
1685 // XXX  areawinset(curarea->win);
1686
1687     /*----------------------------------------------------
1688      * record how much time has passed. clamp at 10 Hz
1689      * pretend the previous frame occured at the clamped time
1690      */
1691 //    now = PIL_check_seconds_timer();
1692  //   frametime = (now - prevTime);
1693  //   if (frametime > 0.1f){        /* if more than 1/10s */
1694  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
1695 //    }
1696 //    prevTime = now;
1697  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
1698
1699     /* fetch the current state of the ndof device & enforce dominant mode if selected */
1700 // XXX    getndof(fval);
1701         if (v3d->ndoffilter)
1702                 filterNDOFvalues(fval);
1703
1704
1705     // put scaling back here, was previously in ghostwinlay
1706     fval[0] = fval[0] * (1.0f/600.0f);
1707     fval[1] = fval[1] * (1.0f/600.0f);
1708     fval[2] = fval[2] * (1.0f/1100.0f);
1709     fval[3] = fval[3] * 0.00005f;
1710     fval[4] =-fval[4] * 0.00005f;
1711     fval[5] = fval[5] * 0.00005f;
1712     fval[6] = fval[6] / 1000000.0f;
1713
1714     // scale more if not in perspective mode
1715     if (v3d->persp == V3D_ORTHO) {
1716         fval[0] = fval[0] * 0.05f;
1717         fval[1] = fval[1] * 0.05f;
1718         fval[2] = fval[2] * 0.05f;
1719         fval[3] = fval[3] * 0.9f;
1720         fval[4] = fval[4] * 0.9f;
1721         fval[5] = fval[5] * 0.9f;
1722         zsens *= 8;
1723     }
1724
1725
1726     /* set object offset */
1727         if (ob) {
1728                 obofs[0] = -ob->obmat[3][0];
1729                 obofs[1] = -ob->obmat[3][1];
1730                 obofs[2] = -ob->obmat[3][2];
1731         }
1732         else {
1733                 VECCOPY(obofs, v3d->ofs);
1734         }
1735
1736     /* calc an adjustment based on distance from camera
1737        disabled per patch 14402 */
1738      d = 1.0f;
1739
1740 /*    if (ob) {
1741         VecSubf(diff, obofs, v3d->ofs);
1742         d = VecLength(diff);
1743     }
1744 */
1745
1746     reverse = (v3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
1747
1748     /*----------------------------------------------------
1749      * ndof device pan
1750      */
1751     psens *= 1.0f + d;
1752     curareaX = sbadjust * psens * fval[0];
1753     curareaY = sbadjust * psens * fval[1];
1754     dvec[0] = curareaX * v3d->persinv[0][0] + curareaY * v3d->persinv[1][0];
1755     dvec[1] = curareaX * v3d->persinv[0][1] + curareaY * v3d->persinv[1][1];
1756     dvec[2] = curareaX * v3d->persinv[0][2] + curareaY * v3d->persinv[1][2];
1757     VecAddf(v3d->ofs, v3d->ofs, dvec);
1758
1759     /*----------------------------------------------------
1760      * ndof device dolly
1761      */
1762     len = zsens * sbadjust * fval[2];
1763
1764     if (v3d->persp==V3D_CAMOB) {
1765         if(v3d->persp==V3D_CAMOB) { /* This is stupid, please fix - TODO */
1766             v3d->camzoom+= 10.0f * -len;
1767         }
1768         if (v3d->camzoom < minZoom) v3d->camzoom = minZoom;
1769         else if (v3d->camzoom > maxZoom) v3d->camzoom = maxZoom;
1770     }
1771     else if ((v3d->dist> 0.001*v3d->grid) && (v3d->dist<10.0*v3d->far)) {
1772         v3d->dist*=(1.0 + len);
1773     }
1774
1775
1776     /*----------------------------------------------------
1777      * ndof device turntable
1778      * derived from the turntable code in viewmove
1779      */
1780
1781     /* Get the 3x3 matrix and its inverse from the quaternion */
1782     QuatToMat3(v3d->viewquat, m);
1783     Mat3Inv(m_inv,m);
1784
1785     /* Determine the direction of the x vector (for rotating up and down) */
1786     /* This can likely be compuated directly from the quaternion. */
1787     Mat3MulVecfl(m_inv,xvec);
1788     Mat3MulVecfl(m_inv,yvec);
1789     Mat3MulVecfl(m_inv,zvec);
1790
1791     /* Perform the up/down rotation */
1792     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
1793     si = sin(phi);
1794     q1[0] = cos(phi);
1795     q1[1] = si * xvec[0];
1796     q1[2] = si * xvec[1];
1797     q1[3] = si * xvec[2];
1798     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1799
1800     if (use_sel) {
1801         QuatConj(q1); /* conj == inv for unit quat */
1802         VecSubf(v3d->ofs, v3d->ofs, obofs);
1803         QuatMulVecf(q1, v3d->ofs);
1804         VecAddf(v3d->ofs, v3d->ofs, obofs);
1805     }
1806
1807     /* Perform the orbital rotation */
1808     /* Perform the orbital rotation
1809        If the seen Up axis is parallel to the zoom axis, rotation should be
1810        achieved with a pure Roll motion (no Spin) on the device. When you start
1811        to tilt, moving from Top to Side view, Spinning will increasingly become
1812        more relevant while the Roll component will decrease. When a full
1813        Side view is reached, rotations around the world's Up axis are achieved
1814        with a pure Spin-only motion.  In other words the control of the spinning
1815        around the world's Up axis should move from the device's Spin axis to the
1816        device's Roll axis depending on the orientation of the world's Up axis
1817        relative to the screen. */
1818     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
1819     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
1820     q1[0] = cos(phi);
1821     q1[1] = q1[2] = 0.0;
1822     q1[3] = sin(phi);
1823     QuatMul(v3d->viewquat, v3d->viewquat, q1);
1824
1825     if (use_sel) {
1826         QuatConj(q1);
1827         VecSubf(v3d->ofs, v3d->ofs, obofs);
1828         QuatMulVecf(q1, v3d->ofs);
1829         VecAddf(v3d->ofs, v3d->ofs, obofs);
1830     }
1831
1832     /*----------------------------------------------------
1833      * refresh the screen
1834      */
1835 // XXX    scrarea_do_windraw(curarea);
1836 }
1837
1838
1839
1840