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