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