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