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