Multitouch trackpad 2 fingers gestures implementation
[blender-staging.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_math.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_paint.h"
58 #include "BKE_report.h"
59 #include "BKE_scene.h"
60 #include "BKE_screen.h"
61 #include "BKE_utildefines.h"
62
63 #include "RE_pipeline.h"        // make_stars
64
65 #include "BIF_gl.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_retopo.h"
75 #include "ED_space_api.h"
76 #include "ED_screen.h"
77 #include "ED_transform.h"
78 #include "ED_types.h"
79
80 #include "UI_interface.h"
81 #include "UI_resources.h"
82 #include "UI_view2d.h"
83
84 #include "PIL_time.h" /* smoothview */
85
86 #include "view3d_intern.h"      // own include
87
88 /* ********************** view3d_edit: view manipulations ********************* */
89
90 /* ********************* box view support ***************** */
91
92 static void view3d_boxview_clip(ScrArea *sa)
93 {
94         ARegion *ar;
95         BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
96         float clip[6][4];
97         float x1= 0.0f, y1= 0.0f, z1= 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
98         int val;
99
100         /* create bounding box */
101         for(ar= sa->regionbase.first; ar; ar= ar->next) {
102                 if(ar->regiontype==RGN_TYPE_WINDOW) {
103                         RegionView3D *rv3d= ar->regiondata;
104
105                         if(rv3d->viewlock & RV3D_BOXCLIP) {
106                                 if(ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
107                                         if(ar->winx>ar->winy) x1= rv3d->dist;
108                                         else x1= ar->winx*rv3d->dist/ar->winy;
109
110                                         if(ar->winx>ar->winy) y1= ar->winy*rv3d->dist/ar->winx;
111                                         else y1= rv3d->dist;
112
113                                         ofs[0]= rv3d->ofs[0];
114                                         ofs[1]= rv3d->ofs[1];
115                                 }
116                                 else if(ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
117                                         ofs[2]= rv3d->ofs[2];
118
119                                         if(ar->winx>ar->winy) z1= ar->winy*rv3d->dist/ar->winx;
120                                         else z1= rv3d->dist;
121                                 }
122                         }
123                 }
124         }
125
126         for(val=0; val<8; val++) {
127                 if(ELEM4(val, 0, 3, 4, 7))
128                         bb->vec[val][0]= -x1 - ofs[0];
129                 else
130                         bb->vec[val][0]=  x1 - ofs[0];
131
132                 if(ELEM4(val, 0, 1, 4, 5))
133                         bb->vec[val][1]= -y1 - ofs[1];
134                 else
135                         bb->vec[val][1]=  y1 - ofs[1];
136
137                 if(val > 3)
138                         bb->vec[val][2]= -z1 - ofs[2];
139                 else
140                         bb->vec[val][2]=  z1 - ofs[2];
141         }
142
143         /* normals for plane equations */
144         normal_tri_v3( clip[0],bb->vec[0], bb->vec[1], bb->vec[4]);
145         normal_tri_v3( clip[1],bb->vec[1], bb->vec[2], bb->vec[5]);
146         normal_tri_v3( clip[2],bb->vec[2], bb->vec[3], bb->vec[6]);
147         normal_tri_v3( clip[3],bb->vec[3], bb->vec[0], bb->vec[7]);
148         normal_tri_v3( clip[4],bb->vec[4], bb->vec[5], bb->vec[6]);
149         normal_tri_v3( clip[5],bb->vec[0], bb->vec[2], bb->vec[1]);
150
151         /* then plane equations */
152         for(val=0; val<5; val++) {
153                 clip[val][3]= - clip[val][0]*bb->vec[val][0] - clip[val][1]*bb->vec[val][1] - clip[val][2]*bb->vec[val][2];
154         }
155         clip[5][3]= - clip[5][0]*bb->vec[0][0] - clip[5][1]*bb->vec[0][1] - clip[5][2]*bb->vec[0][2];
156
157         /* create bounding box */
158         for(ar= sa->regionbase.first; ar; ar= ar->next) {
159                 if(ar->regiontype==RGN_TYPE_WINDOW) {
160                         RegionView3D *rv3d= ar->regiondata;
161
162                         if(rv3d->viewlock & RV3D_BOXCLIP) {
163                                 rv3d->rflag |= RV3D_CLIPPING;
164                                 memcpy(rv3d->clip, clip, sizeof(clip));
165                         }
166                 }
167         }
168         MEM_freeN(bb);
169 }
170
171 /* sync center/zoom view of region to others, for view transforms */
172 static void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
173 {
174         ARegion *artest;
175         RegionView3D *rv3d= ar->regiondata;
176
177         for(artest= sa->regionbase.first; artest; artest= artest->next) {
178                 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
179                         RegionView3D *rv3dtest= artest->regiondata;
180
181                         if(rv3dtest->viewlock) {
182                                 rv3dtest->dist= rv3d->dist;
183
184                                 if( ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ) {
185                                         if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
186                                                 rv3dtest->ofs[0]= rv3d->ofs[0];
187                                         else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
188                                                 rv3dtest->ofs[1]= rv3d->ofs[1];
189                                 }
190                                 else if( ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK) ) {
191                                         if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
192                                                 rv3dtest->ofs[0]= rv3d->ofs[0];
193                                         else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
194                                                 rv3dtest->ofs[2]= rv3d->ofs[2];
195                                 }
196                                 else if( ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ) {
197                                         if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
198                                                 rv3dtest->ofs[1]= rv3d->ofs[1];
199                                         if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
200                                                 rv3dtest->ofs[2]= rv3d->ofs[2];
201                                 }
202
203                                 ED_region_tag_redraw(artest);
204                         }
205                 }
206         }
207         view3d_boxview_clip(sa);
208 }
209
210 /* for home, center etc */
211 void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
212 {
213         ARegion *artest;
214         RegionView3D *rv3d= ar->regiondata;
215
216         for(artest= sa->regionbase.first; artest; artest= artest->next) {
217                 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
218                         RegionView3D *rv3dtest= artest->regiondata;
219
220                         if(rv3dtest->viewlock) {
221                                 rv3dtest->dist= rv3d->dist;
222                                 VECCOPY(rv3dtest->ofs, rv3d->ofs);
223                                 ED_region_tag_redraw(artest);
224                         }
225                 }
226         }
227         view3d_boxview_clip(sa);
228 }
229
230 /* ************************** init for view ops **********************************/
231
232 typedef struct ViewOpsData {
233         ScrArea *sa;
234         ARegion *ar;
235         RegionView3D *rv3d;
236
237         /* needed for continuous zoom */
238         wmTimer *timer;
239         double timer_lastdraw;
240
241         float oldquat[4];
242         float trackvec[3];
243         float reverse, dist0;
244         float grid, far;
245         short axis_snap; /* view rotate only */
246
247         /* use for orbit selection and auto-dist */
248         float ofs[3], dyn_ofs[3];
249         short use_dyn_ofs;
250
251         int origx, origy, oldx, oldy;
252         int origkey; /* the key that triggered the operator */
253
254 } ViewOpsData;
255
256 #define TRACKBALLSIZE  (1.1)
257
258 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
259 {
260         float x, y, radius, d, z, t;
261
262         radius= TRACKBALLSIZE;
263
264         /* normalize x and y */
265         x= (rect->xmax + rect->xmin)/2 - mx;
266         x/= (float)((rect->xmax - rect->xmin)/4);
267         y= (rect->ymax + rect->ymin)/2 - my;
268         y/= (float)((rect->ymax - rect->ymin)/2);
269
270         d = sqrt(x*x + y*y);
271         if (d < radius*M_SQRT1_2)       /* Inside sphere */
272                 z = sqrt(radius*radius - d*d);
273         else
274         {                       /* On hyperbola */
275                 t = radius / M_SQRT2;
276                 z = t*t / d;
277         }
278
279         vec[0]= x;
280         vec[1]= y;
281         vec[2]= -z;             /* yah yah! */
282 }
283
284
285 static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
286 {
287         static float lastofs[3] = {0,0,0};
288         View3D *v3d = CTX_wm_view3d(C);
289         RegionView3D *rv3d;
290         ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
291
292         /* store data */
293         op->customdata= vod;
294         vod->sa= CTX_wm_area(C);
295         vod->ar= CTX_wm_region(C);
296         vod->rv3d= rv3d= vod->ar->regiondata;
297         vod->dist0= rv3d->dist;
298         QUATCOPY(vod->oldquat, rv3d->viewquat);
299         vod->origx= vod->oldx= event->x;
300         vod->origy= vod->oldy= event->y;
301         vod->origkey= event->type; /* the key that triggered the operator.  */
302         vod->use_dyn_ofs= (U.uiflag & USER_ORBIT_SELECTION) ? 1:0;
303
304         if (vod->use_dyn_ofs) {
305                 VECCOPY(vod->ofs, rv3d->ofs);
306                 /* If there's no selection, lastofs is unmodified and last value since static */
307                 calculateTransformCenter(C, V3D_CENTROID, lastofs);
308                 VECCOPY(vod->dyn_ofs, lastofs);
309                 mul_v3_fl(vod->dyn_ofs, -1.0f);
310         }
311         else if (U.uiflag & USER_ORBIT_ZBUF) {
312
313                 view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
314
315                 if((vod->use_dyn_ofs=view_autodist(CTX_data_scene(C), vod->ar, v3d, event->mval, vod->dyn_ofs))) {
316                         if (rv3d->persp==RV3D_PERSP) {
317                                 float my_origin[3]; /* original G.vd->ofs */
318                                 float my_pivot[3]; /* view */
319                                 float dvec[3];
320
321                                 // locals for dist correction
322                                 float mat[3][3];
323                                 float upvec[3];
324
325                                 VECCOPY(my_origin, rv3d->ofs);
326                                 negate_v3(my_origin);                           /* ofs is flipped */
327
328                                 /* Set the dist value to be the distance from this 3d point */
329                                 /* this means youll always be able to zoom into it and panning wont go bad when dist was zero */
330
331                                 /* remove dist value */
332                                 upvec[0] = upvec[1] = 0;
333                                 upvec[2] = rv3d->dist;
334                                 copy_m3_m4(mat, rv3d->viewinv);
335
336                                 mul_m3_v3(mat, upvec);
337                                 sub_v3_v3v3(my_pivot, rv3d->ofs, upvec);
338                                 negate_v3(my_pivot);                            /* ofs is flipped */
339
340                                 /* find a new ofs value that is allong the view axis (rather then the mouse location) */
341                                 closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin);
342                                 vod->dist0 = rv3d->dist = len_v3v3(my_pivot, dvec);
343
344                                 negate_v3(dvec);
345                                 VECCOPY(rv3d->ofs, dvec);
346                         }
347                         negate_v3(vod->dyn_ofs);
348                         VECCOPY(vod->ofs, rv3d->ofs);
349                 } else {
350                         vod->ofs[0] = vod->ofs[1] = vod->ofs[2] = 0.0f;
351                 }
352         }
353
354         /* lookup, we dont pass on v3d to prevent confusement */
355         vod->grid= v3d->grid;
356         vod->far= v3d->far;
357
358         calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
359
360         initgrabz(rv3d, -rv3d->ofs[0], -rv3d->ofs[1], -rv3d->ofs[2]);
361
362         vod->reverse= 1.0f;
363         if (rv3d->persmat[2][1] < 0.0f)
364                 vod->reverse= -1.0f;
365
366         rv3d->rflag |= RV3D_NAVIGATING;
367 }
368
369 static void viewops_data_free(bContext *C, wmOperator *op)
370 {
371         Paint *p = paint_get_active(CTX_data_scene(C));
372         ViewOpsData *vod= op->customdata;
373
374         vod->rv3d->rflag &= ~RV3D_NAVIGATING;
375
376         if(p && (p->flags & PAINT_FAST_NAVIGATE))
377                 ED_region_tag_redraw(vod->ar);
378
379         if(vod->timer)
380                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), vod->timer);
381
382         MEM_freeN(vod);
383         op->customdata= NULL;
384 }
385
386 /* ************************** viewrotate **********************************/
387
388 static const float thres = 0.93f; //cos(20 deg);
389
390 #define COS45 0.70710678118654746
391 #define SIN45 COS45
392
393 static float snapquats[39][6] = {
394         /*{q0, q1, q3, q4, view, oposite_direction}*/
395 {COS45, -SIN45, 0.0, 0.0, RV3D_VIEW_FRONT, 0},  //front
396 {0.0, 0.0, -SIN45, -SIN45, RV3D_VIEW_BACK, 0}, //back
397 {1.0, 0.0, 0.0, 0.0, RV3D_VIEW_TOP, 0},       //top
398 {0.0, -1.0, 0.0, 0.0, RV3D_VIEW_BOTTOM, 0},      //bottom
399 {0.5, -0.5, -0.5, -0.5, RV3D_VIEW_LEFT, 0},    //left
400 {0.5, -0.5, 0.5, 0.5, RV3D_VIEW_RIGHT, 0},      //right
401
402         /* some more 45 deg snaps */
403 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
404 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
405 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
406 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
407 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
408 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
409 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
410 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
411 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
412 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
413 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
414 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
415 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
416 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
417 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
418 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
419 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
420 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
421 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
422 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
423 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
424 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
425 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
426 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
427 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
428 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
429 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
430 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
431 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
432 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
433 {-COS45, 0.0, 0.0, SIN45, 0, 0},
434 {COS45, 0.0, 0.0, SIN45, 0, 0},
435 {0.0, 0.0, 0.0, 1.0, 0, 0}
436 };
437
438 enum {
439         VIEW_PASS= 0,
440         VIEW_APPLY,
441         VIEW_CONFIRM
442 };
443
444 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
445 #define VIEW_MODAL_CONFIRM                              1 /* used for all view operations */
446 #define VIEWROT_MODAL_AXIS_SNAP_ENABLE  2
447 #define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3
448 #define VIEWROT_MODAL_SWITCH_ZOOM               4
449 #define VIEWROT_MODAL_SWITCH_MOVE               5
450 #define VIEWROT_MODAL_SWITCH_ROTATE             6
451
452 /* called in transform_ops.c, on each regeneration of keymaps  */
453 void viewrotate_modal_keymap(wmKeyConfig *keyconf)
454 {
455         static EnumPropertyItem modal_items[] = {
456         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Cancel", ""},
457
458         {VIEWROT_MODAL_AXIS_SNAP_ENABLE,        "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""},
459         {VIEWROT_MODAL_AXIS_SNAP_DISABLE,       "AXIS_SNAP_DISABLE", 0, "Disable Axis Snap", ""},
460                 
461         {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
462         {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
463
464         {0, NULL, 0, NULL, NULL}};
465
466         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Rotate Modal");
467
468         /* this function is called for each spacetype, only needs to add map once */
469         if(keymap) return;
470
471         keymap= WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items);
472
473         /* items for modal map */
474         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
475         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
476
477         WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE);
478         WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE);
479
480         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
481         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
482         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
483         
484         /* assign map to operators */
485         WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate");
486
487 }
488
489 static void viewrotate_apply(ViewOpsData *vod, int x, int y)
490 {
491         RegionView3D *rv3d= vod->rv3d;
492
493         rv3d->view= 0; /* need to reset everytime because of view snapping */
494
495         if (U.flag & USER_TRACKBALL) {
496                 float phi, si, q1[4], dvec[3], newvec[3];
497
498                 calctrackballvec(&vod->ar->winrct, x, y, newvec);
499
500                 sub_v3_v3v3(dvec, newvec, vod->trackvec);
501
502                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
503                 si/= (2.0*TRACKBALLSIZE);
504
505                 cross_v3_v3v3(q1+1, vod->trackvec, newvec);
506                 normalize_v3(q1+1);
507
508                 /* Allow for rotation beyond the interval
509                         * [-pi, pi] */
510                 while (si > 1.0)
511                         si -= 2.0;
512
513                 /* This relation is used instead of
514                         * phi = asin(si) so that the angle
515                         * of rotation is linearly proportional
516                         * to the distance that the mouse is
517                         * dragged. */
518                 phi = si * M_PI / 2.0;
519
520                 si= sin(phi);
521                 q1[0]= cos(phi);
522                 q1[1]*= si;
523                 q1[2]*= si;
524                 q1[3]*= si;
525                 mul_qt_qtqt(rv3d->viewquat, q1, vod->oldquat);
526
527                 if (vod->use_dyn_ofs) {
528                         /* compute the post multiplication quat, to rotate the offset correctly */
529                         QUATCOPY(q1, vod->oldquat);
530                         conjugate_qt(q1);
531                         mul_qt_qtqt(q1, q1, rv3d->viewquat);
532
533                         conjugate_qt(q1); /* conj == inv for unit quat */
534                         VECCOPY(rv3d->ofs, vod->ofs);
535                         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
536                         mul_qt_v3(q1, rv3d->ofs);
537                         add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
538                 }
539         }
540         else {
541                 /* New turntable view code by John Aughey */
542                 float si, phi, q1[4];
543                 float m[3][3];
544                 float m_inv[3][3];
545                 float xvec[3] = {1,0,0};
546                 /* Sensitivity will control how fast the viewport rotates.  0.0035 was
547                         obtained experimentally by looking at viewport rotation sensitivities
548                         on other modeling programs. */
549                 /* Perhaps this should be a configurable user parameter. */
550                 const float sensitivity = 0.0035;
551
552                 /* Get the 3x3 matrix and its inverse from the quaternion */
553                 quat_to_mat3( m,rv3d->viewquat);
554                 invert_m3_m3(m_inv,m);
555
556                 /* Determine the direction of the x vector (for rotating up and down) */
557                 /* This can likely be computed directly from the quaternion. */
558                 mul_m3_v3(m_inv,xvec);
559
560                 /* Perform the up/down rotation */
561                 phi = sensitivity * -(y - vod->oldy);
562                 si = sin(phi);
563                 q1[0] = cos(phi);
564                 q1[1] = si * xvec[0];
565                 q1[2] = si * xvec[1];
566                 q1[3] = si * xvec[2];
567                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
568
569                 if (vod->use_dyn_ofs) {
570                         conjugate_qt(q1); /* conj == inv for unit quat */
571                         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
572                         mul_qt_v3(q1, rv3d->ofs);
573                         add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
574                 }
575
576                 /* Perform the orbital rotation */
577                 phi = sensitivity * vod->reverse * (x - vod->oldx);
578                 q1[0] = cos(phi);
579                 q1[1] = q1[2] = 0.0;
580                 q1[3] = sin(phi);
581                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
582
583                 if (vod->use_dyn_ofs) {
584                         conjugate_qt(q1);
585                         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
586                         mul_qt_v3(q1, rv3d->ofs);
587                         add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
588                 }
589         }
590
591         /* check for view snap */
592         if (vod->axis_snap){
593                 int i;
594                 float viewmat[3][3];
595
596
597                 quat_to_mat3( viewmat,rv3d->viewquat);
598
599                 for (i = 0 ; i < 39; i++){
600                         float snapmat[3][3];
601                         float view = (int)snapquats[i][4];
602
603                         quat_to_mat3( snapmat,snapquats[i]);
604
605                         if ((dot_v3v3(snapmat[0], viewmat[0]) > thres) &&
606                                 (dot_v3v3(snapmat[1], viewmat[1]) > thres) &&
607                                 (dot_v3v3(snapmat[2], viewmat[2]) > thres)){
608
609                                 QUATCOPY(rv3d->viewquat, snapquats[i]);
610
611                                 rv3d->view = view;
612
613                                 break;
614                         }
615                 }
616         }
617         vod->oldx= x;
618         vod->oldy= y;
619
620         ED_region_tag_redraw(vod->ar);
621 }
622
623 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
624 {
625         ViewOpsData *vod= op->customdata;
626         short event_code= VIEW_PASS;
627
628         /* execute the events */
629         if(event->type==MOUSEMOVE) {
630                 event_code= VIEW_APPLY;
631         }
632         else if(event->type==EVT_MODAL_MAP) {
633                 switch (event->val) {
634                         case VIEW_MODAL_CONFIRM:
635                                 event_code= VIEW_CONFIRM;
636                                 break;
637                         case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
638                                 vod->axis_snap= TRUE;
639                                 event_code= VIEW_APPLY;
640                                 break;
641                         case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
642                                 vod->axis_snap= FALSE;
643                                 event_code= VIEW_APPLY;
644                                 break;
645                         case VIEWROT_MODAL_SWITCH_ZOOM:
646                                 WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
647                                 event_code= VIEW_CONFIRM;
648                                 break;
649                         case VIEWROT_MODAL_SWITCH_MOVE:
650                                 WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
651                                 event_code= VIEW_CONFIRM;
652                                 break;
653                 }
654         }
655         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
656                 event_code= VIEW_CONFIRM;
657         }
658
659         if(event_code==VIEW_APPLY) {
660                 viewrotate_apply(vod, event->x, event->y);
661         }
662         else if (event_code==VIEW_CONFIRM) {
663                 request_depth_update(CTX_wm_region_view3d(C));
664                 viewops_data_free(C, op);
665
666                 return OPERATOR_FINISHED;
667         }
668
669         return OPERATOR_RUNNING_MODAL;
670 }
671
672 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
673 {
674         RegionView3D *rv3d= CTX_wm_region_view3d(C);
675         ViewOpsData *vod;
676
677         if(rv3d->viewlock)
678                 return OPERATOR_CANCELLED;
679
680         /* makes op->customdata */
681         viewops_data_create(C, op, event);
682         vod= op->customdata;
683
684         /* switch from camera view when: */
685         if(vod->rv3d->persp != RV3D_PERSP) {
686
687                 if (U.uiflag & USER_AUTOPERSP)
688                         vod->rv3d->persp= RV3D_PERSP;
689                 else if(vod->rv3d->persp==RV3D_CAMOB)
690                         vod->rv3d->persp= RV3D_PERSP;
691                 ED_region_tag_redraw(vod->ar);
692         }
693         
694         if (event->type == MOUSEPAN) {
695                 viewrotate_apply(vod, event->prevx, event->prevy);
696                 request_depth_update(CTX_wm_region_view3d(C));
697                 
698                 viewops_data_free(C, op);
699                 
700                 return OPERATOR_FINISHED;
701         }
702         else if (event->type == MOUSEROTATE) {
703                 /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
704                 viewrotate_apply(vod, event->prevx, event->y);
705                 request_depth_update(CTX_wm_region_view3d(C));
706                 
707                 viewops_data_free(C, op);
708                 
709                 return OPERATOR_FINISHED;
710         }
711         else {          
712                 /* add temp handler */
713                 WM_event_add_modal_handler(C, op);
714
715                 return OPERATOR_RUNNING_MODAL;
716         }
717 }
718
719 static int ED_operator_view3d_rotate(bContext *C)
720 {
721         if (!ED_operator_view3d_active(C)) {
722                 return 0;
723         } else {
724                 RegionView3D *rv3d= CTX_wm_region_view3d(C);
725                 /* rv3d is null in menus, but it's ok when the menu is clicked on */
726                 /* XXX of course, this doesn't work with quadview
727                  * Maybe having exec return PASSTHROUGH would be better than polling here
728                  * Poll functions are full of problems anyway.
729                  * */
730                 return rv3d == NULL || rv3d->viewlock == 0;
731         }
732 }
733
734 void VIEW3D_OT_rotate(wmOperatorType *ot)
735 {
736
737         /* identifiers */
738         ot->name= "Rotate view";
739         ot->description = "Rotate the view.";
740         ot->idname= "VIEW3D_OT_rotate";
741
742         /* api callbacks */
743         ot->invoke= viewrotate_invoke;
744         ot->modal= viewrotate_modal;
745         ot->poll= ED_operator_view3d_rotate;
746
747         /* flags */
748         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
749 }
750
751 /* ************************ viewmove ******************************** */
752
753
754 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
755
756 /* called in transform_ops.c, on each regeneration of keymaps  */
757 void viewmove_modal_keymap(wmKeyConfig *keyconf)
758 {
759         static EnumPropertyItem modal_items[] = {
760         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Confirm", ""},
761
762         {0, NULL, 0, NULL, NULL}};
763
764         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Move Modal");
765
766         /* this function is called for each spacetype, only needs to add map once */
767         if(keymap) return;
768
769         keymap= WM_modalkeymap_add(keyconf, "View3D Move Modal", modal_items);
770
771         /* items for modal map */
772         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
773         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
774
775         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
776         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
777         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
778         
779         /* assign map to operators */
780         WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
781 }
782
783
784 static void viewmove_apply(ViewOpsData *vod, int x, int y)
785 {
786         if(vod->rv3d->persp==RV3D_CAMOB) {
787                 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
788
789                 vod->rv3d->camdx += (vod->oldx - x)/(max);
790                 vod->rv3d->camdy += (vod->oldy - y)/(max);
791                 CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
792                 CLAMP(vod->rv3d->camdy, -1.0f, 1.0f);
793 // XXX          preview3d_event= 0;
794         }
795         else {
796                 float dvec[3];
797
798                 window_to_3d_delta(vod->ar, dvec, x-vod->oldx, y-vod->oldy);
799                 add_v3_v3v3(vod->rv3d->ofs, vod->rv3d->ofs, dvec);
800
801                 if(vod->rv3d->viewlock & RV3D_BOXVIEW)
802                         view3d_boxview_sync(vod->sa, vod->ar);
803         }
804
805         vod->oldx= x;
806         vod->oldy= y;
807
808         ED_region_tag_redraw(vod->ar);
809 }
810
811
812 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
813 {
814
815         ViewOpsData *vod= op->customdata;
816         short event_code= VIEW_PASS;
817
818         /* execute the events */
819         if(event->type==MOUSEMOVE) {
820                 event_code= VIEW_APPLY;
821         }
822         else if(event->type==EVT_MODAL_MAP) {
823                 switch (event->val) {
824                         case VIEW_MODAL_CONFIRM:
825                                 event_code= VIEW_CONFIRM;
826                                 break;
827                         case VIEWROT_MODAL_SWITCH_ZOOM:
828                                 WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
829                                 event_code= VIEW_CONFIRM;
830                                 break;
831                         case VIEWROT_MODAL_SWITCH_ROTATE:
832                                 WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
833                                 event_code= VIEW_CONFIRM;
834                                 break;
835                 }
836         }
837         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
838                 event_code= VIEW_CONFIRM;
839         }
840
841         if(event_code==VIEW_APPLY) {
842                 viewmove_apply(vod, event->x, event->y);
843         }
844         else if (event_code==VIEW_CONFIRM) {
845                 request_depth_update(CTX_wm_region_view3d(C));
846
847                 viewops_data_free(C, op);
848
849                 return OPERATOR_FINISHED;
850         }
851
852         return OPERATOR_RUNNING_MODAL;
853 }
854
855 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
856 {
857         /* makes op->customdata */
858         viewops_data_create(C, op, event);
859
860         if (event->type == MOUSEPAN) {
861                 ViewOpsData *vod= op->customdata;
862                 viewmove_apply(vod, event->prevx, event->prevy);
863                 request_depth_update(CTX_wm_region_view3d(C));
864                 
865                 viewops_data_free(C, op);               
866                 
867                 return OPERATOR_FINISHED;
868         }
869         else {
870                 /* add temp handler */
871                 WM_event_add_modal_handler(C, op);
872
873                 return OPERATOR_RUNNING_MODAL;
874         }
875 }
876
877 void VIEW3D_OT_move(wmOperatorType *ot)
878 {
879
880         /* identifiers */
881         ot->name= "Move view";
882         ot->description = "Move the view.";
883         ot->idname= "VIEW3D_OT_move";
884
885         /* api callbacks */
886         ot->invoke= viewmove_invoke;
887         ot->modal= viewmove_modal;
888         ot->poll= ED_operator_view3d_active;
889
890         /* flags */
891         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
892 }
893
894 /* ************************ viewzoom ******************************** */
895
896 /* called in transform_ops.c, on each regeneration of keymaps  */
897 void viewzoom_modal_keymap(wmKeyConfig *keyconf)
898 {
899         static EnumPropertyItem modal_items[] = {
900         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Confirm", ""},
901
902         {0, NULL, 0, NULL, NULL}};
903
904         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Zoom Modal");
905
906         /* this function is called for each spacetype, only needs to add map once */
907         if(keymap) return;
908
909         keymap= WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items);
910
911         /* items for modal map */
912         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
913         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
914
915         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
916         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
917         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
918         
919         /* assign map to operators */
920         WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
921 }
922
923 static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
924 {
925         RegionView3D *rv3d= ar->regiondata;
926
927         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
928                 float dvec[3];
929                 float tvec[3];
930                 float tpos[3];
931                 float new_dist;
932                 short vb[2], mouseloc[2];
933
934                 mouseloc[0]= mx - ar->winrct.xmin;
935                 mouseloc[1]= my - ar->winrct.ymin;
936
937                 /* find the current window width and height */
938                 vb[0] = ar->winx;
939                 vb[1] = ar->winy;
940
941                 tpos[0] = -rv3d->ofs[0];
942                 tpos[1] = -rv3d->ofs[1];
943                 tpos[2] = -rv3d->ofs[2];
944
945                 /* Project cursor position into 3D space */
946                 initgrabz(rv3d, tpos[0], tpos[1], tpos[2]);
947                 window_to_3d_delta(ar, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
948
949                 /* Calculate view target position for dolly */
950                 tvec[0] = -(tpos[0] + dvec[0]);
951                 tvec[1] = -(tpos[1] + dvec[1]);
952                 tvec[2] = -(tpos[2] + dvec[2]);
953
954                 /* Offset to target position and dolly */
955                 new_dist = rv3d->dist * dfac;
956
957                 VECCOPY(rv3d->ofs, tvec);
958                 rv3d->dist = new_dist;
959
960                 /* Calculate final offset */
961                 dvec[0] = tvec[0] + dvec[0] * dfac;
962                 dvec[1] = tvec[1] + dvec[1] * dfac;
963                 dvec[2] = tvec[2] + dvec[2] * dfac;
964
965                 VECCOPY(rv3d->ofs, dvec);
966         } else {
967                 rv3d->dist *= dfac;
968         }
969 }
970
971
972 static void viewzoom_apply(ViewOpsData *vod, int x, int y, short viewzoom)
973 {
974         float zfac=1.0;
975
976         if(viewzoom==USER_ZOOM_CONT) {
977                 double time= PIL_check_seconds_timer();
978                 float time_step= (float)(time - vod->timer_lastdraw);
979
980                 // oldstyle zoom
981                 zfac = 1.0f + (((float)(vod->origx - x + vod->origy - y)/20.0) * time_step);
982                 vod->timer_lastdraw= time;
983         }
984         else if(viewzoom==USER_ZOOM_SCALE) {
985                 int ctr[2], len1, len2;
986                 // method which zooms based on how far you move the mouse
987
988                 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
989                 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
990
991                 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
992                 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
993
994                 zfac = vod->dist0 * ((float)len2/len1) / vod->rv3d->dist;
995         }
996         else {  /* USER_ZOOM_DOLLY */
997                 float len1, len2;
998                 
999                 if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
1000                         len1 = (vod->ar->winrct.xmax - x) + 5;
1001                         len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
1002                 }
1003                 else {
1004                         len1 = (vod->ar->winrct.ymax - y) + 5;
1005                         len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
1006                 }
1007                 if (U.uiflag & USER_ZOOM_INVERT)
1008                         SWAP(float, len1, len2);
1009                 
1010                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->rv3d->dist;
1011         }
1012
1013         if(zfac != 1.0 && zfac*vod->rv3d->dist > 0.001*vod->grid &&
1014                                 zfac*vod->rv3d->dist < 10.0*vod->far)
1015                 view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
1016
1017
1018         if ((U.uiflag & USER_ORBIT_ZBUF) && (viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
1019                 float upvec[3], mat[3][3];
1020
1021                 /* Secret apricot feature, translate the view when in continues mode */
1022                 upvec[0] = upvec[1] = 0.0f;
1023                 upvec[2] = (vod->dist0 - vod->rv3d->dist) * vod->grid;
1024                 vod->rv3d->dist = vod->dist0;
1025                 copy_m3_m4(mat, vod->rv3d->viewinv);
1026                 mul_m3_v3(mat, upvec);
1027                 add_v3_v3v3(vod->rv3d->ofs, vod->rv3d->ofs, upvec);
1028         } else {
1029                 /* these limits were in old code too */
1030                 if(vod->rv3d->dist<0.001*vod->grid) vod->rv3d->dist= 0.001*vod->grid;
1031                 if(vod->rv3d->dist>10.0*vod->far) vod->rv3d->dist=10.0*vod->far;
1032         }
1033
1034 // XXX  if(vod->rv3d->persp==RV3D_ORTHO || vod->rv3d->persp==RV3D_CAMOB) preview3d_event= 0;
1035
1036         if(vod->rv3d->viewlock & RV3D_BOXVIEW)
1037                 view3d_boxview_sync(vod->sa, vod->ar);
1038
1039         ED_region_tag_redraw(vod->ar);
1040 }
1041
1042
1043 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
1044 {
1045         ViewOpsData *vod= op->customdata;
1046         short event_code= VIEW_PASS;
1047
1048         /* execute the events */
1049         if (event->type == TIMER && event->customdata == vod->timer) {
1050                 event_code= VIEW_APPLY;
1051         }
1052         else if(event->type==MOUSEMOVE) {
1053                 event_code= VIEW_APPLY;
1054         }
1055         else if(event->type==EVT_MODAL_MAP) {
1056                 switch (event->val) {
1057                         case VIEW_MODAL_CONFIRM:
1058                                 event_code= VIEW_CONFIRM;
1059                                 break;
1060                         case VIEWROT_MODAL_SWITCH_MOVE:
1061                                 WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
1062                                 event_code= VIEW_CONFIRM;
1063                                 break;
1064                         case VIEWROT_MODAL_SWITCH_ROTATE:
1065                                 WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
1066                                 event_code= VIEW_CONFIRM;
1067                                 break;
1068                 }
1069         }
1070         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
1071                 event_code= VIEW_CONFIRM;
1072         }
1073
1074         if(event_code==VIEW_APPLY) {
1075                 viewzoom_apply(vod, event->x, event->y, U.viewzoom);
1076         }
1077         else if (event_code==VIEW_CONFIRM) {
1078                 request_depth_update(CTX_wm_region_view3d(C));
1079                 viewops_data_free(C, op);
1080
1081                 return OPERATOR_FINISHED;
1082         }
1083
1084         return OPERATOR_RUNNING_MODAL;
1085 }
1086
1087 static int viewzoom_exec(bContext *C, wmOperator *op)
1088 {
1089         View3D *v3d = CTX_wm_view3d(C);
1090         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1091         int delta= RNA_int_get(op->ptr, "delta");
1092         int mx = RNA_int_get(op->ptr, "mx");
1093         int my = RNA_int_get(op->ptr, "my");
1094
1095         if(delta < 0) {
1096                 /* this min and max is also in viewmove() */
1097                 if(rv3d->persp==RV3D_CAMOB) {
1098                         rv3d->camzoom-= 10;
1099                         if(rv3d->camzoom<-30) rv3d->camzoom= -30;
1100                 }
1101                 else if(rv3d->dist<10.0*v3d->far) {
1102                         view_zoom_mouseloc(CTX_wm_region(C), 1.2f, mx, my);
1103                 }
1104         }
1105         else {
1106                 if(rv3d->persp==RV3D_CAMOB) {
1107                         rv3d->camzoom+= 10;
1108                         if(rv3d->camzoom>300) rv3d->camzoom= 300;
1109                 }
1110                 else if(rv3d->dist> 0.001*v3d->grid) {
1111                         view_zoom_mouseloc(CTX_wm_region(C), .83333f, mx, my);
1112                 }
1113         }
1114
1115         if(rv3d->viewlock & RV3D_BOXVIEW)
1116                 view3d_boxview_sync(CTX_wm_area(C), CTX_wm_region(C));
1117
1118         request_depth_update(CTX_wm_region_view3d(C));
1119         ED_region_tag_redraw(CTX_wm_region(C));
1120
1121         return OPERATOR_FINISHED;
1122 }
1123
1124 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
1125 {
1126         int delta= RNA_int_get(op->ptr, "delta");
1127         
1128         /* if one or the other zoom position aren't set, set from event */
1129         if (!RNA_property_is_set(op->ptr, "mx") || !RNA_property_is_set(op->ptr, "my"))
1130         {
1131                 RNA_int_set(op->ptr, "mx", event->x);
1132                 RNA_int_set(op->ptr, "my", event->y);
1133         }
1134
1135         if(delta) {
1136                 viewzoom_exec(C, op);
1137         }
1138         else {
1139                 ViewOpsData *vod;
1140
1141                 /* makes op->customdata */
1142                 viewops_data_create(C, op, event);
1143
1144                 vod= op->customdata;
1145
1146                 if (event->type == MOUSEZOOM) {
1147                         if (U.uiflag & USER_ZOOM_INVERT) /* Bypass Zoom invert flag */
1148                                 SWAP(int, event->x, event->prevx);
1149
1150                         if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
1151                                 vod->origx = vod->oldx = event->x;
1152                                 viewzoom_apply(vod, event->prevx, event->prevy, USER_ZOOM_DOLLY);
1153                         }
1154                         else {
1155                                 
1156                                 /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
1157                                 vod->origy = vod->oldy = event->x;
1158                                 viewzoom_apply(vod, event->x, event->prevx, USER_ZOOM_DOLLY);
1159                         }
1160                         request_depth_update(CTX_wm_region_view3d(C));
1161                         
1162                         viewops_data_free(C, op);
1163                         return OPERATOR_FINISHED;
1164                 }
1165                 else {
1166                         vod->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
1167                         vod->timer_lastdraw= PIL_check_seconds_timer();
1168
1169                         /* add temp handler */
1170                         WM_event_add_modal_handler(C, op);
1171
1172                         return OPERATOR_RUNNING_MODAL;
1173                 }
1174         }
1175         return OPERATOR_FINISHED;
1176 }
1177
1178
1179 void VIEW3D_OT_zoom(wmOperatorType *ot)
1180 {
1181         /* identifiers */
1182         ot->name= "Zoom view";
1183         ot->description = "Zoom in/out in the view.";
1184         ot->idname= "VIEW3D_OT_zoom";
1185
1186         /* api callbacks */
1187         ot->invoke= viewzoom_invoke;
1188         ot->exec= viewzoom_exec;
1189         ot->modal= viewzoom_modal;
1190         ot->poll= ED_operator_view3d_active;
1191
1192         /* flags */
1193         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1194
1195         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1196         RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
1197         RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
1198 }
1199
1200 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1201 {
1202         ARegion *ar= CTX_wm_region(C);
1203         View3D *v3d = CTX_wm_view3d(C);
1204         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1205         Scene *scene= CTX_data_scene(C);
1206         Base *base;
1207         float *curs;
1208
1209         int center= RNA_boolean_get(op->ptr, "center");
1210
1211         float size, min[3], max[3], afm[3];
1212         int ok= 1, onedone=0;
1213
1214         if(center) {
1215                 min[0]= min[1]= min[2]= 0.0f;
1216                 max[0]= max[1]= max[2]= 0.0f;
1217
1218                 /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
1219                 curs= give_cursor(scene, v3d);
1220                 curs[0]= curs[1]= curs[2]= 0.0;
1221         }
1222         else {
1223                 INIT_MINMAX(min, max);
1224         }
1225
1226         for(base= scene->base.first; base; base= base->next) {
1227                 if(base->lay & v3d->lay) {
1228                         onedone= 1;
1229                         minmax_object(base->object, min, max);
1230                 }
1231         }
1232         if(!onedone) return OPERATOR_FINISHED; /* TODO - should this be cancel? */
1233
1234         afm[0]= (max[0]-min[0]);
1235         afm[1]= (max[1]-min[1]);
1236         afm[2]= (max[2]-min[2]);
1237         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
1238         if(size==0.0) ok= 0;
1239
1240         if(ok) {
1241                 float new_dist;
1242                 float new_ofs[3];
1243
1244                 new_dist = size;
1245                 new_ofs[0]= -(min[0]+max[0])/2.0f;
1246                 new_ofs[1]= -(min[1]+max[1])/2.0f;
1247                 new_ofs[2]= -(min[2]+max[2])/2.0f;
1248
1249                 // correction for window aspect ratio
1250                 if(ar->winy>2 && ar->winx>2) {
1251                         size= (float)ar->winx/(float)ar->winy;
1252                         if(size<1.0) size= 1.0f/size;
1253                         new_dist*= size;
1254                 }
1255
1256                 if (rv3d->persp==RV3D_CAMOB) {
1257                         rv3d->persp= RV3D_PERSP;
1258                         smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL);
1259                 }
1260         else {
1261             smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1262         }
1263         }
1264 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1265
1266         if(rv3d->viewlock & RV3D_BOXVIEW)
1267                 view3d_boxview_copy(CTX_wm_area(C), ar);
1268
1269         return OPERATOR_FINISHED;
1270 }
1271
1272 void VIEW3D_OT_view_all(wmOperatorType *ot)
1273 {
1274         /* identifiers */
1275         ot->name= "View All";
1276         ot->description = "View all objects in scene.";
1277         ot->idname= "VIEW3D_OT_view_all";
1278
1279         /* api callbacks */
1280         ot->exec= viewhome_exec;
1281         ot->poll= ED_operator_view3d_active;
1282
1283         /* flags */
1284         ot->flag= 0;
1285
1286         RNA_def_boolean(ot->srna, "center", 0, "Center", "");
1287 }
1288
1289 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
1290 {
1291         ARegion *ar= CTX_wm_region(C);
1292         View3D *v3d = CTX_wm_view3d(C);
1293         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1294         Scene *scene= CTX_data_scene(C);
1295         Object *ob= OBACT;
1296         Object *obedit= CTX_data_edit_object(C);
1297         float size, min[3], max[3], afm[3];
1298         int ok=0;
1299
1300         /* SMOOTHVIEW */
1301         float new_ofs[3];
1302         float new_dist;
1303
1304         INIT_MINMAX(min, max);
1305
1306         if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
1307                 /* hardcoded exception, we look for the one selected armature */
1308                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1309                 Base *base;
1310                 for(base=scene->base.first; base; base= base->next) {
1311                         if(TESTBASELIB(v3d, base)) {
1312                                 if(base->object->type==OB_ARMATURE)
1313                                         if(base->object->mode & OB_MODE_POSE)
1314                                                 break;
1315                         }
1316                 }
1317                 if(base)
1318                         ob= base->object;
1319         }
1320
1321
1322         if(obedit) {
1323                 ok = minmax_verts(obedit, min, max);    /* only selected */
1324         }
1325         else if(ob && (ob->mode & OB_MODE_POSE)) {
1326                 if(ob->pose) {
1327                         bArmature *arm= ob->data;
1328                         bPoseChannel *pchan;
1329                         float vec[3];
1330
1331                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1332                                 if(pchan->bone->flag & BONE_SELECTED) {
1333                                         if(pchan->bone->layer & arm->layer) {
1334                                                 ok= 1;
1335                                                 VECCOPY(vec, pchan->pose_head);
1336                                                 mul_m4_v3(ob->obmat, vec);
1337                                                 DO_MINMAX(vec, min, max);
1338                                                 VECCOPY(vec, pchan->pose_tail);
1339                                                 mul_m4_v3(ob->obmat, vec);
1340                                                 DO_MINMAX(vec, min, max);
1341                                         }
1342                                 }
1343                         }
1344                 }
1345         }
1346         else if (paint_facesel_test(ob)) {
1347 // XXX          ok= minmax_tface(min, max);
1348         }
1349         else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1350                 ok= PE_minmax(scene, min, max);
1351         }
1352         else {
1353                 Base *base= FIRSTBASE;
1354                 while(base) {
1355                         if(TESTBASE(v3d, base))  {
1356                                 minmax_object(base->object, min, max);
1357                                 /* account for duplis */
1358                                 minmax_object_duplis(scene, base->object, min, max);
1359
1360                                 ok= 1;
1361                         }
1362                         base= base->next;
1363                 }
1364         }
1365
1366         if(ok==0) return OPERATOR_FINISHED;
1367
1368         afm[0]= (max[0]-min[0]);
1369         afm[1]= (max[1]-min[1]);
1370         afm[2]= (max[2]-min[2]);
1371         size= MAX3(afm[0], afm[1], afm[2]);
1372         /* perspective should be a bit farther away to look nice */
1373         if(rv3d->persp==RV3D_ORTHO)
1374                 size*= 0.7;
1375
1376         if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
1377
1378         new_ofs[0]= -(min[0]+max[0])/2.0f;
1379         new_ofs[1]= -(min[1]+max[1])/2.0f;
1380         new_ofs[2]= -(min[2]+max[2])/2.0f;
1381
1382         new_dist = size;
1383
1384         /* correction for window aspect ratio */
1385         if(ar->winy>2 && ar->winx>2) {
1386                 size= (float)ar->winx/(float)ar->winy;
1387                 if(size<1.0f) size= 1.0f/size;
1388                 new_dist*= size;
1389         }
1390
1391         if (rv3d->persp==RV3D_CAMOB) {
1392                 rv3d->persp= RV3D_PERSP;
1393                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1394         }
1395         else {
1396                 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1397         }
1398
1399 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1400         if(rv3d->viewlock & RV3D_BOXVIEW)
1401                 view3d_boxview_copy(CTX_wm_area(C), ar);
1402
1403         return OPERATOR_FINISHED;
1404 }
1405
1406 void VIEW3D_OT_view_center(wmOperatorType *ot)
1407 {
1408
1409         /* identifiers */
1410         ot->name= "View Selected";
1411         ot->description = "Move the view to the selection center.";
1412         ot->idname= "VIEW3D_OT_view_center";
1413
1414         /* api callbacks */
1415         ot->exec= viewcenter_exec;
1416         ot->poll= ED_operator_view3d_active;
1417
1418         /* flags */
1419         ot->flag= 0;
1420 }
1421
1422 static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
1423 {
1424         View3D *v3d = CTX_wm_view3d(C);
1425         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1426         Scene *scene= CTX_data_scene(C);
1427         
1428         if (rv3d) {
1429                 if (rv3d->persp==RV3D_CAMOB) {
1430                         /* center the camera offset */
1431                         rv3d->camdx= rv3d->camdy= 0.0;
1432                 }
1433                 else {
1434                         /* non camera center */
1435                         float *curs= give_cursor(scene, v3d);
1436                         float new_ofs[3];
1437                         
1438                         new_ofs[0]= -curs[0];
1439                         new_ofs[1]= -curs[1];
1440                         new_ofs[2]= -curs[2];
1441                         
1442                         smooth_view(C, NULL, NULL, new_ofs, NULL, NULL, NULL);
1443                 }
1444                 
1445                 if (rv3d->viewlock & RV3D_BOXVIEW)
1446                         view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
1447         }
1448         
1449         return OPERATOR_FINISHED;
1450 }
1451
1452 void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
1453 {
1454         /* identifiers */
1455         ot->name= "Center View to Cursor";
1456         ot->description= "Centers the view so that the cursor is in the middle of the view.";
1457         ot->idname= "VIEW3D_OT_view_center_cursor";
1458         
1459         /* api callbacks */
1460         ot->exec= viewcenter_cursor_exec;
1461         ot->poll= ED_operator_view3d_active;
1462         
1463         /* flags */
1464         ot->flag= 0;
1465 }
1466
1467 /* ********************* Set render border operator ****************** */
1468
1469 static int render_border_exec(bContext *C, wmOperator *op)
1470 {
1471         View3D *v3d = CTX_wm_view3d(C);
1472         ARegion *ar= CTX_wm_region(C);
1473         Scene *scene= CTX_data_scene(C);
1474
1475         rcti rect;
1476         rctf vb;
1477
1478         /* get border select values using rna */
1479         rect.xmin= RNA_int_get(op->ptr, "xmin");
1480         rect.ymin= RNA_int_get(op->ptr, "ymin");
1481         rect.xmax= RNA_int_get(op->ptr, "xmax");
1482         rect.ymax= RNA_int_get(op->ptr, "ymax");
1483
1484         /* calculate range */
1485         calc_viewborder(scene, ar, v3d, &vb);
1486
1487         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1488         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1489         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1490         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1491
1492         /* actually set border */
1493         CLAMP(scene->r.border.xmin, 0.0, 1.0);
1494         CLAMP(scene->r.border.ymin, 0.0, 1.0);
1495         CLAMP(scene->r.border.xmax, 0.0, 1.0);
1496         CLAMP(scene->r.border.ymax, 0.0, 1.0);
1497
1498         /* drawing a border surrounding the entire camera view switches off border rendering
1499          * or the border covers no pixels */
1500         if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1501                 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1502            (scene->r.border.xmin == scene->r.border.xmax ||
1503                 scene->r.border.ymin == scene->r.border.ymax ))
1504         {
1505                 scene->r.mode &= ~R_BORDER;
1506         } else {
1507                 scene->r.mode |= R_BORDER;
1508         }
1509         
1510         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, NULL);
1511
1512         return OPERATOR_FINISHED;
1513
1514 }
1515
1516 static int view3d_render_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1517 {
1518         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1519
1520         /* if not in camera view do not exec the operator*/
1521         if (rv3d->persp == RV3D_CAMOB) return WM_border_select_invoke(C, op, event);
1522         else return OPERATOR_PASS_THROUGH;
1523 }
1524
1525 void VIEW3D_OT_render_border(wmOperatorType *ot)
1526 {
1527         /* identifiers */
1528         ot->name= "Set Render Border";
1529         ot->description = "Set the boundries of the border render and enables border render .";
1530         ot->idname= "VIEW3D_OT_render_border";
1531
1532         /* api callbacks */
1533         ot->invoke= view3d_render_border_invoke;
1534         ot->exec= render_border_exec;
1535         ot->modal= WM_border_select_modal;
1536
1537         ot->poll= ED_operator_view3d_active;
1538
1539         /* flags */
1540         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1541
1542         /* rna */
1543         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1544         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1545         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1546         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1547
1548 }
1549 /* ********************* Border Zoom operator ****************** */
1550
1551 static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
1552 {
1553         ARegion *ar= CTX_wm_region(C);
1554         View3D *v3d = CTX_wm_view3d(C);
1555         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1556         Scene *scene= CTX_data_scene(C);
1557
1558         /* Zooms in on a border drawn by the user */
1559         rcti rect;
1560         float dvec[3], vb[2], xscale, yscale, scale;
1561
1562         /* SMOOTHVIEW */
1563         float new_dist;
1564         float new_ofs[3];
1565
1566         /* ZBuffer depth vars */
1567         bglMats mats;
1568         float depth, depth_close= FLT_MAX;
1569         int had_depth = 0;
1570         double cent[2],  p[3];
1571         int xs, ys;
1572
1573         /* note; otherwise opengl won't work */
1574         view3d_operator_needs_opengl(C);
1575
1576         /* get border select values using rna */
1577         rect.xmin= RNA_int_get(op->ptr, "xmin");
1578         rect.ymin= RNA_int_get(op->ptr, "ymin");
1579         rect.xmax= RNA_int_get(op->ptr, "xmax");
1580         rect.ymax= RNA_int_get(op->ptr, "ymax");
1581
1582         /* Get Z Depths, needed for perspective, nice for ortho */
1583         bgl_get_mats(&mats);
1584         draw_depth(scene, ar, v3d, NULL);
1585
1586         /* force updating */
1587         if (rv3d->depths) {
1588                 had_depth = 1;
1589                 rv3d->depths->damaged = 1;
1590         }
1591
1592         view3d_update_depths(ar, v3d);
1593
1594         /* Constrain rect to depth bounds */
1595         if (rect.xmin < 0) rect.xmin = 0;
1596         if (rect.ymin < 0) rect.ymin = 0;
1597         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1598         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1599
1600         /* Find the closest Z pixel */
1601         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1602                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1603                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1604                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1605                                 if (depth_close > depth) {
1606                                         depth_close = depth;
1607                                 }
1608                         }
1609                 }
1610         }
1611
1612         if (had_depth==0) {
1613                 MEM_freeN(rv3d->depths->depths);
1614                 rv3d->depths->depths = NULL;
1615         }
1616         rv3d->depths->damaged = 1;
1617
1618         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1619         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1620
1621         if (rv3d->persp==RV3D_PERSP) {
1622                 double p_corner[3];
1623
1624                 /* no depths to use, we cant do anything! */
1625                 if (depth_close==FLT_MAX){
1626                         BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1627                         return OPERATOR_CANCELLED;
1628                 }
1629                 /* convert border to 3d coordinates */
1630                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1631                         (       !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])))
1632                         return OPERATOR_CANCELLED;
1633
1634                 dvec[0] = p[0]-p_corner[0];
1635                 dvec[1] = p[1]-p_corner[1];
1636                 dvec[2] = p[2]-p_corner[2];
1637
1638                 new_dist = len_v3(dvec);
1639                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1640
1641                 new_ofs[0] = -p[0];
1642                 new_ofs[1] = -p[1];
1643                 new_ofs[2] = -p[2];
1644
1645         } else { /* othographic */
1646                 /* find the current window width and height */
1647                 vb[0] = ar->winx;
1648                 vb[1] = ar->winy;
1649
1650                 new_dist = rv3d->dist;
1651
1652                 /* convert the drawn rectangle into 3d space */
1653                 if (depth_close!=FLT_MAX && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1654                         new_ofs[0] = -p[0];
1655                         new_ofs[1] = -p[1];
1656                         new_ofs[2] = -p[2];
1657                 } else {
1658                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1659                         new_ofs[0] = rv3d->ofs[0];
1660                         new_ofs[1] = rv3d->ofs[1];
1661                         new_ofs[2] = rv3d->ofs[2];
1662
1663                         initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1664
1665                         window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1666                         /* center the view to the center of the rectangle */
1667                         sub_v3_v3v3(new_ofs, new_ofs, dvec);
1668                 }
1669
1670                 /* work out the ratios, so that everything selected fits when we zoom */
1671                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1672                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1673                 scale = (xscale >= yscale)?xscale:yscale;
1674
1675                 /* zoom in as required, or as far as we can go */
1676                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1677         }
1678
1679         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1680
1681         if(rv3d->viewlock & RV3D_BOXVIEW)
1682                 view3d_boxview_sync(CTX_wm_area(C), ar);
1683
1684         return OPERATOR_FINISHED;
1685 }
1686
1687 static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1688 {
1689         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1690
1691         /* if in camera view do not exec the operator so we do not conflict with set render border*/
1692         if (rv3d->persp != RV3D_CAMOB)
1693                 return WM_border_select_invoke(C, op, event);
1694         else
1695                 return OPERATOR_PASS_THROUGH;
1696 }
1697
1698 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1699 {
1700
1701         /* identifiers */
1702         ot->name= "Border Zoom";
1703         ot->description = "Zoom in the view to the nearest object contained in the border.";
1704         ot->idname= "VIEW3D_OT_zoom_border";
1705
1706         /* api callbacks */
1707         ot->invoke= view3d_zoom_border_invoke;
1708         ot->exec= view3d_zoom_border_exec;
1709         ot->modal= WM_border_select_modal;
1710
1711         ot->poll= ED_operator_view3d_active;
1712
1713         /* flags */
1714         ot->flag= 0;
1715
1716         /* rna */
1717         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1718         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1719         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1720         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1721
1722 }
1723 /* ********************* Changing view operator ****************** */
1724
1725 static EnumPropertyItem prop_view_items[] = {
1726         {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1727         {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1728         {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1729         {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1730         {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1731         {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1732         {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1733         {0, NULL, 0, NULL, NULL}};
1734
1735
1736 /* would like to make this a generic function - outside of transform */
1737
1738 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo, int align_active)
1739 {
1740         View3D *v3d = CTX_wm_view3d(C);
1741         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1742         float new_quat[4];
1743
1744         new_quat[0]= q1; new_quat[1]= q2;
1745         new_quat[2]= q3; new_quat[3]= q4;
1746
1747         if(align_active) {
1748                 /* align to active object */
1749                 Object *obact= CTX_data_active_object(C);
1750                 if (obact==NULL) {
1751                         /* no active object, ignore this option */
1752                         align_active= FALSE;
1753                 }
1754                 else {
1755                         float obact_quat[4];
1756                         float twmat[3][3];
1757
1758                         /* same as transform manipulator when normal is set */
1759                         ED_getTransformOrientationMatrix(C, twmat, TRUE);
1760
1761                         mat3_to_quat( obact_quat,twmat);
1762                         invert_qt(obact_quat);
1763                         mul_qt_qtqt(new_quat, new_quat, obact_quat);
1764
1765                         rv3d->view= view= 0;
1766                 }
1767         }
1768
1769         if(align_active==FALSE) {
1770                 /* normal operation */
1771                 if(rv3d->viewlock) {
1772                         /* only pass on if */
1773                         if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
1774                         else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
1775                         else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
1776                         else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
1777                         else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
1778                         else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
1779                         else return;
1780                 }
1781
1782                 rv3d->view= view;
1783         }
1784
1785         if(rv3d->viewlock) {
1786                 ED_region_tag_redraw(CTX_wm_region(C));
1787                 return;
1788         }
1789
1790         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1791
1792                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1793                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1794
1795                 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1796         }
1797         else {
1798
1799                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1800                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1801
1802                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1803         }
1804
1805 }
1806
1807 static int viewnumpad_exec(bContext *C, wmOperator *op)
1808 {
1809         View3D *v3d = CTX_wm_view3d(C);
1810         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1811         Scene *scene= CTX_data_scene(C);
1812         static int perspo=RV3D_PERSP;
1813         int viewnum, align_active, nextperspo;
1814
1815         viewnum = RNA_enum_get(op->ptr, "type");
1816         align_active = RNA_boolean_get(op->ptr, "align_active");
1817
1818
1819         /* Use this to test if we started out with a camera */
1820
1821         if (rv3d->persp == RV3D_CAMOB) {
1822                 nextperspo= rv3d->lpersp;
1823         } else {
1824                 nextperspo= perspo;
1825         }
1826
1827         switch (viewnum) {
1828                 case RV3D_VIEW_BOTTOM :
1829                         axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1830                         break;
1831
1832                 case RV3D_VIEW_BACK:
1833                         axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, nextperspo, align_active);
1834                         break;
1835
1836                 case RV3D_VIEW_LEFT:
1837                         axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, nextperspo, align_active);
1838                         break;
1839
1840                 case RV3D_VIEW_TOP:
1841                         axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1842                         break;
1843
1844                 case RV3D_VIEW_FRONT:
1845                         axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, nextperspo, align_active);
1846                         break;
1847
1848                 case RV3D_VIEW_RIGHT:
1849                         axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, nextperspo, align_active);
1850                         break;
1851
1852                 case RV3D_VIEW_CAMERA:
1853                         if(rv3d->viewlock==0) {
1854                                 /* lastview -  */
1855
1856                                 if(rv3d->persp != RV3D_CAMOB) {
1857                                         /* store settings of current view before allowing overwriting with camera view */
1858                                         QUATCOPY(rv3d->lviewquat, rv3d->viewquat);
1859                                         rv3d->lview= rv3d->view;
1860                                         rv3d->lpersp= rv3d->persp;
1861
1862         #if 0
1863                                         if(G.qual==LR_ALTKEY) {
1864                                                 if(oldcamera && is_an_active_object(oldcamera)) {
1865                                                         v3d->camera= oldcamera;
1866                                                 }
1867                                                 handle_view3d_lock();
1868                                         }
1869         #endif
1870
1871                                         if(BASACT) {
1872                                                 /* check both G.vd as G.scene cameras */
1873                                                 if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1874                                                         v3d->camera= OBACT;
1875                                                         /*handle_view3d_lock();*/
1876                                                 }
1877                                         }
1878
1879                                         if(v3d->camera==NULL) {
1880                                                 v3d->camera= scene_find_camera(scene);
1881                                                 /*handle_view3d_lock();*/
1882                                         }
1883                                         rv3d->persp= RV3D_CAMOB;
1884                                         smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
1885
1886                                 }
1887                                 else{
1888                                         /* return to settings of last view */
1889                                         /* does smooth_view too */
1890                                         axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
1891                                 }
1892                         }
1893                         break;
1894
1895                 default :
1896                         break;
1897         }
1898
1899         if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
1900
1901         return OPERATOR_FINISHED;
1902 }
1903 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1904 {
1905         /* identifiers */
1906         ot->name= "View numpad";
1907         ot->description = "Set the view.";
1908         ot->idname= "VIEW3D_OT_viewnumpad";
1909
1910         /* api callbacks */
1911         ot->exec= viewnumpad_exec;
1912         ot->poll= ED_operator_view3d_active;
1913
1914         /* flags */
1915         ot->flag= 0;
1916
1917         RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
1918         RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
1919 }
1920
1921 static EnumPropertyItem prop_view_orbit_items[] = {
1922         {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
1923         {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
1924         {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
1925         {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
1926         {0, NULL, 0, NULL, NULL}};
1927
1928 static int vieworbit_exec(bContext *C, wmOperator *op)
1929 {
1930         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1931         float phi, si, q1[4], new_quat[4];
1932         int orbitdir;
1933
1934         orbitdir = RNA_enum_get(op->ptr, "type");
1935
1936         if(rv3d->viewlock==0) {
1937
1938                 if(rv3d->persp != RV3D_CAMOB) {
1939                         if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
1940                                 /* z-axis */
1941                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1942                                 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
1943                                 si= (float)sin(phi);
1944                                 q1[0]= (float)cos(phi);
1945                                 q1[1]= q1[2]= 0.0;
1946                                 q1[3]= si;
1947                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
1948                                 rv3d->view= 0;
1949                         }
1950                         else if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
1951                                 /* horizontal axis */
1952                                 VECCOPY(q1+1, rv3d->viewinv[0]);
1953
1954                                 normalize_v3(q1+1);
1955                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1956                                 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
1957                                 si= (float)sin(phi);
1958                                 q1[0]= (float)cos(phi);
1959                                 q1[1]*= si;
1960                                 q1[2]*= si;
1961                                 q1[3]*= si;
1962                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
1963                                 rv3d->view= 0;
1964                         }
1965
1966                         smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1967                 }
1968         }
1969
1970         return OPERATOR_FINISHED;
1971 }
1972
1973 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
1974 {
1975         /* identifiers */
1976         ot->name= "View Orbit";
1977         ot->description = "Orbit the view.";
1978         ot->idname= "VIEW3D_OT_view_orbit";
1979
1980         /* api callbacks */
1981         ot->exec= vieworbit_exec;
1982         ot->poll= ED_operator_view3d_rotate;
1983
1984         /* flags */
1985         ot->flag= 0;
1986         RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
1987 }
1988
1989 static EnumPropertyItem prop_view_pan_items[] = {
1990         {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
1991         {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
1992         {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
1993         {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
1994         {0, NULL, 0, NULL, NULL}};
1995
1996 static int viewpan_exec(bContext *C, wmOperator *op)
1997 {
1998         ARegion *ar= CTX_wm_region(C);
1999         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2000         float vec[3];
2001         int pandir;
2002
2003         pandir = RNA_enum_get(op->ptr, "type");
2004
2005         initgrabz(rv3d, 0.0, 0.0, 0.0);
2006
2007         if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
2008         else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
2009         else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
2010         else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
2011         rv3d->ofs[0]+= vec[0];
2012         rv3d->ofs[1]+= vec[1];
2013         rv3d->ofs[2]+= vec[2];
2014
2015         if(rv3d->viewlock & RV3D_BOXVIEW)
2016                 view3d_boxview_sync(CTX_wm_area(C), ar);
2017
2018         ED_region_tag_redraw(ar);
2019
2020         return OPERATOR_FINISHED;
2021 }
2022
2023 void VIEW3D_OT_view_pan(wmOperatorType *ot)
2024 {
2025         /* identifiers */
2026         ot->name= "View Pan";
2027         ot->description = "Pan the view.";
2028         ot->idname= "VIEW3D_OT_view_pan";
2029
2030         /* api callbacks */
2031         ot->exec= viewpan_exec;
2032         ot->poll= ED_operator_view3d_active;
2033
2034         /* flags */
2035         ot->flag= 0;
2036         RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
2037 }
2038
2039 static int viewpersportho_exec(bContext *C, wmOperator *op)
2040 {
2041         ARegion *ar= CTX_wm_region(C);
2042         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2043
2044         if(rv3d->viewlock==0) {
2045                 if(rv3d->persp!=RV3D_ORTHO)
2046                         rv3d->persp=RV3D_ORTHO;
2047                 else rv3d->persp=RV3D_PERSP;
2048                 ED_region_tag_redraw(ar);
2049         }
2050
2051         return OPERATOR_FINISHED;
2052
2053 }
2054
2055 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
2056 {
2057         /* identifiers */
2058         ot->name= "View Persp/Ortho";
2059         ot->description = "Switch the current view from perspective/orthographic.";
2060         ot->idname= "VIEW3D_OT_view_persportho";
2061
2062         /* api callbacks */
2063         ot->exec= viewpersportho_exec;
2064         ot->poll= ED_operator_view3d_active;
2065
2066         /* flags */
2067         ot->flag= 0;
2068 }
2069
2070
2071 /* ********************* set clipping operator ****************** */
2072
2073 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
2074 {
2075         int val;
2076
2077         for(val=0; val<4; val++) {
2078
2079                 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
2080
2081                 clip[val][3]=
2082                         - clip[val][0]*clipbb->vec[val][0]
2083                         - clip[val][1]*clipbb->vec[val][1]
2084                         - clip[val][2]*clipbb->vec[val][2];
2085         }
2086 }
2087
2088 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
2089 {
2090         BoundBox clipbb_local;
2091         float imat[4][4];
2092         int i;
2093
2094         invert_m4_m4(imat, mat);
2095
2096         for(i=0; i<8; i++) {
2097                 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
2098         }
2099
2100         calc_clipping_plane(clip_local, &clipbb_local);
2101 }
2102
2103 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
2104 {
2105         if(rv3d->rflag & RV3D_CLIPPING)
2106                 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
2107 }
2108
2109 static int view3d_clipping_exec(bContext *C, wmOperator *op)
2110 {
2111         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2112         ViewContext vc;
2113         bglMats mats;
2114         rcti rect;
2115
2116         rect.xmin= RNA_int_get(op->ptr, "xmin");
2117         rect.ymin= RNA_int_get(op->ptr, "ymin");
2118         rect.xmax= RNA_int_get(op->ptr, "xmax");
2119         rect.ymax= RNA_int_get(op->ptr, "ymax");
2120
2121         rv3d->rflag |= RV3D_CLIPPING;
2122         rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
2123
2124         /* note; otherwise opengl won't work */
2125         view3d_operator_needs_opengl(C);
2126
2127         view3d_set_viewcontext(C, &vc);
2128         view3d_get_transformation(vc.ar, vc.rv3d, NULL, &mats); /* NULL because we don't want it in object space */
2129         view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
2130
2131         return OPERATOR_FINISHED;
2132 }
2133
2134 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
2135 {
2136         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2137         ARegion *ar= CTX_wm_region(C);
2138
2139         if(rv3d->rflag & RV3D_CLIPPING) {
2140                 rv3d->rflag &= ~RV3D_CLIPPING;
2141                 ED_region_tag_redraw(ar);
2142                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
2143                 rv3d->clipbb= NULL;
2144                 return OPERATOR_FINISHED;
2145         }
2146         else {
2147                 return WM_border_select_invoke(C, op, event);
2148         }
2149 }
2150
2151 /* toggles */
2152 void VIEW3D_OT_clip_border(wmOperatorType *ot)
2153 {
2154
2155         /* identifiers */
2156         ot->name= "Clipping Border";
2157         ot->description = "Set the view clipping border.";
2158         ot->idname= "VIEW3D_OT_clip_border";
2159
2160         /* api callbacks */
2161         ot->invoke= view3d_clipping_invoke;
2162         ot->exec= view3d_clipping_exec;
2163         ot->modal= WM_border_select_modal;
2164
2165         ot->poll= ED_operator_view3d_active;
2166
2167         /* flags */
2168         ot->flag= 0;
2169
2170         /* rna */
2171         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2172         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2173         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2174         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2175 }
2176
2177 /* ***************** 3d cursor cursor op ******************* */
2178
2179 /* mx my in region coords */
2180 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
2181 {
2182         Scene *scene= CTX_data_scene(C);
2183         ARegion *ar= CTX_wm_region(C);
2184         View3D *v3d = CTX_wm_view3d(C);
2185         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2186         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2187         short mx, my, mval[2];
2188 //      short ctrl= 0; // XXX
2189
2190         fp= give_cursor(scene, v3d);
2191
2192 //      if(obedit && ctrl) lr_click= 1;
2193         VECCOPY(oldcurs, fp);
2194
2195         mx= event->x - ar->winrct.xmin;
2196         my= event->y - ar->winrct.ymin;
2197         project_short_noclip(ar, fp, mval);
2198
2199         initgrabz(rv3d, fp[0], fp[1], fp[2]);
2200
2201         if(mval[0]!=IS_CLIPPED) {
2202
2203                 window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2204                 sub_v3_v3v3(fp, fp, dvec);
2205         }
2206         else {
2207
2208                 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2209                 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2210
2211                 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2212                 fz= fz/rv3d->zfac;
2213
2214                 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2215                 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2216                 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2217         }
2218
2219         if(v3d && v3d->localvd)
2220                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2221         else
2222                 WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene);
2223
2224         return OPERATOR_FINISHED;
2225 }
2226
2227 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2228 {
2229
2230         /* identifiers */
2231         ot->name= "Set 3D Cursor";
2232         ot->description = "Set the location of the 3D cursor.";
2233         ot->idname= "VIEW3D_OT_cursor3d";
2234
2235         /* api callbacks */
2236         ot->invoke= set_3dcursor_invoke;
2237
2238         ot->poll= ED_operator_view3d_active;
2239     
2240         /* flags */
2241 //      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2242     
2243         /* rna later */
2244
2245 }
2246
2247 /* ***************** manipulator op ******************* */
2248
2249
2250 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2251 {
2252         View3D *v3d = CTX_wm_view3d(C);
2253
2254         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2255         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2256
2257         /* only no modifier or shift */
2258         if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2259
2260         /* note; otherwise opengl won't work */
2261         view3d_operator_needs_opengl(C);
2262
2263         if(0==BIF_do_manipulator(C, event, op))
2264                 return OPERATOR_PASS_THROUGH;
2265
2266         return OPERATOR_FINISHED;
2267 }
2268
2269 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2270 {
2271
2272         /* identifiers */
2273         ot->name= "3D Manipulator";
2274         ot->description = "Manipulate selected item by axis.";
2275         ot->idname= "VIEW3D_OT_manipulator";
2276
2277         /* api callbacks */
2278         ot->invoke= manipulator_invoke;
2279
2280         ot->poll= ED_operator_view3d_active;
2281
2282         /* rna later */
2283         RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
2284 }
2285
2286
2287
2288 /* ************************* below the line! *********************** */
2289
2290
2291 static float view_autodist_depth_margin(ARegion *ar, short *mval, int margin)
2292 {
2293         RegionView3D *rv3d= ar->regiondata;
2294         float depth= FLT_MAX;
2295
2296         if(margin==0) {
2297                 if (mval[0] < 0) return 0;
2298                 if (mval[1] < 0) return 0;
2299                 if (mval[0] >= rv3d->depths->w) return 0;
2300                 if (mval[1] >= rv3d->depths->h) return 0;
2301
2302                 /* Get Z Depths, needed for perspective, nice for ortho */
2303                 depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
2304                 if(depth >= rv3d->depths->depth_range[1] || depth <= rv3d->depths->depth_range[0]) {
2305                         depth= FLT_MAX;
2306                 }
2307         }
2308         else {
2309                 rcti rect;
2310                 float depth_close= FLT_MAX;
2311                 int xs, ys;
2312
2313                 rect.xmax = mval[0] + margin;
2314                 rect.ymax = mval[1] + margin;
2315
2316                 rect.xmin = mval[0] - margin;
2317                 rect.ymin = mval[1] - margin;
2318
2319                 /* Constrain rect to depth bounds */
2320                 if (rect.xmin < 0) rect.xmin = 0;
2321                 if (rect.ymin < 0) rect.ymin = 0;
2322                 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
2323                 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
2324
2325                 /* Find the closest Z pixel */
2326                 for (xs=rect.xmin; xs < rect.xmax; xs++) {
2327                         for (ys=rect.ymin; ys < rect.ymax; ys++) {
2328                                 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
2329                                 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
2330                                         if (depth_close > depth) {
2331                                                 depth_close = depth;
2332                                         }
2333                                 }
2334                         }
2335                 }
2336
2337                 depth= depth_close;
2338         }
2339
2340         return depth;
2341 }
2342
2343 /* XXX todo Zooms in on a border drawn by the user */
2344 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2345 {
2346         RegionView3D *rv3d= ar->regiondata;
2347         bglMats mats; /* ZBuffer depth vars */
2348         float depth_close= FLT_MAX;
2349         int had_depth = 0;
2350         double cent[2],  p[3];
2351
2352         /* Get Z Depths, needed for perspective, nice for ortho */
2353         bgl_get_mats(&mats);
2354         draw_depth(scene, ar, v3d, NULL);
2355
2356         /* force updating */
2357         if (rv3d->depths) {
2358                 had_depth = 1;
2359                 rv3d->depths->damaged = 1;
2360         }
2361
2362         view3d_update_depths(ar, v3d);
2363
2364         depth_close= view_autodist_depth_margin(ar, mval, 4);
2365
2366         if (depth_close==FLT_MAX)
2367                 return 0;
2368
2369         if (had_depth==0) {
2370                 MEM_freeN(rv3d->depths->depths);
2371                 rv3d->depths->depths = NULL;
2372         }
2373         rv3d->depths->damaged = 1;
2374
2375         cent[0] = (double)mval[0];
2376         cent[1] = (double)mval[1];
2377
2378         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2379                 return 0;
2380
2381         mouse_worldloc[0] = (float)p[0];
2382         mouse_worldloc[1] = (float)p[1];
2383         mouse_worldloc[2] = (float)p[2];
2384         return 1;
2385 }
2386
2387 int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode) //, float *autodist )
2388 {
2389         RegionView3D *rv3d= ar->regiondata;
2390
2391         /* Get Z Depths, needed for perspective, nice for ortho */
2392         switch(mode) {
2393         case 0:
2394                 draw_depth(scene, ar, v3d, NULL);
2395                 break;
2396         case 1:
2397                 draw_depth_gpencil(scene, ar, v3d);
2398                 break;
2399         }
2400
2401         /* force updating */
2402         if (rv3d->depths) {
2403                 rv3d->depths->damaged = 1;
2404         }
2405
2406         view3d_update_depths(ar, v3d);
2407         return 1;
2408 }
2409
2410 // no 4x4 sampling, run view_autodist_init first
2411 int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3], int margin, float *force_depth) //, float *autodist )
2412 {
2413         bglMats mats; /* ZBuffer depth vars, could cache? */
2414         float depth;
2415         double cent[2],  p[3];
2416
2417         /* Get Z Depths, needed for perspective, nice for ortho */
2418         if(force_depth)
2419                 depth= *force_depth;
2420         else
2421                 depth= view_autodist_depth_margin(ar, mval, margin);
2422
2423         if (depth==FLT_MAX)
2424                 return 0;
2425
2426         cent[0] = (double)mval[0];
2427         cent[1] = (double)mval[1];
2428
2429         bgl_get_mats(&mats);
2430         if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2431                 return 0;
2432
2433         mouse_worldloc[0] = (float)p[0];
2434         mouse_worldloc[1] = (float)p[1];
2435         mouse_worldloc[2] = (float)p[2];
2436         return 1;
2437 }
2438
2439 int view_autodist_depth(struct ARegion *ar, short *mval, int margin, float *depth)
2440 {
2441         *depth= view_autodist_depth_margin(ar, mval, margin);
2442
2443         return (*depth==FLT_MAX) ? 0:1;
2444                 return 0;
2445 }
2446
2447 /* ********************* NDOF ************************ */
2448 /* note: this code is confusing and unclear... (ton) */
2449 /* **************************************************** */
2450
2451 // ndof scaling will be moved to user setting.
2452 // In the mean time this is just a place holder.
2453
2454 // Note: scaling in the plugin and ghostwinlay.c
2455 // should be removed. With driver default setting,
2456 // each axis returns approx. +-200 max deflection.
2457
2458 // The values I selected are based on the older
2459 // polling i/f. With event i/f, the sensistivity
2460 // can be increased for improved response from
2461 // small deflections of the device input.
2462
2463
2464 // lukep notes : i disagree on the range.
2465 // the normal 3Dconnection driver give +/-400
2466 // on defaut range in other applications
2467 // and up to +/- 1000 if set to maximum
2468 // because i remove the scaling by delta,
2469 // which was a bad idea as it depend of the system
2470 // speed and os, i changed the scaling values, but
2471 // those are still not ok
2472
2473
2474 float ndof_axis_scale[6] = {
2475         +0.01,  // Tx
2476         +0.01,  // Tz
2477         +0.01,  // Ty
2478         +0.0015,        // Rx
2479         +0.0015,        // Rz
2480         +0.0015 // Ry
2481 };
2482
2483 void filterNDOFvalues(float *sbval)
2484 {
2485         int i=0;
2486         float max  = 0.0;
2487
2488         for (i =0; i<6;i++)
2489                 if (fabs(sbval[i]) > max)
2490                         max = fabs(sbval[i]);
2491         for (i =0; i<6;i++)
2492                 if (fabs(sbval[i]) != max )
2493                         sbval[i]=0.0;
2494 }
2495
2496 // statics for controlling rv3d->dist corrections.
2497 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2498 // viewmove restores based on dz_flag state.
2499
2500 int dz_flag = 0;
2501 float m_dist;
2502
2503 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2504 {
2505         RegionView3D *rv3d= ar->regiondata;
2506     int i;
2507     float phi;
2508     float dval[7];
2509         // static fval[6] for low pass filter; device input vector is dval[6]
2510         static float fval[6];
2511     float tvec[3],rvec[3];
2512     float q1[4];
2513         float mat[3][3];
2514         float upvec[3];
2515
2516
2517     /*----------------------------------------------------
2518          * sometimes this routine is called from headerbuttons
2519      * viewmove needs to refresh the screen
2520      */
2521 // XXX  areawinset(ar->win);
2522
2523
2524         // fetch the current state of the ndof device
2525 // XXX  getndof(dval);
2526
2527         if (v3d->ndoffilter)
2528                 filterNDOFvalues(fval);
2529
2530         // Scale input values
2531
2532 //      if(dval[6] == 0) return; // guard against divide by zero
2533
2534         for(i=0;i<6;i++) {
2535
2536                 // user scaling
2537                 dval[i] = dval[i] * ndof_axis_scale[i];
2538         }
2539
2540
2541         // low pass filter with zero crossing reset
2542
2543         for(i=0;i<6;i++) {
2544                 if((dval[i] * fval[i]) >= 0)
2545                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
2546                 else
2547                         fval[i] = 0;
2548         }
2549
2550
2551         // force perspective mode. This is a hack and is
2552         // incomplete. It doesn't actually effect the view
2553         // until the first draw and doesn't update the menu
2554         // to reflect persp mode.
2555
2556         rv3d->persp = RV3D_PERSP;
2557
2558
2559         // Correct the distance jump if rv3d->dist != 0
2560
2561         // This is due to a side effect of the original
2562         // mouse view rotation code. The rotation point is
2563         // set a distance in front of the viewport to
2564         // make rotating with the mouse look better.
2565         // The distance effect is written at a low level
2566         // in the view management instead of the mouse
2567         // view function. This means that all other view
2568         // movement devices must subtract this from their
2569         // view transformations.
2570
2571         if(rv3d->dist != 0.0) {
2572                 dz_flag = 1;
2573                 m_dist = rv3d->dist;
2574                 upvec[0] = upvec[1] = 0;
2575                 upvec[2] = rv3d->dist;
2576                 copy_m3_m4(mat, rv3d->viewinv);
2577                 mul_m3_v3(mat, upvec);
2578                 sub_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2579                 rv3d->dist = 0.0;
2580         }
2581
2582
2583         // Apply rotation
2584         // Rotations feel relatively faster than translations only in fly mode, so
2585         // we have no choice but to fix that here (not in the plugins)
2586         rvec[0] = -0.5 * dval[3];
2587         rvec[1] = -0.5 * dval[4];
2588         rvec[2] = -0.5 * dval[5];
2589
2590         // rotate device x and y by view z
2591
2592         copy_m3_m4(mat, rv3d->viewinv);
2593         mat[2][2] = 0.0f;
2594         mul_m3_v3(mat, rvec);
2595
2596         // rotate the view
2597
2598         phi = normalize_v3(rvec);
2599         if(phi != 0) {
2600                 axis_angle_to_quat(q1,rvec,phi);
2601                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2602         }
2603
2604
2605         // Apply translation
2606
2607         tvec[0] = dval[0];
2608         tvec[1] = dval[1];
2609         tvec[2] = -dval[2];
2610
2611         // the next three lines rotate the x and y translation coordinates
2612         // by the current z axis angle
2613
2614         copy_m3_m4(mat, rv3d->viewinv);
2615         mat[2][2] = 0.0f;
2616         mul_m3_v3(mat, tvec);
2617
2618         // translate the view
2619
2620         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, tvec);
2621
2622
2623         /*----------------------------------------------------
2624      * refresh the screen XXX
2625       */
2626
2627         // update render preview window
2628
2629 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2630 }
2631
2632 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2633 {
2634         RegionView3D *rv3d= ar->regiondata;
2635         float fval[7];
2636         float dvec[3];
2637         float sbadjust = 1.0f;
2638         float len;
2639         short use_sel = 0;
2640         Object *ob = OBACT;
2641         float m[3][3];
2642         float m_inv[3][3];
2643         float xvec[3] = {1,0,0};
2644         float yvec[3] = {0,-1,0};
2645         float zvec[3] = {0,0,1};
2646         float phi, si;
2647         float q1[4];
2648         float obofs[3];
2649         float reverse;
2650         //float diff[4];
2651         float d, curareaX, curareaY;
2652         float mat[3][3];
2653         float upvec[3];
2654
2655     /* Sensitivity will control how fast the view rotates.  The value was
2656      * obtained experimentally by tweaking until the author didn't get dizzy watching.
2657      * Perhaps this should be a configurable user parameter.
2658      */
2659         float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
2660         float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
2661         float zsens = 0.3f;   /* zoom sensitivity */
2662
2663         const float minZoom = -30.0f;
2664         const float maxZoom = 300.0f;
2665
2666         //reset view type
2667         rv3d->view = 0;
2668 //printf("passing here \n");
2669 //
2670         if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
2671                 use_sel = 1;
2672         }
2673
2674         if((dz_flag)||rv3d->dist==0) {
2675                 dz_flag = 0;
2676                 rv3d->dist = m_dist;
2677                 upvec[0] = upvec[1] = 0;
2678                 upvec[2] = rv3d->dist;
2679                 copy_m3_m4(mat, rv3d->viewinv);
2680                 mul_m3_v3(mat, upvec);
2681                 add_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2682         }
2683
2684     /*----------------------------------------------------
2685          * sometimes this routine is called from headerbuttons
2686      * viewmove needs to refresh the screen
2687      */
2688 // XXX  areawinset(curarea->win);
2689
2690     /*----------------------------------------------------
2691      * record how much time has passed. clamp at 10 Hz
2692      * pretend the previous frame occured at the clamped time
2693      */
2694 //    now = PIL_check_seconds_timer();
2695  //   frametime = (now - prevTime);
2696  //   if (frametime > 0.1f){        /* if more than 1/10s */
2697  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
2698 //    }
2699 //    prevTime = now;
2700  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
2701
2702     /* fetch the current state of the ndof device & enforce dominant mode if selected */
2703 // XXX    getndof(fval);
2704         if (v3d->ndoffilter)
2705                 filterNDOFvalues(fval);
2706
2707
2708     // put scaling back here, was previously in ghostwinlay
2709         fval[0] = fval[0] * (1.0f/600.0f);
2710         fval[1] = fval[1] * (1.0f/600.0f);
2711         fval[2] = fval[2] * (1.0f/1100.0f);
2712         fval[3] = fval[3] * 0.00005f;
2713         fval[4] =-fval[4] * 0.00005f;
2714         fval[5] = fval[5] * 0.00005f;
2715         fval[6] = fval[6] / 1000000.0f;
2716
2717     // scale more if not in perspective mode
2718         if (rv3d->persp == RV3D_ORTHO) {
2719                 fval[0] = fval[0] * 0.05f;
2720                 fval[1] = fval[1] * 0.05f;
2721                 fval[2] = fval[2] * 0.05f;
2722                 fval[3] = fval[3] * 0.9f;
2723                 fval[4] = fval[4] * 0.9f;
2724                 fval[5] = fval[5] * 0.9f;
2725                 zsens *= 8;
2726         }
2727
2728     /* set object offset */
2729         if (ob) {
2730                 obofs[0] = -ob->obmat[3][0];
2731                 obofs[1] = -ob->obmat[3][1];
2732                 obofs[2] = -ob->obmat[3][2];
2733         }
2734         else {
2735                 VECCOPY(obofs, rv3d->ofs);
2736         }
2737
2738     /* calc an adjustment based on distance from camera
2739        disabled per patch 14402 */
2740      d = 1.0f;
2741
2742 /*    if (ob) {
2743         sub_v3_v3v3(diff, obofs, rv3d->ofs);
2744         d = len_v3(diff);
2745     }
2746 */
2747
2748     reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
2749
2750     /*----------------------------------------------------
2751      * ndof device pan
2752      */
2753     psens *= 1.0f + d;
2754     curareaX = sbadjust * psens * fval[0];
2755     curareaY = sbadjust * psens * fval[1];
2756     dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
2757     dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
2758     dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
2759     add_v3_v3v3(rv3d->ofs, rv3d->ofs, dvec);
2760
2761     /*----------------------------------------------------
2762      * ndof device dolly
2763      */
2764     len = zsens * sbadjust * fval[2];
2765
2766     if (rv3d->persp==RV3D_CAMOB) {
2767         if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
2768             rv3d->camzoom+= 10.0f * -len;
2769         }
2770         if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
2771         else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
2772     }
2773     else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
2774         rv3d->dist*=(1.0 + len);
2775     }
2776
2777
2778     /*----------------------------------------------------
2779      * ndof device turntable
2780      * derived from the turntable code in viewmove
2781      */
2782
2783     /* Get the 3x3 matrix and its inverse from the quaternion */
2784     quat_to_mat3( m,rv3d->viewquat);
2785     invert_m3_m3(m_inv,m);
2786
2787     /* Determine the direction of the x vector (for rotating up and down) */
2788     /* This can likely be compuated directly from the quaternion. */
2789     mul_m3_v3(m_inv,xvec);
2790     mul_m3_v3(m_inv,yvec);
2791     mul_m3_v3(m_inv,zvec);
2792
2793     /* Perform the up/down rotation */
2794     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
2795     si = sin(phi);
2796     q1[0] = cos(phi);
2797     q1[1] = si * xvec[0];
2798     q1[2] = si * xvec[1];
2799     q1[3] = si * xvec[2];
2800     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2801
2802     if (use_sel) {
2803         conjugate_qt(q1); /* conj == inv for unit quat */
2804         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2805         mul_qt_v3(q1, rv3d->ofs);
2806         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2807     }
2808
2809     /* Perform the orbital rotation */
2810     /* Perform the orbital rotation
2811        If the seen Up axis is parallel to the zoom axis, rotation should be
2812        achieved with a pure Roll motion (no Spin) on the device. When you start
2813        to tilt, moving from Top to Side view, Spinning will increasingly become
2814        more relevant while the Roll component will decrease. When a full
2815        Side view is reached, rotations around the world's Up axis are achieved
2816        with a pure Spin-only motion.  In other words the control of the spinning
2817        around the world's Up axis should move from the device's Spin axis to the
2818        device's Roll axis depending on the orientation of the world's Up axis
2819        relative to the screen. */
2820     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
2821     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
2822     q1[0] = cos(phi);
2823     q1[1] = q1[2] = 0.0;
2824     q1[3] = sin(phi);
2825     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2826
2827     if (use_sel) {
2828         conjugate_qt(q1);
2829         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2830         mul_qt_v3(q1, rv3d->ofs);
2831         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2832     }
2833
2834     /*----------------------------------------------------
2835      * refresh the screen
2836      */
2837 // XXX    scrarea_do_windraw(curarea);
2838 }
2839
2840
2841
2842