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