aee4b2515ec7b372e919bf98d4362ac5aed2b8e7
[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 viewquat_inv[4];
604                 float zaxis[3]={0,0,1};
605                 invert_qt_qt(viewquat_inv, rv3d->viewquat);
606
607                 mul_qt_v3(viewquat_inv, zaxis);
608
609                 for (i = 0 ; i < 39; i++){
610
611                         float view = (int)snapquats[i][4];
612                         float viewquat_inv_test[4];
613                         float zaxis_test[3]={0,0,1};
614
615                         invert_qt_qt(viewquat_inv_test, snapquats[i]);
616                         mul_qt_v3(viewquat_inv_test, zaxis_test);
617                         
618                         if(angle_v3v3(zaxis_test, zaxis) < DEG2RAD(45/3)) {
619                                 /* find the best roll */
620                                 float quat_roll[4], quat_final[4], quat_best[4];
621                                 float viewquat_align[4]; /* viewquat aligned to zaxis_test */
622                                 float viewquat_align_inv[4]; /* viewquat aligned to zaxis_test */
623                                 float best_angle = FLT_MAX;
624                                 int j;
625
626                                 /* viewquat_align is the original viewquat aligned to the snapped axis
627                                  * for testing roll */
628                                 rotation_between_vecs_to_quat(viewquat_align, zaxis_test, zaxis);
629                                 normalize_qt(viewquat_align);
630                                 mul_qt_qtqt(viewquat_align, rv3d->viewquat, viewquat_align);
631                                 normalize_qt(viewquat_align);
632                                 invert_qt_qt(viewquat_align_inv, viewquat_align);
633
634                                 /* find best roll */
635                                 for(j= 0; j<8; j++) {
636                                         float angle;
637                                         float xaxis1[3]={1,0,0};
638                                         float xaxis2[3]={1,0,0};
639                                         float quat_final_inv[4];
640
641                                         axis_angle_to_quat(quat_roll, zaxis_test, j * DEG2RAD(45.0));
642                                         normalize_qt(quat_roll);
643
644                                         mul_qt_qtqt(quat_final, snapquats[i], quat_roll);
645                                         normalize_qt(quat_final);
646                                         
647                                         /* compare 2 vector angles to find the least roll */
648                                         invert_qt_qt(quat_final_inv, quat_final);
649                                         mul_qt_v3(viewquat_align_inv, xaxis1);
650                                         mul_qt_v3(quat_final_inv, xaxis2);
651                                         angle= angle_v3v3(xaxis1, xaxis2);
652
653                                         if(angle <= best_angle) {
654                                                 best_angle= angle;
655                                                 copy_qt_qt(quat_best, quat_final);
656                                                 if(j) view= 0; /* view grid assumes certain up axis */
657                                         }
658                                 }
659
660                                 copy_qt_qt(rv3d->viewquat, quat_best);
661                                 rv3d->view= view; /* if we snap to a rolled camera the grid is invalid */
662
663                                 break;
664                         }
665                 }
666         }
667         vod->oldx= x;
668         vod->oldy= y;
669
670         ED_region_tag_redraw(vod->ar);
671 }
672
673 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
674 {
675         ViewOpsData *vod= op->customdata;
676         short event_code= VIEW_PASS;
677
678         /* execute the events */
679         if(event->type==MOUSEMOVE) {
680                 event_code= VIEW_APPLY;
681         }
682         else if(event->type==EVT_MODAL_MAP) {
683                 switch (event->val) {
684                         case VIEW_MODAL_CONFIRM:
685                                 event_code= VIEW_CONFIRM;
686                                 break;
687                         case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
688                                 vod->axis_snap= TRUE;
689                                 event_code= VIEW_APPLY;
690                                 break;
691                         case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
692                                 vod->axis_snap= FALSE;
693                                 event_code= VIEW_APPLY;
694                                 break;
695                         case VIEWROT_MODAL_SWITCH_ZOOM:
696                                 WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
697                                 event_code= VIEW_CONFIRM;
698                                 break;
699                         case VIEWROT_MODAL_SWITCH_MOVE:
700                                 WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
701                                 event_code= VIEW_CONFIRM;
702                                 break;
703                 }
704         }
705         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
706                 event_code= VIEW_CONFIRM;
707         }
708
709         if(event_code==VIEW_APPLY) {
710                 viewrotate_apply(vod, event->x, event->y);
711         }
712         else if (event_code==VIEW_CONFIRM) {
713                 request_depth_update(CTX_wm_region_view3d(C));
714                 viewops_data_free(C, op);
715
716                 return OPERATOR_FINISHED;
717         }
718
719         return OPERATOR_RUNNING_MODAL;
720 }
721
722 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
723 {
724         RegionView3D *rv3d= CTX_wm_region_view3d(C);
725         ViewOpsData *vod;
726
727         if(rv3d->viewlock)
728                 return OPERATOR_CANCELLED;
729
730         /* makes op->customdata */
731         viewops_data_create(C, op, event);
732         vod= op->customdata;
733
734         /* switch from camera view when: */
735         if(vod->rv3d->persp != RV3D_PERSP) {
736
737                 if (U.uiflag & USER_AUTOPERSP)
738                         vod->rv3d->persp= RV3D_PERSP;
739                 else if(vod->rv3d->persp==RV3D_CAMOB) {
740
741                         /* changed since 2.4x, use the camera view */
742                         View3D *v3d = CTX_wm_view3d(C);
743                         if(v3d->camera)
744                                 view3d_settings_from_ob(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
745
746                         vod->rv3d->persp= RV3D_PERSP;
747                 }
748                 ED_region_tag_redraw(vod->ar);
749         }
750         
751         if (event->type == MOUSEPAN) {
752                 viewrotate_apply(vod, event->prevx, event->prevy);
753                 request_depth_update(CTX_wm_region_view3d(C));
754                 
755                 viewops_data_free(C, op);
756                 
757                 return OPERATOR_FINISHED;
758         }
759         else if (event->type == MOUSEROTATE) {
760                 /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
761                 viewrotate_apply(vod, event->prevx, event->y);
762                 request_depth_update(CTX_wm_region_view3d(C));
763                 
764                 viewops_data_free(C, op);
765                 
766                 return OPERATOR_FINISHED;
767         }
768         else {          
769                 /* add temp handler */
770                 WM_event_add_modal_handler(C, op);
771
772                 return OPERATOR_RUNNING_MODAL;
773         }
774 }
775
776 static int view3d_camera_active_poll(bContext *C)
777 {
778         if(ED_operator_view3d_active(C)) {
779                 RegionView3D *rv3d= CTX_wm_region_view3d(C);
780                 if(rv3d && rv3d->persp==RV3D_CAMOB) {
781                         return 1;
782                 }
783         }
784
785         return 0;
786 }
787
788 static int view3d_rotate_poll(bContext *C)
789 {
790         if (!ED_operator_view3d_active(C)) {
791                 return 0;
792         } else {
793                 RegionView3D *rv3d= CTX_wm_region_view3d(C);
794                 /* rv3d is null in menus, but it's ok when the menu is clicked on */
795                 /* XXX of course, this doesn't work with quadview
796                  * Maybe having exec return PASSTHROUGH would be better than polling here
797                  * Poll functions are full of problems anyway.
798                  * */
799                 return rv3d == NULL || rv3d->viewlock == 0;
800         }
801 }
802
803 void VIEW3D_OT_rotate(wmOperatorType *ot)
804 {
805
806         /* identifiers */
807         ot->name= "Rotate view";
808         ot->description = "Rotate the view";
809         ot->idname= "VIEW3D_OT_rotate";
810
811         /* api callbacks */
812         ot->invoke= viewrotate_invoke;
813         ot->modal= viewrotate_modal;
814         ot->poll= view3d_rotate_poll;
815
816         /* flags */
817         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
818 }
819
820 /* ************************ viewmove ******************************** */
821
822
823 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
824
825 /* called in transform_ops.c, on each regeneration of keymaps  */
826 void viewmove_modal_keymap(wmKeyConfig *keyconf)
827 {
828         static EnumPropertyItem modal_items[] = {
829         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Confirm", ""},
830
831         {0, NULL, 0, NULL, NULL}};
832
833         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Move Modal");
834
835         /* this function is called for each spacetype, only needs to add map once */
836         if(keymap) return;
837
838         keymap= WM_modalkeymap_add(keyconf, "View3D Move Modal", modal_items);
839
840         /* items for modal map */
841         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
842         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
843
844         /* disabled mode switching for now, can re-implement better, later on
845         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
846         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
847         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
848         */
849         
850         /* assign map to operators */
851         WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
852 }
853
854
855 static void viewmove_apply(ViewOpsData *vod, int x, int y)
856 {
857         if(vod->rv3d->persp==RV3D_CAMOB) {
858                 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
859
860                 vod->rv3d->camdx += (vod->oldx - x)/(max);
861                 vod->rv3d->camdy += (vod->oldy - y)/(max);
862                 CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
863                 CLAMP(vod->rv3d->camdy, -1.0f, 1.0f);
864 // XXX          preview3d_event= 0;
865         }
866         else {
867                 float dvec[3];
868
869                 window_to_3d_delta(vod->ar, dvec, x-vod->oldx, y-vod->oldy);
870                 add_v3_v3(vod->rv3d->ofs, dvec);
871
872                 if(vod->rv3d->viewlock & RV3D_BOXVIEW)
873                         view3d_boxview_sync(vod->sa, vod->ar);
874         }
875
876         vod->oldx= x;
877         vod->oldy= y;
878
879         ED_region_tag_redraw(vod->ar);
880 }
881
882
883 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
884 {
885
886         ViewOpsData *vod= op->customdata;
887         short event_code= VIEW_PASS;
888
889         /* execute the events */
890         if(event->type==MOUSEMOVE) {
891                 event_code= VIEW_APPLY;
892         }
893         else if(event->type==EVT_MODAL_MAP) {
894                 switch (event->val) {
895                         case VIEW_MODAL_CONFIRM:
896                                 event_code= VIEW_CONFIRM;
897                                 break;
898                         case VIEWROT_MODAL_SWITCH_ZOOM:
899                                 WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
900                                 event_code= VIEW_CONFIRM;
901                                 break;
902                         case VIEWROT_MODAL_SWITCH_ROTATE:
903                                 WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
904                                 event_code= VIEW_CONFIRM;
905                                 break;
906                 }
907         }
908         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
909                 event_code= VIEW_CONFIRM;
910         }
911
912         if(event_code==VIEW_APPLY) {
913                 viewmove_apply(vod, event->x, event->y);
914         }
915         else if (event_code==VIEW_CONFIRM) {
916                 request_depth_update(CTX_wm_region_view3d(C));
917
918                 viewops_data_free(C, op);
919
920                 return OPERATOR_FINISHED;
921         }
922
923         return OPERATOR_RUNNING_MODAL;
924 }
925
926 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
927 {
928         /* makes op->customdata */
929         viewops_data_create(C, op, event);
930
931         if (event->type == MOUSEPAN) {
932                 ViewOpsData *vod= op->customdata;
933                 viewmove_apply(vod, event->prevx, event->prevy);
934                 request_depth_update(CTX_wm_region_view3d(C));
935                 
936                 viewops_data_free(C, op);               
937                 
938                 return OPERATOR_FINISHED;
939         }
940         else {
941                 /* add temp handler */
942                 WM_event_add_modal_handler(C, op);
943
944                 return OPERATOR_RUNNING_MODAL;
945         }
946 }
947
948 void VIEW3D_OT_move(wmOperatorType *ot)
949 {
950
951         /* identifiers */
952         ot->name= "Move view";
953         ot->description = "Move the view";
954         ot->idname= "VIEW3D_OT_move";
955
956         /* api callbacks */
957         ot->invoke= viewmove_invoke;
958         ot->modal= viewmove_modal;
959         ot->poll= ED_operator_view3d_active;
960
961         /* flags */
962         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
963 }
964
965 /* ************************ viewzoom ******************************** */
966
967 /* called in transform_ops.c, on each regeneration of keymaps  */
968 void viewzoom_modal_keymap(wmKeyConfig *keyconf)
969 {
970         static EnumPropertyItem modal_items[] = {
971         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Confirm", ""},
972
973         {0, NULL, 0, NULL, NULL}};
974
975         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Zoom Modal");
976
977         /* this function is called for each spacetype, only needs to add map once */
978         if(keymap) return;
979
980         keymap= WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items);
981
982         /* items for modal map */
983         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
984         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
985
986         /* disabled mode switching for now, can re-implement better, later on
987         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
988         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
989         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
990          */
991         
992         /* assign map to operators */
993         WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
994 }
995
996 static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
997 {
998         RegionView3D *rv3d= ar->regiondata;
999
1000         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
1001                 float dvec[3];
1002                 float tvec[3];
1003                 float tpos[3];
1004                 float new_dist;
1005                 short vb[2], mouseloc[2];
1006
1007                 mouseloc[0]= mx - ar->winrct.xmin;
1008                 mouseloc[1]= my - ar->winrct.ymin;
1009
1010                 /* find the current window width and height */
1011                 vb[0] = ar->winx;
1012                 vb[1] = ar->winy;
1013
1014                 negate_v3_v3(tpos, rv3d->ofs);
1015
1016                 /* Project cursor position into 3D space */
1017                 initgrabz(rv3d, tpos[0], tpos[1], tpos[2]);
1018                 window_to_3d_delta(ar, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
1019
1020                 /* Calculate view target position for dolly */
1021                 add_v3_v3v3(tvec, tpos, dvec);
1022                 negate_v3(tvec);
1023
1024                 /* Offset to target position and dolly */
1025                 new_dist = rv3d->dist * dfac;
1026
1027                 VECCOPY(rv3d->ofs, tvec);
1028                 rv3d->dist = new_dist;
1029
1030                 /* Calculate final offset */
1031                 madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac);
1032         } else {
1033                 rv3d->dist *= dfac;
1034         }
1035 }
1036
1037
1038 static void viewzoom_apply(ViewOpsData *vod, int x, int y, short viewzoom)
1039 {
1040         float zfac=1.0;
1041
1042         if(viewzoom==USER_ZOOM_CONT) {
1043                 double time= PIL_check_seconds_timer();
1044                 float time_step= (float)(time - vod->timer_lastdraw);
1045
1046                 // oldstyle zoom
1047                 zfac = 1.0f + (((float)(vod->origx - x + vod->origy - y)/20.0) * time_step);
1048                 vod->timer_lastdraw= time;
1049         }
1050         else if(viewzoom==USER_ZOOM_SCALE) {
1051                 int ctr[2], len1, len2;
1052                 // method which zooms based on how far you move the mouse
1053
1054                 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
1055                 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
1056
1057                 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
1058                 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
1059
1060                 zfac = vod->dist0 * ((float)len2/len1) / vod->rv3d->dist;
1061         }
1062         else {  /* USER_ZOOM_DOLLY */
1063                 float len1, len2;
1064                 
1065                 if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
1066                         len1 = (vod->ar->winrct.xmax - x) + 5;
1067                         len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
1068                 }
1069                 else {
1070                         len1 = (vod->ar->winrct.ymax - y) + 5;
1071                         len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
1072                 }
1073                 if (U.uiflag & USER_ZOOM_INVERT)
1074                         SWAP(float, len1, len2);
1075                 
1076                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->rv3d->dist;
1077         }
1078
1079         if(zfac != 1.0 && zfac*vod->rv3d->dist > 0.001*vod->grid &&
1080                                 zfac*vod->rv3d->dist < 10.0*vod->far)
1081                 view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
1082
1083
1084         if ((U.uiflag & USER_ORBIT_ZBUF) && (viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
1085                 float upvec[3], mat[3][3];
1086
1087                 /* Secret apricot feature, translate the view when in continues mode */
1088                 upvec[0] = upvec[1] = 0.0f;
1089                 upvec[2] = (vod->dist0 - vod->rv3d->dist) * vod->grid;
1090                 vod->rv3d->dist = vod->dist0;
1091                 copy_m3_m4(mat, vod->rv3d->viewinv);
1092                 mul_m3_v3(mat, upvec);
1093                 add_v3_v3(vod->rv3d->ofs, upvec);
1094         } else {
1095                 /* these limits were in old code too */
1096                 if(vod->rv3d->dist<0.001*vod->grid) vod->rv3d->dist= 0.001*vod->grid;
1097                 if(vod->rv3d->dist>10.0*vod->far) vod->rv3d->dist=10.0*vod->far;
1098         }
1099
1100 // XXX  if(vod->rv3d->persp==RV3D_ORTHO || vod->rv3d->persp==RV3D_CAMOB) preview3d_event= 0;
1101
1102         if(vod->rv3d->viewlock & RV3D_BOXVIEW)
1103                 view3d_boxview_sync(vod->sa, vod->ar);
1104
1105         ED_region_tag_redraw(vod->ar);
1106 }
1107
1108
1109 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
1110 {
1111         ViewOpsData *vod= op->customdata;
1112         short event_code= VIEW_PASS;
1113
1114         /* execute the events */
1115         if (event->type == TIMER && event->customdata == vod->timer) {
1116                 /* continuous zoom */
1117                 event_code= VIEW_APPLY;
1118         }
1119         else if(event->type==MOUSEMOVE) {
1120                 event_code= VIEW_APPLY;
1121         }
1122         else if(event->type==EVT_MODAL_MAP) {
1123                 switch (event->val) {
1124                         case VIEW_MODAL_CONFIRM:
1125                                 event_code= VIEW_CONFIRM;
1126                                 break;
1127                         case VIEWROT_MODAL_SWITCH_MOVE:
1128                                 WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
1129                                 event_code= VIEW_CONFIRM;
1130                                 break;
1131                         case VIEWROT_MODAL_SWITCH_ROTATE:
1132                                 WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
1133                                 event_code= VIEW_CONFIRM;
1134                                 break;
1135                 }
1136         }
1137         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
1138                 event_code= VIEW_CONFIRM;
1139         }
1140
1141         if(event_code==VIEW_APPLY) {
1142                 viewzoom_apply(vod, event->x, event->y, U.viewzoom);
1143         }
1144         else if (event_code==VIEW_CONFIRM) {
1145                 request_depth_update(CTX_wm_region_view3d(C));
1146                 viewops_data_free(C, op);
1147
1148                 return OPERATOR_FINISHED;
1149         }
1150
1151         return OPERATOR_RUNNING_MODAL;
1152 }
1153
1154 static int viewzoom_exec(bContext *C, wmOperator *op)
1155 {
1156         View3D *v3d = CTX_wm_view3d(C);
1157         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1158         int delta= RNA_int_get(op->ptr, "delta");
1159         int mx = RNA_int_get(op->ptr, "mx");
1160         int my = RNA_int_get(op->ptr, "my");
1161
1162         if(delta < 0) {
1163                 /* this min and max is also in viewmove() */
1164                 if(rv3d->persp==RV3D_CAMOB) {
1165                         rv3d->camzoom-= 10;
1166                         if(rv3d->camzoom<-30) rv3d->camzoom= -30;
1167                 }
1168                 else if(rv3d->dist<10.0*v3d->far) {
1169                         view_zoom_mouseloc(CTX_wm_region(C), 1.2f, mx, my);
1170                 }
1171         }
1172         else {
1173                 if(rv3d->persp==RV3D_CAMOB) {
1174                         rv3d->camzoom+= 10;
1175                         if(rv3d->camzoom>600) rv3d->camzoom= 600;
1176                 }
1177                 else if(rv3d->dist> 0.001*v3d->grid) {
1178                         view_zoom_mouseloc(CTX_wm_region(C), .83333f, mx, my);
1179                 }
1180         }
1181
1182         if(rv3d->viewlock & RV3D_BOXVIEW)
1183                 view3d_boxview_sync(CTX_wm_area(C), CTX_wm_region(C));
1184
1185         request_depth_update(CTX_wm_region_view3d(C));
1186         ED_region_tag_redraw(CTX_wm_region(C));
1187         
1188         viewops_data_free(C, op);
1189
1190         return OPERATOR_FINISHED;
1191 }
1192
1193 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
1194 {
1195         int delta= RNA_int_get(op->ptr, "delta");
1196         
1197         /* if one or the other zoom position aren't set, set from event */
1198         if (!RNA_property_is_set(op->ptr, "mx") || !RNA_property_is_set(op->ptr, "my"))
1199         {
1200                 RNA_int_set(op->ptr, "mx", event->x);
1201                 RNA_int_set(op->ptr, "my", event->y);
1202         }
1203
1204         if(delta) {
1205                 /* makes op->customdata */
1206                 viewops_data_create(C, op, event);
1207                 viewzoom_exec(C, op);
1208         }
1209         else {
1210                 ViewOpsData *vod;
1211
1212                 /* makes op->customdata */
1213                 viewops_data_create(C, op, event);
1214
1215                 vod= op->customdata;
1216
1217                 if (event->type == MOUSEZOOM) {
1218                         if (U.uiflag & USER_ZOOM_INVERT) /* Bypass Zoom invert flag */
1219                                 SWAP(int, event->x, event->prevx);
1220
1221                         if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
1222                                 vod->origx = vod->oldx = event->x;
1223                                 viewzoom_apply(vod, event->prevx, event->prevy, USER_ZOOM_DOLLY);
1224                         }
1225                         else {
1226                                 
1227                                 /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
1228                                 vod->origy = vod->oldy = vod->origy + event->x - event->prevx;
1229                                 viewzoom_apply(vod, event->prevx, event->prevy, USER_ZOOM_DOLLY);
1230                         }
1231                         request_depth_update(CTX_wm_region_view3d(C));
1232                         
1233                         viewops_data_free(C, op);
1234                         return OPERATOR_FINISHED;
1235                 }
1236                 else {
1237                         if(U.viewzoom == USER_ZOOM_CONT) {
1238                                 /* needs a timer to continue redrawing */
1239                                 vod->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
1240                                 vod->timer_lastdraw= PIL_check_seconds_timer();
1241                         }
1242
1243                         /* add temp handler */
1244                         WM_event_add_modal_handler(C, op);
1245
1246                         return OPERATOR_RUNNING_MODAL;
1247                 }
1248         }
1249         return OPERATOR_FINISHED;
1250 }
1251
1252
1253 void VIEW3D_OT_zoom(wmOperatorType *ot)
1254 {
1255         /* identifiers */
1256         ot->name= "Zoom view";
1257         ot->description = "Zoom in/out in the view";
1258         ot->idname= "VIEW3D_OT_zoom";
1259
1260         /* api callbacks */
1261         ot->invoke= viewzoom_invoke;
1262         ot->exec= viewzoom_exec;
1263         ot->modal= viewzoom_modal;
1264         ot->poll= ED_operator_view3d_active;
1265
1266         /* flags */
1267         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1268
1269         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1270         RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
1271         RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
1272 }
1273
1274 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1275 {
1276         ARegion *ar= CTX_wm_region(C);
1277         View3D *v3d = CTX_wm_view3d(C);
1278         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1279         Scene *scene= CTX_data_scene(C);
1280         Base *base;
1281         float *curs;
1282
1283         int center= RNA_boolean_get(op->ptr, "center");
1284
1285         float size, min[3], max[3], afm[3];
1286         int ok= 1, onedone=0;
1287
1288         if(center) {
1289                 min[0]= min[1]= min[2]= 0.0f;
1290                 max[0]= max[1]= max[2]= 0.0f;
1291
1292                 /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
1293                 curs= give_cursor(scene, v3d);
1294                 curs[0]= curs[1]= curs[2]= 0.0;
1295         }
1296         else {
1297                 INIT_MINMAX(min, max);
1298         }
1299
1300         for(base= scene->base.first; base; base= base->next) {
1301                 if(base->lay & v3d->lay) {
1302                         onedone= 1;
1303                         minmax_object(base->object, min, max);
1304                 }
1305         }
1306         if(!onedone) {
1307                 ED_region_tag_redraw(ar);
1308                 /* TODO - should this be cancel?
1309                  * I think no, because we always move the cursor, with or without
1310                  * object, but in this case there is no change in the scene,
1311                  * only the cursor so I choice a ED_region_tag like
1312                  * smooth_view do for the center_cursor.
1313                  * See bug #22640
1314                  */
1315                 return OPERATOR_FINISHED;
1316         }
1317
1318         afm[0]= (max[0]-min[0]);
1319         afm[1]= (max[1]-min[1]);
1320         afm[2]= (max[2]-min[2]);
1321         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
1322         if(size==0.0) ok= 0;
1323
1324         if(ok) {
1325                 float new_dist;
1326                 float new_ofs[3];
1327
1328                 new_dist = size;
1329                 new_ofs[0]= -(min[0]+max[0])/2.0f;
1330                 new_ofs[1]= -(min[1]+max[1])/2.0f;
1331                 new_ofs[2]= -(min[2]+max[2])/2.0f;
1332
1333                 // correction for window aspect ratio
1334                 if(ar->winy>2 && ar->winx>2) {
1335                         size= (float)ar->winx/(float)ar->winy;
1336                         if(size<1.0) size= 1.0f/size;
1337                         new_dist*= size;
1338                 }
1339
1340                 if (rv3d->persp==RV3D_CAMOB) {
1341                         rv3d->persp= RV3D_PERSP;
1342                         smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL);
1343                 }
1344                 else {
1345                         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1346                 }
1347         }
1348 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1349
1350         if(rv3d->viewlock & RV3D_BOXVIEW)
1351                 view3d_boxview_copy(CTX_wm_area(C), ar);
1352                 
1353         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
1354
1355         return OPERATOR_FINISHED;
1356 }
1357
1358 static int viewhome_poll(bContext *C)
1359 {
1360         if(ED_operator_view3d_active(C)) {
1361                 RegionView3D *rv3d= CTX_wm_region_view3d(C); //XXX, when accessed from a header menu this doesnt work!
1362                 if(rv3d && rv3d->persp!=RV3D_CAMOB) {
1363                         return 1;
1364                 }
1365         }
1366
1367         return 0;
1368 }
1369
1370 void VIEW3D_OT_view_all(wmOperatorType *ot)
1371 {
1372         /* identifiers */
1373         ot->name= "View All";
1374         ot->description = "View all objects in scene";
1375         ot->idname= "VIEW3D_OT_view_all";
1376
1377         /* api callbacks */
1378         ot->exec= viewhome_exec;
1379         ot->poll= viewhome_poll;
1380
1381         /* flags */
1382         ot->flag= 0;
1383
1384         RNA_def_boolean(ot->srna, "center", 0, "Center", "");
1385 }
1386
1387
1388 static int viewselected_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
1389 {
1390         ARegion *ar= CTX_wm_region(C);
1391         View3D *v3d = CTX_wm_view3d(C);
1392         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1393         Scene *scene= CTX_data_scene(C);
1394         Object *ob= OBACT;
1395         Object *obedit= CTX_data_edit_object(C);
1396         float size, min[3], max[3], afm[3];
1397         int ok=0, ok_dist=1;
1398
1399         /* SMOOTHVIEW */
1400         float new_ofs[3];
1401         float new_dist;
1402
1403         INIT_MINMAX(min, max);
1404
1405         if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
1406                 /* hardcoded exception, we look for the one selected armature */
1407                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1408                 Base *base;
1409                 for(base=scene->base.first; base; base= base->next) {
1410                         if(TESTBASELIB(v3d, base)) {
1411                                 if(base->object->type==OB_ARMATURE)
1412                                         if(base->object->mode & OB_MODE_POSE)
1413                                                 break;
1414                         }
1415                 }
1416                 if(base)
1417                         ob= base->object;
1418         }
1419
1420
1421         if(obedit) {
1422                 ok = minmax_verts(obedit, min, max);    /* only selected */
1423         }
1424         else if(ob && (ob->mode & OB_MODE_POSE)) {
1425                 if(ob->pose) {
1426                         bArmature *arm= ob->data;
1427                         bPoseChannel *pchan;
1428                         float vec[3];
1429
1430                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1431                                 if(pchan->bone->flag & BONE_SELECTED) {
1432                                         if(pchan->bone->layer & arm->layer) {
1433                                                 bPoseChannel *pchan_tx= pchan->custom_tx ? pchan->custom_tx : pchan;
1434                                                 ok= 1;
1435                                                 VECCOPY(vec, pchan_tx->pose_head);
1436                                                 mul_m4_v3(ob->obmat, vec);
1437                                                 DO_MINMAX(vec, min, max);
1438                                                 VECCOPY(vec, pchan_tx->pose_tail);
1439                                                 mul_m4_v3(ob->obmat, vec);
1440                                                 DO_MINMAX(vec, min, max);
1441                                         }
1442                                 }
1443                         }
1444                 }
1445         }
1446         else if (paint_facesel_test(ob)) {
1447                 ok= minmax_tface(ob, min, max);
1448         }
1449         else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1450                 ok= PE_minmax(scene, min, max);
1451         }
1452         else {
1453                 Base *base= FIRSTBASE;
1454                 while(base) {
1455                         if(TESTBASE(v3d, base))  {
1456
1457                                 /* account for duplis */
1458                                 if (minmax_object_duplis(scene, base->object, min, max)==0)
1459                                         minmax_object(base->object, min, max); /* use if duplis not found */
1460
1461                                 ok= 1;
1462                         }
1463                         base= base->next;
1464                 }
1465         }
1466
1467         if(ok==0) return OPERATOR_FINISHED;
1468
1469         sub_v3_v3v3(afm, max, min);
1470         size= MAX3(afm[0], afm[1], afm[2]);
1471
1472         if(rv3d->persp==RV3D_ORTHO) {
1473                 if(size < 0.0001f) { /* if its a sinble point. dont even re-scale */
1474                         ok_dist= 0;
1475                 }
1476                 else {
1477                         /* perspective should be a bit farther away to look nice */
1478                         size*= 0.7f;
1479                 }
1480         }
1481         else {
1482                 if(size <= v3d->near*1.5f) {
1483                         size= v3d->near*1.5f;
1484                 }
1485         }
1486
1487         add_v3_v3v3(new_ofs, min, max);
1488         mul_v3_fl(new_ofs, -0.5f);
1489
1490         new_dist = size;
1491
1492         /* correction for window aspect ratio */
1493         if(ar->winy>2 && ar->winx>2) {
1494                 size= (float)ar->winx/(float)ar->winy;
1495                 if(size<1.0f) size= 1.0f/size;
1496                 new_dist*= size;
1497         }
1498
1499         if (rv3d->persp==RV3D_CAMOB) {
1500                 rv3d->persp= RV3D_PERSP;
1501                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1502         }
1503         else {
1504                 smooth_view(C, NULL, NULL, new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL);
1505         }
1506
1507 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1508         if(rv3d->viewlock & RV3D_BOXVIEW)
1509                 view3d_boxview_copy(CTX_wm_area(C), ar);
1510
1511         return OPERATOR_FINISHED;
1512 }
1513
1514 void VIEW3D_OT_view_selected(wmOperatorType *ot)
1515 {
1516
1517         /* identifiers */
1518         ot->name= "View Selected";
1519         ot->description = "Move the view to the selection center";
1520         ot->idname= "VIEW3D_OT_view_selected";
1521
1522         /* api callbacks */
1523         ot->exec= viewselected_exec;
1524         ot->poll= ED_operator_view3d_active;
1525
1526         /* flags */
1527         ot->flag= 0;
1528 }
1529
1530 static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
1531 {
1532         View3D *v3d = CTX_wm_view3d(C);
1533         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1534         Scene *scene= CTX_data_scene(C);
1535         
1536         if (rv3d) {
1537                 /* non camera center */
1538                 float new_ofs[3];
1539                 negate_v3_v3(new_ofs, give_cursor(scene, v3d));
1540                 smooth_view(C, NULL, NULL, new_ofs, NULL, NULL, NULL);
1541                 
1542                 if (rv3d->viewlock & RV3D_BOXVIEW)
1543                         view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
1544         }
1545         
1546         return OPERATOR_FINISHED;
1547 }
1548
1549 void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
1550 {
1551         /* identifiers */
1552         ot->name= "Center View to Cursor";
1553         ot->description= "Centers the view so that the cursor is in the middle of the view";
1554         ot->idname= "VIEW3D_OT_view_center_cursor";
1555         
1556         /* api callbacks */
1557         ot->exec= viewcenter_cursor_exec;
1558         ot->poll= ED_operator_view3d_active;
1559         
1560         /* flags */
1561         ot->flag= 0;
1562 }
1563
1564 static int view3d_center_camera_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1565 {
1566         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1567
1568         rv3d->camdx= rv3d->camdy= 0.0f;
1569
1570         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, CTX_wm_view3d(C));
1571
1572         return OPERATOR_FINISHED;
1573 }
1574
1575 void VIEW3D_OT_view_center_camera(wmOperatorType *ot)
1576 {
1577         /* identifiers */
1578         ot->name= "View Camera Center";
1579         ot->description = "Center the camera view";
1580         ot->idname= "VIEW3D_OT_view_center_camera";
1581
1582         /* api callbacks */
1583         ot->exec= view3d_center_camera_exec;
1584         ot->poll= view3d_camera_active_poll;
1585
1586         /* flags */
1587         ot->flag= 0;
1588 }
1589
1590 /* ********************* Set render border operator ****************** */
1591
1592 static int render_border_exec(bContext *C, wmOperator *op)
1593 {
1594         View3D *v3d = CTX_wm_view3d(C);
1595         ARegion *ar= CTX_wm_region(C);
1596         RegionView3D *rv3d= ED_view3d_context_rv3d(C);
1597         Scene *scene= CTX_data_scene(C);
1598
1599         rcti rect;
1600         rctf vb;
1601
1602         /* get border select values using rna */
1603         rect.xmin= RNA_int_get(op->ptr, "xmin");
1604         rect.ymin= RNA_int_get(op->ptr, "ymin");
1605         rect.xmax= RNA_int_get(op->ptr, "xmax");
1606         rect.ymax= RNA_int_get(op->ptr, "ymax");
1607
1608         /* calculate range */
1609         calc_viewborder(scene, ar, rv3d, v3d, &vb);
1610
1611         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1612         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1613         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1614         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1615
1616         /* actually set border */
1617         CLAMP(scene->r.border.xmin, 0.0, 1.0);
1618         CLAMP(scene->r.border.ymin, 0.0, 1.0);
1619         CLAMP(scene->r.border.xmax, 0.0, 1.0);
1620         CLAMP(scene->r.border.ymax, 0.0, 1.0);
1621
1622         /* drawing a border surrounding the entire camera view switches off border rendering
1623          * or the border covers no pixels */
1624         if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1625                 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1626            (scene->r.border.xmin == scene->r.border.xmax ||
1627                 scene->r.border.ymin == scene->r.border.ymax ))
1628         {
1629                 scene->r.mode &= ~R_BORDER;
1630         } else {
1631                 scene->r.mode |= R_BORDER;
1632         }
1633         
1634         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, NULL);
1635
1636         return OPERATOR_FINISHED;
1637
1638 }
1639
1640 void VIEW3D_OT_render_border(wmOperatorType *ot)
1641 {
1642         /* identifiers */
1643         ot->name= "Set Render Border";
1644         ot->description = "Set the boundries of the border render and enables border render ";
1645         ot->idname= "VIEW3D_OT_render_border";
1646
1647         /* api callbacks */
1648         ot->invoke= WM_border_select_invoke;
1649         ot->exec= render_border_exec;
1650         ot->modal= WM_border_select_modal;
1651
1652         ot->poll= view3d_camera_active_poll;
1653
1654         /* flags */
1655         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1656
1657         /* rna */
1658         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1659         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1660         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1661         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1662
1663 }
1664 /* ********************* Border Zoom operator ****************** */
1665
1666 static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
1667 {
1668         ARegion *ar= CTX_wm_region(C);
1669         View3D *v3d = CTX_wm_view3d(C);
1670         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1671         Scene *scene= CTX_data_scene(C);
1672
1673         /* Zooms in on a border drawn by the user */
1674         rcti rect;
1675         float dvec[3], vb[2], xscale, yscale, scale;
1676
1677         /* SMOOTHVIEW */
1678         float new_dist;
1679         float new_ofs[3];
1680
1681         /* ZBuffer depth vars */
1682         bglMats mats;
1683         float depth, depth_close= FLT_MAX;
1684         int had_depth = 0;
1685         double cent[2],  p[3];
1686         int xs, ys;
1687
1688         /* note; otherwise opengl won't work */
1689         view3d_operator_needs_opengl(C);
1690
1691         /* get border select values using rna */
1692         rect.xmin= RNA_int_get(op->ptr, "xmin");
1693         rect.ymin= RNA_int_get(op->ptr, "ymin");
1694         rect.xmax= RNA_int_get(op->ptr, "xmax");
1695         rect.ymax= RNA_int_get(op->ptr, "ymax");
1696
1697         /* Get Z Depths, needed for perspective, nice for ortho */
1698         bgl_get_mats(&mats);
1699         draw_depth(scene, ar, v3d, NULL);
1700
1701         /* force updating */
1702         if (rv3d->depths) {
1703                 had_depth = 1;
1704                 rv3d->depths->damaged = 1;
1705         }
1706
1707         view3d_update_depths(ar, v3d);
1708
1709         /* Constrain rect to depth bounds */
1710         if (rect.xmin < 0) rect.xmin = 0;
1711         if (rect.ymin < 0) rect.ymin = 0;
1712         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1713         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1714
1715         /* Find the closest Z pixel */
1716         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1717                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1718                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1719                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1720                                 if (depth_close > depth) {
1721                                         depth_close = depth;
1722                                 }
1723                         }
1724                 }
1725         }
1726
1727         if (had_depth==0) {
1728                 MEM_freeN(rv3d->depths->depths);
1729                 rv3d->depths->depths = NULL;
1730         }
1731         rv3d->depths->damaged = 1;
1732
1733         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1734         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1735
1736         if (rv3d->persp==RV3D_PERSP) {
1737                 double p_corner[3];
1738
1739                 /* no depths to use, we cant do anything! */
1740                 if (depth_close==FLT_MAX){
1741                         BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1742                         return OPERATOR_CANCELLED;
1743                 }
1744                 /* convert border to 3d coordinates */
1745                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1746                         (       !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])))
1747                         return OPERATOR_CANCELLED;
1748
1749                 dvec[0] = p[0]-p_corner[0];
1750                 dvec[1] = p[1]-p_corner[1];
1751                 dvec[2] = p[2]-p_corner[2];
1752
1753                 new_dist = len_v3(dvec);
1754                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1755
1756                 new_ofs[0] = -p[0];
1757                 new_ofs[1] = -p[1];
1758                 new_ofs[2] = -p[2];
1759
1760         } else { /* othographic */
1761                 /* find the current window width and height */
1762                 vb[0] = ar->winx;
1763                 vb[1] = ar->winy;
1764
1765                 new_dist = rv3d->dist;
1766
1767                 /* convert the drawn rectangle into 3d space */
1768                 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])) {
1769                         new_ofs[0] = -p[0];
1770                         new_ofs[1] = -p[1];
1771                         new_ofs[2] = -p[2];
1772                 } else {
1773                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1774                         copy_v3_v3(new_ofs, rv3d->ofs);
1775
1776                         initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1777
1778                         window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1779                         /* center the view to the center of the rectangle */
1780                         sub_v3_v3(new_ofs, dvec);
1781                 }
1782
1783                 /* work out the ratios, so that everything selected fits when we zoom */
1784                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1785                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1786                 scale = (xscale >= yscale)?xscale:yscale;
1787
1788                 /* zoom in as required, or as far as we can go */
1789                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1790         }
1791
1792         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1793
1794         if(rv3d->viewlock & RV3D_BOXVIEW)
1795                 view3d_boxview_sync(CTX_wm_area(C), ar);
1796
1797         return OPERATOR_FINISHED;
1798 }
1799
1800 static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1801 {
1802         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1803
1804         /* if in camera view do not exec the operator so we do not conflict with set render border*/
1805         if (rv3d->persp != RV3D_CAMOB)
1806                 return WM_border_select_invoke(C, op, event);
1807         else
1808                 return OPERATOR_PASS_THROUGH;
1809 }
1810
1811 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1812 {
1813
1814         /* identifiers */
1815         ot->name= "Border Zoom";
1816         ot->description = "Zoom in the view to the nearest object contained in the border";
1817         ot->idname= "VIEW3D_OT_zoom_border";
1818
1819         /* api callbacks */
1820         ot->invoke= view3d_zoom_border_invoke;
1821         ot->exec= view3d_zoom_border_exec;
1822         ot->modal= WM_border_select_modal;
1823
1824         ot->poll= ED_operator_view3d_active;
1825
1826         /* flags */
1827         ot->flag= 0;
1828
1829         /* rna */
1830         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1831         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1832         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1833         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1834
1835 }
1836 /* ********************* Changing view operator ****************** */
1837
1838 static EnumPropertyItem prop_view_items[] = {
1839         {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1840         {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1841         {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1842         {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1843         {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1844         {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1845         {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1846         {0, NULL, 0, NULL, NULL}};
1847
1848
1849 /* would like to make this a generic function - outside of transform */
1850
1851 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo, int align_active)
1852 {
1853         View3D *v3d = CTX_wm_view3d(C);
1854         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1855         float new_quat[4];
1856
1857         new_quat[0]= q1; new_quat[1]= q2;
1858         new_quat[2]= q3; new_quat[3]= q4;
1859
1860         if(align_active) {
1861                 /* align to active object */
1862                 Object *obact= CTX_data_active_object(C);
1863                 if (obact==NULL) {
1864                         /* no active object, ignore this option */
1865                         align_active= FALSE;
1866                 }
1867                 else {
1868                         float obact_quat[4];
1869                         float twmat[3][3];
1870
1871                         /* same as transform manipulator when normal is set */
1872                         ED_getTransformOrientationMatrix(C, twmat, TRUE);
1873
1874                         mat3_to_quat( obact_quat,twmat);
1875                         invert_qt(obact_quat);
1876                         mul_qt_qtqt(new_quat, new_quat, obact_quat);
1877
1878                         rv3d->view= view= 0;
1879                 }
1880         }
1881
1882         if(align_active==FALSE) {
1883                 /* normal operation */
1884                 if(rv3d->viewlock) {
1885                         /* only pass on if */
1886                         if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
1887                         else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
1888                         else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
1889                         else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
1890                         else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
1891                         else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
1892                         else return;
1893                 }
1894
1895                 rv3d->view= view;
1896         }
1897
1898         if(rv3d->viewlock) {
1899                 ED_region_tag_redraw(CTX_wm_region(C));
1900                 return;
1901         }
1902
1903         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1904
1905                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1906                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1907
1908                 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1909         }
1910         else {
1911
1912                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1913                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1914
1915                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1916         }
1917
1918 }
1919
1920 static int viewnumpad_exec(bContext *C, wmOperator *op)
1921 {
1922         View3D *v3d = CTX_wm_view3d(C);
1923         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1924         Scene *scene= CTX_data_scene(C);
1925         static int perspo=RV3D_PERSP;
1926         int viewnum, align_active, nextperspo;
1927
1928         viewnum = RNA_enum_get(op->ptr, "type");
1929         align_active = RNA_boolean_get(op->ptr, "align_active");
1930
1931
1932         /* Use this to test if we started out with a camera */
1933
1934         if (rv3d->persp == RV3D_CAMOB) {
1935                 nextperspo= rv3d->lpersp;
1936         } else {
1937                 nextperspo= perspo;
1938         }
1939
1940         switch (viewnum) {
1941                 case RV3D_VIEW_BOTTOM :
1942                         axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1943                         break;
1944
1945                 case RV3D_VIEW_BACK:
1946                         axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, nextperspo, align_active);
1947                         break;
1948
1949                 case RV3D_VIEW_LEFT:
1950                         axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, nextperspo, align_active);
1951                         break;
1952
1953                 case RV3D_VIEW_TOP:
1954                         axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1955                         break;
1956
1957                 case RV3D_VIEW_FRONT:
1958                         axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, nextperspo, align_active);
1959                         break;
1960
1961                 case RV3D_VIEW_RIGHT:
1962                         axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, nextperspo, align_active);
1963                         break;
1964
1965                 case RV3D_VIEW_CAMERA:
1966                         if(rv3d->viewlock==0) {
1967                                 /* lastview -  */
1968
1969                                 if(rv3d->persp != RV3D_CAMOB) {
1970                                         Object *ob= OBACT;
1971
1972                                         if (!rv3d->smooth_timer) {
1973                                                 /* store settings of current view before allowing overwriting with camera view
1974                                                  * only if we're not currently in a view transition */
1975                                                 copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
1976                                                 rv3d->lview= rv3d->view;
1977                                                 rv3d->lpersp= rv3d->persp;
1978                                         }
1979
1980         #if 0
1981                                         if(G.qual==LR_ALTKEY) {
1982                                                 if(oldcamera && is_an_active_object(oldcamera)) {
1983                                                         v3d->camera= oldcamera;
1984                                                 }
1985                                                 handle_view3d_lock();
1986                                         }
1987         #endif
1988                                         
1989                                         /* first get the default camera for the view lock type */
1990                                         if(v3d->scenelock) {
1991                                                 /* sets the camera view if available */
1992                                                 v3d->camera= scene->camera;                                             
1993                                         }
1994                                         else {
1995                                                 /* use scene camera if one is not set (even though we're unlocked) */
1996                                                 if(v3d->camera==NULL) {
1997                                                         v3d->camera= scene->camera;
1998                                                 }
1999                                         }
2000
2001                                         /* if the camera isnt found, check a number of options */
2002                                         if(v3d->camera==NULL && ob && ob->type==OB_CAMERA)
2003                                                 v3d->camera= ob;
2004                                         
2005                                         if(v3d->camera==NULL)
2006                                                 v3d->camera= scene_find_camera(scene);          
2007
2008                                         /* couldnt find any useful camera, bail out */
2009                                         if(v3d->camera==NULL)
2010                                                 return OPERATOR_CANCELLED;
2011                                         
2012                                         /* important these dont get out of sync for locked scenes */
2013                                         if(v3d->scenelock)
2014                                                 scene->camera= v3d->camera;
2015
2016                                         /* finally do snazzy view zooming */
2017                                         rv3d->persp= RV3D_CAMOB;
2018                                         smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
2019
2020                                 }
2021                                 else{
2022                                         /* return to settings of last view */
2023                                         /* does smooth_view too */
2024                                         axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
2025                                 }
2026                         }
2027                         break;
2028
2029                 default :
2030                         break;
2031         }
2032
2033         if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
2034
2035         return OPERATOR_FINISHED;
2036 }
2037 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
2038 {
2039         /* identifiers */
2040         ot->name= "View numpad";
2041         ot->description = "Set the view";
2042         ot->idname= "VIEW3D_OT_viewnumpad";
2043
2044         /* api callbacks */
2045         ot->exec= viewnumpad_exec;
2046         ot->poll= ED_operator_view3d_active;
2047
2048         /* flags */
2049         ot->flag= 0;
2050
2051         RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
2052         RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
2053 }
2054
2055 static EnumPropertyItem prop_view_orbit_items[] = {
2056         {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
2057         {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
2058         {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
2059         {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
2060         {0, NULL, 0, NULL, NULL}};
2061
2062 static int vieworbit_exec(bContext *C, wmOperator *op)
2063 {
2064         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2065         float phi, q1[4], new_quat[4];
2066         int orbitdir;
2067
2068         orbitdir = RNA_enum_get(op->ptr, "type");
2069
2070         if(rv3d->viewlock==0) {
2071
2072                 if(rv3d->persp != RV3D_CAMOB) {
2073                         if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
2074                                 float si;
2075                                 /* z-axis */
2076                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
2077                                 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
2078                                 si= (float)sin(phi);
2079                                 q1[0]= (float)cos(phi);
2080                                 q1[1]= q1[2]= 0.0;
2081                                 q1[3]= si;
2082                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
2083                                 rv3d->view= 0;
2084                         }
2085                         else if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
2086                                 /* horizontal axis */
2087                                 VECCOPY(q1+1, rv3d->viewinv[0]);
2088
2089                                 normalize_v3(q1+1);
2090                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
2091                                 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
2092                                 q1[0]= (float)cos(phi);
2093                                 mul_v3_fl(q1+1, sin(phi));
2094                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
2095                                 rv3d->view= 0;
2096                         }
2097
2098                         smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
2099                 }
2100         }
2101
2102         return OPERATOR_FINISHED;
2103 }
2104
2105 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
2106 {
2107         /* identifiers */
2108         ot->name= "View Orbit";
2109         ot->description = "Orbit the view";
2110         ot->idname= "VIEW3D_OT_view_orbit";
2111
2112         /* api callbacks */
2113         ot->exec= vieworbit_exec;
2114         ot->poll= view3d_rotate_poll;
2115
2116         /* flags */
2117         ot->flag= 0;
2118         RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
2119 }
2120
2121 static EnumPropertyItem prop_view_pan_items[] = {
2122         {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
2123         {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
2124         {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
2125         {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
2126         {0, NULL, 0, NULL, NULL}};
2127
2128 static int viewpan_exec(bContext *C, wmOperator *op)
2129 {
2130         ARegion *ar= CTX_wm_region(C);
2131         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2132         float vec[3];
2133         int pandir;
2134
2135         pandir = RNA_enum_get(op->ptr, "type");
2136
2137         initgrabz(rv3d, 0.0, 0.0, 0.0);
2138
2139         if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
2140         else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
2141         else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
2142         else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
2143         rv3d->ofs[0]+= vec[0];
2144         rv3d->ofs[1]+= vec[1];
2145         rv3d->ofs[2]+= vec[2];
2146
2147         if(rv3d->viewlock & RV3D_BOXVIEW)
2148                 view3d_boxview_sync(CTX_wm_area(C), ar);
2149
2150         ED_region_tag_redraw(ar);
2151
2152         return OPERATOR_FINISHED;
2153 }
2154
2155 void VIEW3D_OT_view_pan(wmOperatorType *ot)
2156 {
2157         /* identifiers */
2158         ot->name= "View Pan";
2159         ot->description = "Pan the view";
2160         ot->idname= "VIEW3D_OT_view_pan";
2161
2162         /* api callbacks */
2163         ot->exec= viewpan_exec;
2164         ot->poll= ED_operator_view3d_active;
2165
2166         /* flags */
2167         ot->flag= 0;
2168         RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
2169 }
2170
2171 static int viewpersportho_exec(bContext *C, wmOperator *op)
2172 {
2173         ARegion *ar= CTX_wm_region(C);
2174         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2175
2176         if(rv3d->viewlock==0) {
2177                 if(rv3d->persp!=RV3D_ORTHO)
2178                         rv3d->persp=RV3D_ORTHO;
2179                 else rv3d->persp=RV3D_PERSP;
2180                 ED_region_tag_redraw(ar);
2181         }
2182
2183         return OPERATOR_FINISHED;
2184
2185 }
2186
2187 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
2188 {
2189         /* identifiers */
2190         ot->name= "View Persp/Ortho";
2191         ot->description = "Switch the current view from perspective/orthographic";
2192         ot->idname= "VIEW3D_OT_view_persportho";
2193
2194         /* api callbacks */
2195         ot->exec= viewpersportho_exec;
2196         ot->poll= ED_operator_view3d_active;
2197
2198         /* flags */
2199         ot->flag= 0;
2200 }
2201
2202 /* ******************** add background image operator **************** */
2203
2204 static int add_background_image_exec(bContext *C, wmOperator *op)
2205 {
2206         View3D *v3d= CTX_wm_view3d(C);
2207
2208         BGpic *bgpic= MEM_callocN(sizeof(BGpic), "Background Image");
2209         bgpic->size= 5.0;
2210         bgpic->blend= 0.5;
2211         bgpic->iuser.fie_ima= 2;
2212         bgpic->iuser.ok= 1;
2213         bgpic->view= 0; /* 0 for all */
2214
2215         BLI_addtail(&v3d->bgpicbase, bgpic);
2216
2217         //ED_region_tag_redraw(v3d);
2218
2219         return OPERATOR_FINISHED;
2220 }
2221
2222 static int add_background_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
2223 {
2224         return add_background_image_exec(C, op);
2225 }
2226
2227 void VIEW3D_OT_add_background_image(wmOperatorType *ot)
2228 {
2229         /* identifiers */
2230         ot->name   = "Add Background Image";
2231         ot->description= "Add a new background image";
2232         ot->idname = "VIEW3D_OT_add_background_image";
2233
2234         /* api callbacks */
2235         ot->invoke = add_background_image_invoke;
2236         ot->exec   = add_background_image_exec;
2237         ot->poll   = ED_operator_view3d_active;
2238
2239         /* flags */
2240         ot->flag   = 0;
2241 }
2242
2243 /* ***** remove image operator ******* */
2244 static int remove_background_image_exec(bContext *C, wmOperator *op)
2245 {
2246         BGpic *bgpic_rem = CTX_data_pointer_get_type(C, "bgpic", &RNA_BackgroundImage).data;
2247         View3D *vd = CTX_wm_view3d(C);
2248         int index = RNA_int_get(op->ptr, "index");
2249
2250         bgpic_rem = BLI_findlink(&vd->bgpicbase, index);
2251         if(bgpic_rem) {
2252                 BLI_remlink(&vd->bgpicbase, bgpic_rem);
2253                 if(bgpic_rem->ima) bgpic_rem->ima->id.us--;
2254                 MEM_freeN(bgpic_rem);
2255         }
2256
2257         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, vd);
2258
2259         return OPERATOR_FINISHED;
2260 }
2261
2262 void VIEW3D_OT_remove_background_image(wmOperatorType *ot)
2263 {
2264         /* identifiers */
2265         ot->name   = "Remove Background Image";
2266         ot->description= "Remove a background image from the 3D view";
2267         ot->idname = "VIEW3D_OT_remove_background_image";
2268
2269         /* api callbacks */
2270         ot->exec   = remove_background_image_exec;
2271         ot->poll   = ED_operator_view3d_active;
2272
2273         /* flags */
2274         ot->flag   = 0;
2275
2276         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove ", 0, INT_MAX);
2277 }
2278 /* ********************* set clipping operator ****************** */
2279
2280 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
2281 {
2282         int val;
2283
2284         for(val=0; val<4; val++) {
2285
2286                 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
2287
2288                 clip[val][3]=
2289                         - clip[val][0]*clipbb->vec[val][0]
2290                         - clip[val][1]*clipbb->vec[val][1]
2291                         - clip[val][2]*clipbb->vec[val][2];
2292         }
2293 }
2294
2295 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
2296 {
2297         BoundBox clipbb_local;
2298         float imat[4][4];
2299         int i;
2300
2301         invert_m4_m4(imat, mat);
2302
2303         for(i=0; i<8; i++) {
2304                 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
2305         }
2306
2307         calc_clipping_plane(clip_local, &clipbb_local);
2308 }
2309
2310 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
2311 {
2312         if(rv3d->rflag & RV3D_CLIPPING)
2313                 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
2314 }
2315
2316 static int view3d_clipping_exec(bContext *C, wmOperator *op)
2317 {
2318         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2319         ViewContext vc;
2320         bglMats mats;
2321         rcti rect;
2322
2323         rect.xmin= RNA_int_get(op->ptr, "xmin");
2324         rect.ymin= RNA_int_get(op->ptr, "ymin");
2325         rect.xmax= RNA_int_get(op->ptr, "xmax");
2326         rect.ymax= RNA_int_get(op->ptr, "ymax");
2327
2328         rv3d->rflag |= RV3D_CLIPPING;
2329         rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
2330
2331         /* note; otherwise opengl won't work */
2332         view3d_operator_needs_opengl(C);
2333
2334         view3d_set_viewcontext(C, &vc);
2335         view3d_get_transformation(vc.ar, vc.rv3d, NULL, &mats); /* NULL because we don't want it in object space */
2336         view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
2337
2338         return OPERATOR_FINISHED;
2339 }
2340
2341 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
2342 {
2343         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2344         ARegion *ar= CTX_wm_region(C);
2345
2346         if(rv3d->rflag & RV3D_CLIPPING) {
2347                 rv3d->rflag &= ~RV3D_CLIPPING;
2348                 ED_region_tag_redraw(ar);
2349                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
2350                 rv3d->clipbb= NULL;
2351                 return OPERATOR_FINISHED;
2352         }
2353         else {
2354                 return WM_border_select_invoke(C, op, event);
2355         }
2356 }
2357
2358 /* toggles */
2359 void VIEW3D_OT_clip_border(wmOperatorType *ot)
2360 {
2361
2362         /* identifiers */
2363         ot->name= "Clipping Border";
2364         ot->description = "Set the view clipping border";
2365         ot->idname= "VIEW3D_OT_clip_border";
2366
2367         /* api callbacks */
2368         ot->invoke= view3d_clipping_invoke;
2369         ot->exec= view3d_clipping_exec;
2370         ot->modal= WM_border_select_modal;
2371
2372         ot->poll= ED_operator_view3d_active;
2373
2374         /* flags */
2375         ot->flag= 0;
2376
2377         /* rna */
2378         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2379         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2380         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2381         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2382 }
2383
2384 /* ***************** 3d cursor cursor op ******************* */
2385
2386 /* mx my in region coords */
2387 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
2388 {
2389         Scene *scene= CTX_data_scene(C);
2390         ARegion *ar= CTX_wm_region(C);
2391         View3D *v3d = CTX_wm_view3d(C);
2392         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2393         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2394         short mx, my, mval[2];
2395 //      short ctrl= 0; // XXX
2396
2397         fp= give_cursor(scene, v3d);
2398
2399 //      if(obedit && ctrl) lr_click= 1;
2400         VECCOPY(oldcurs, fp);
2401
2402         mx= event->x - ar->winrct.xmin;
2403         my= event->y - ar->winrct.ymin;
2404         project_short_noclip(ar, fp, mval);
2405
2406         initgrabz(rv3d, fp[0], fp[1], fp[2]);
2407
2408         if(mval[0]!=IS_CLIPPED) {
2409                 short depth_used = 0;
2410
2411                 if (U.uiflag & USER_ORBIT_ZBUF) { /* maybe this should be accessed some other way */
2412                         short mval_depth[2] = {mx, my};
2413                         view3d_operator_needs_opengl(C);
2414                         if (view_autodist(scene, ar, v3d, mval_depth, fp))
2415                                 depth_used= 1;
2416                 }
2417
2418                 if(depth_used==0) {
2419                         window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2420                         sub_v3_v3(fp, dvec);
2421                 }
2422         }
2423         else {
2424
2425                 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2426                 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2427
2428                 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2429                 fz= fz/rv3d->zfac;
2430
2431                 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2432                 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2433                 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2434         }
2435
2436         if(v3d && v3d->localvd)
2437                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2438         else
2439                 WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene);
2440
2441         return OPERATOR_FINISHED;
2442 }
2443
2444 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2445 {
2446
2447         /* identifiers */
2448         ot->name= "Set 3D Cursor";
2449         ot->description = "Set the location of the 3D cursor";
2450         ot->idname= "VIEW3D_OT_cursor3d";
2451
2452         /* api callbacks */
2453         ot->invoke= set_3dcursor_invoke;
2454
2455         ot->poll= ED_operator_view3d_active;
2456     
2457         /* flags */
2458 //      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2459     
2460         /* rna later */
2461
2462 }
2463
2464 /* ***************** manipulator op ******************* */
2465
2466
2467 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2468 {
2469         View3D *v3d = CTX_wm_view3d(C);
2470
2471         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2472         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2473
2474         /* only no modifier or shift */
2475         if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2476
2477         /* note; otherwise opengl won't work */
2478         view3d_operator_needs_opengl(C);
2479
2480         if(0==BIF_do_manipulator(C, event, op))
2481                 return OPERATOR_PASS_THROUGH;
2482
2483         return OPERATOR_FINISHED;
2484 }
2485
2486 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2487 {
2488
2489         /* identifiers */
2490         ot->name= "3D Manipulator";
2491         ot->description = "Manipulate selected item by axis";
2492         ot->idname= "VIEW3D_OT_manipulator";
2493
2494         /* api callbacks */
2495         ot->invoke= manipulator_invoke;
2496
2497         ot->poll= ED_operator_view3d_active;
2498
2499         /* properties to pass to transform */
2500         Transform_Properties(ot, P_CONSTRAINT);
2501 }
2502
2503 static int enable_manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2504 {
2505         View3D *v3d = CTX_wm_view3d(C);
2506
2507         v3d->twtype=0;
2508         
2509         if (RNA_boolean_get(op->ptr, "translate"))
2510                 v3d->twtype |= V3D_MANIP_TRANSLATE;
2511         if (RNA_boolean_get(op->ptr, "rotate"))
2512                 v3d->twtype |= V3D_MANIP_ROTATE;
2513         if (RNA_boolean_get(op->ptr, "scale"))
2514                 v3d->twtype |= V3D_MANIP_SCALE;
2515                 
2516         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2517
2518         return OPERATOR_FINISHED;
2519 }
2520
2521 void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
2522 {
2523         /* identifiers */
2524         ot->name= "Enable 3D Manipulator";
2525         ot->description = "Enable the transform manipulator for use";
2526         ot->idname= "VIEW3D_OT_enable_manipulator";
2527         
2528         /* api callbacks */
2529         ot->invoke= enable_manipulator_invoke;
2530         ot->poll= ED_operator_view3d_active;
2531         
2532         /* rna later */
2533         RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator");
2534         RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator");
2535         RNA_def_boolean(ot->srna, "scale", 0, "Scale", "Enable the scale manipulator");
2536 }
2537
2538 /* ************************* below the line! *********************** */
2539
2540
2541 static float view_autodist_depth_margin(ARegion *ar, short *mval, int margin)
2542 {
2543         RegionView3D *rv3d= ar->regiondata;
2544         float depth= FLT_MAX;
2545
2546         if(margin==0) {
2547                 if (mval[0] < 0) return 0;
2548                 if (mval[1] < 0) return 0;
2549                 if (mval[0] >= rv3d->depths->w) return 0;
2550                 if (mval[1] >= rv3d->depths->h) return 0;
2551
2552                 /* Get Z Depths, needed for perspective, nice for ortho */
2553                 depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
2554                 if(depth >= rv3d->depths->depth_range[1] || depth <= rv3d->depths->depth_range[0]) {
2555                         depth= FLT_MAX;
2556                 }
2557         }
2558         else {
2559                 rcti rect;
2560                 float depth_close= FLT_MAX;
2561                 int xs, ys;
2562
2563                 rect.xmax = mval[0] + margin;
2564                 rect.ymax = mval[1] + margin;
2565
2566                 rect.xmin = mval[0] - margin;
2567                 rect.ymin = mval[1] - margin;
2568
2569                 /* Constrain rect to depth bounds */
2570                 if (rect.xmin < 0) rect.xmin = 0;
2571                 if (rect.ymin < 0) rect.ymin = 0;
2572                 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
2573                 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
2574
2575                 /* Find the closest Z pixel */
2576                 for (xs=rect.xmin; xs < rect.xmax; xs++) {
2577                         for (ys=rect.ymin; ys < rect.ymax; ys++) {
2578                                 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
2579                                 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
2580                                         if (depth_close > depth) {
2581                                                 depth_close = depth;
2582                                         }
2583                                 }
2584                         }
2585                 }
2586
2587                 depth= depth_close;
2588         }
2589
2590         return depth;
2591 }
2592
2593 /* XXX todo Zooms in on a border drawn by the user */
2594 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2595 {
2596         RegionView3D *rv3d= ar->regiondata;
2597         bglMats mats; /* ZBuffer depth vars */
2598         float depth_close= FLT_MAX;
2599         int had_depth = 0;
2600         double cent[2],  p[3];
2601
2602         /* Get Z Depths, needed for perspective, nice for ortho */
2603         bgl_get_mats(&mats);
2604         draw_depth(scene, ar, v3d, NULL);
2605
2606         /* force updating */
2607         if (rv3d->depths) {
2608                 had_depth = 1;
2609                 rv3d->depths->damaged = 1;
2610         }
2611
2612         view3d_update_depths(ar, v3d);
2613
2614         depth_close= view_autodist_depth_margin(ar, mval, 4);
2615
2616         if (depth_close==FLT_MAX)
2617                 return 0;
2618
2619         if (had_depth==0) {
2620                 MEM_freeN(rv3d->depths->depths);
2621                 rv3d->depths->depths = NULL;
2622         }
2623         rv3d->depths->damaged = 1;
2624
2625         cent[0] = (double)mval[0];
2626         cent[1] = (double)mval[1];
2627
2628         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2629                 return 0;
2630
2631         mouse_worldloc[0] = (float)p[0];
2632         mouse_worldloc[1] = (float)p[1];
2633         mouse_worldloc[2] = (float)p[2];
2634         return 1;
2635 }
2636
2637 int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode) //, float *autodist )
2638 {
2639         RegionView3D *rv3d= ar->regiondata;
2640
2641         /* Get Z Depths, needed for perspective, nice for ortho */
2642         switch(mode) {
2643         case 0:
2644                 draw_depth(scene, ar, v3d, NULL);
2645                 break;
2646         case 1:
2647                 draw_depth_gpencil(scene, ar, v3d);
2648                 break;
2649         }
2650
2651         /* force updating */
2652         if (rv3d->depths) {
2653                 rv3d->depths->damaged = 1;
2654         }
2655
2656         view3d_update_depths(ar, v3d);
2657         return 1;
2658 }
2659
2660 // no 4x4 sampling, run view_autodist_init first
2661 int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3], int margin, float *force_depth) //, float *autodist )
2662 {
2663         bglMats mats; /* ZBuffer depth vars, could cache? */
2664         float depth;
2665         double cent[2],  p[3];
2666
2667         /* Get Z Depths, needed for perspective, nice for ortho */
2668         if(force_depth)
2669                 depth= *force_depth;
2670         else
2671                 depth= view_autodist_depth_margin(ar, mval, margin);
2672
2673         if (depth==FLT_MAX)
2674                 return 0;
2675
2676         cent[0] = (double)mval[0];
2677         cent[1] = (double)mval[1];
2678
2679         bgl_get_mats(&mats);
2680         if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2681                 return 0;
2682
2683         mouse_worldloc[0] = (float)p[0];
2684         mouse_worldloc[1] = (float)p[1];
2685         mouse_worldloc[2] = (float)p[2];
2686         return 1;
2687 }
2688
2689 int view_autodist_depth(struct ARegion *ar, short *mval, int margin, float *depth)
2690 {
2691         *depth= view_autodist_depth_margin(ar, mval, margin);
2692
2693         return (*depth==FLT_MAX) ? 0:1;
2694                 return 0;
2695 }
2696
2697 /* ********************* NDOF ************************ */
2698 /* note: this code is confusing and unclear... (ton) */
2699 /* **************************************************** */
2700
2701 // ndof scaling will be moved to user setting.
2702 // In the mean time this is just a place holder.
2703
2704 // Note: scaling in the plugin and ghostwinlay.c
2705 // should be removed. With driver default setting,
2706 // each axis returns approx. +-200 max deflection.
2707
2708 // The values I selected are based on the older
2709 // polling i/f. With event i/f, the sensistivity
2710 // can be increased for improved response from
2711 // small deflections of the device input.
2712
2713
2714 // lukep notes : i disagree on the range.
2715 // the normal 3Dconnection driver give +/-400
2716 // on defaut range in other applications
2717 // and up to +/- 1000 if set to maximum
2718 // because i remove the scaling by delta,
2719 // which was a bad idea as it depend of the system
2720 // speed and os, i changed the scaling values, but
2721 // those are still not ok
2722
2723
2724 float ndof_axis_scale[6] = {
2725         +0.01,  // Tx
2726         +0.01,  // Tz
2727         +0.01,  // Ty
2728         +0.0015,        // Rx
2729         +0.0015,        // Rz
2730         +0.0015 // Ry
2731 };
2732
2733 void filterNDOFvalues(float *sbval)
2734 {
2735         int i=0;
2736         float max  = 0.0;
2737
2738         for (i =0; i<6;i++)
2739                 if (fabs(sbval[i]) > max)
2740                         max = fabs(sbval[i]);
2741         for (i =0; i<6;i++)
2742                 if (fabs(sbval[i]) != max )
2743                         sbval[i]=0.0;
2744 }
2745
2746 // statics for controlling rv3d->dist corrections.
2747 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2748 // viewmove restores based on dz_flag state.
2749
2750 int dz_flag = 0;
2751 float m_dist;
2752
2753 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2754 {
2755         RegionView3D *rv3d= ar->regiondata;
2756         int i;
2757         float phi;
2758         float dval[7];
2759         // static fval[6] for low pass filter; device input vector is dval[6]
2760         static float fval[6];
2761         float tvec[3],rvec[3];
2762         float q1[4];
2763         float mat[3][3];
2764         float upvec[3];
2765
2766
2767         /*----------------------------------------------------
2768          * sometimes this routine is called from headerbuttons
2769          * viewmove needs to refresh the screen
2770          */
2771 // XXX  areawinset(ar->win);
2772
2773
2774         // fetch the current state of the ndof device
2775 // XXX  getndof(dval);
2776
2777         if (v3d->ndoffilter)
2778                 filterNDOFvalues(fval);
2779
2780         // Scale input values
2781
2782 //      if(dval[6] == 0) return; // guard against divide by zero
2783
2784         for(i=0;i<6;i++) {
2785
2786                 // user scaling
2787                 dval[i] = dval[i] * ndof_axis_scale[i];
2788         }
2789
2790
2791         // low pass filter with zero crossing reset
2792
2793         for(i=0;i<6;i++) {
2794                 if((dval[i] * fval[i]) >= 0)
2795                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
2796                 else
2797                         fval[i] = 0;
2798         }
2799
2800
2801         // force perspective mode. This is a hack and is
2802         // incomplete. It doesn't actually effect the view
2803         // until the first draw and doesn't update the menu
2804         // to reflect persp mode.
2805
2806         rv3d->persp = RV3D_PERSP;
2807
2808
2809         // Correct the distance jump if rv3d->dist != 0
2810
2811         // This is due to a side effect of the original
2812         // mouse view rotation code. The rotation point is
2813         // set a distance in front of the viewport to
2814         // make rotating with the mouse look better.
2815         // The distance effect is written at a low level
2816         // in the view management instead of the mouse
2817         // view function. This means that all other view
2818         // movement devices must subtract this from their
2819         // view transformations.
2820
2821         if(rv3d->dist != 0.0) {
2822                 dz_flag = 1;
2823                 m_dist = rv3d->dist;
2824                 upvec[0] = upvec[1] = 0;
2825                 upvec[2] = rv3d->dist;
2826                 copy_m3_m4(mat, rv3d->viewinv);
2827                 mul_m3_v3(mat, upvec);
2828                 sub_v3_v3(rv3d->ofs, upvec);
2829                 rv3d->dist = 0.0;
2830         }
2831
2832
2833         // Apply rotation
2834         // Rotations feel relatively faster than translations only in fly mode, so
2835         // we have no choice but to fix that here (not in the plugins)
2836         rvec[0] = -0.5 * dval[3];
2837         rvec[1] = -0.5 * dval[4];
2838         rvec[2] = -0.5 * dval[5];
2839
2840         // rotate device x and y by view z
2841
2842         copy_m3_m4(mat, rv3d->viewinv);
2843         mat[2][2] = 0.0f;
2844         mul_m3_v3(mat, rvec);
2845
2846         // rotate the view
2847
2848         phi = normalize_v3(rvec);
2849         if(phi != 0) {
2850                 axis_angle_to_quat(q1,rvec,phi);
2851                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2852         }
2853
2854
2855         // Apply translation
2856
2857         tvec[0] = dval[0];
2858         tvec[1] = dval[1];
2859         tvec[2] = -dval[2];
2860
2861         // the next three lines rotate the x and y translation coordinates
2862         // by the current z axis angle
2863
2864         copy_m3_m4(mat, rv3d->viewinv);
2865         mat[2][2] = 0.0f;
2866         mul_m3_v3(mat, tvec);
2867
2868         // translate the view
2869
2870         sub_v3_v3(rv3d->ofs, tvec);
2871
2872
2873         /*----------------------------------------------------
2874          * refresh the screen XXX
2875           */
2876
2877         // update render preview window
2878
2879 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2880 }
2881
2882 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2883 {
2884         RegionView3D *rv3d= ar->regiondata;
2885         float fval[7];
2886         float dvec[3];
2887         float sbadjust = 1.0f;
2888         float len;
2889         short use_sel = 0;
2890         Object *ob = OBACT;
2891         float m[3][3];
2892         float m_inv[3][3];
2893         float xvec[3] = {1,0,0};
2894         float yvec[3] = {0,-1,0};
2895         float zvec[3] = {0,0,1};
2896         float phi;
2897         float q1[4];
2898         float obofs[3];
2899         float reverse;
2900         //float diff[4];
2901         float d, curareaX, curareaY;
2902         float mat[3][3];
2903         float upvec[3];
2904
2905         /* Sensitivity will control how fast the view rotates.  The value was
2906          * obtained experimentally by tweaking until the author didn't get dizzy watching.
2907          * Perhaps this should be a configurable user parameter.
2908          */
2909         float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
2910         float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
2911         float zsens = 0.3f;   /* zoom sensitivity */
2912
2913         const float minZoom = -30.0f;
2914         const float maxZoom = 300.0f;
2915
2916         //reset view type
2917         rv3d->view = 0;
2918 //printf("passing here \n");
2919 //
2920         if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
2921                 use_sel = 1;
2922         }
2923
2924         if((dz_flag)||rv3d->dist==0) {
2925                 dz_flag = 0;
2926                 rv3d->dist = m_dist;
2927                 upvec[0] = upvec[1] = 0;
2928                 upvec[2] = rv3d->dist;
2929                 copy_m3_m4(mat, rv3d->viewinv);
2930                 mul_m3_v3(mat, upvec);
2931                 add_v3_v3(rv3d->ofs, upvec);
2932         }
2933
2934         /*----------------------------------------------------
2935          * sometimes this routine is called from headerbuttons
2936          * viewmove needs to refresh the screen
2937          */
2938 // XXX  areawinset(curarea->win);
2939
2940         /*----------------------------------------------------
2941          * record how much time has passed. clamp at 10 Hz
2942          * pretend the previous frame occurred at the clamped time
2943          */
2944 //    now = PIL_check_seconds_timer();
2945  //   frametime = (now - prevTime);
2946  //   if (frametime > 0.1f){        /* if more than 1/10s */
2947  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
2948 //    }
2949 //    prevTime = now;
2950  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
2951
2952         /* fetch the current state of the ndof device & enforce dominant mode if selected */
2953 // XXX    getndof(fval);
2954         if (v3d->ndoffilter)
2955                 filterNDOFvalues(fval);
2956
2957
2958         // put scaling back here, was previously in ghostwinlay
2959         fval[0] = fval[0] * (1.0f/600.0f);
2960         fval[1] = fval[1] * (1.0f/600.0f);
2961         fval[2] = fval[2] * (1.0f/1100.0f);
2962         fval[3] = fval[3] * 0.00005f;
2963         fval[4] =-fval[4] * 0.00005f;
2964         fval[5] = fval[5] * 0.00005f;
2965         fval[6] = fval[6] / 1000000.0f;
2966
2967         // scale more if not in perspective mode
2968         if (rv3d->persp == RV3D_ORTHO) {
2969                 fval[0] = fval[0] * 0.05f;
2970                 fval[1] = fval[1] * 0.05f;
2971                 fval[2] = fval[2] * 0.05f;
2972                 fval[3] = fval[3] * 0.9f;
2973                 fval[4] = fval[4] * 0.9f;
2974                 fval[5] = fval[5] * 0.9f;
2975                 zsens *= 8;
2976         }
2977
2978         /* set object offset */
2979         if (ob) {
2980                 obofs[0] = -ob->obmat[3][0];
2981                 obofs[1] = -ob->obmat[3][1];
2982                 obofs[2] = -ob->obmat[3][2];
2983         }
2984         else {
2985                 VECCOPY(obofs, rv3d->ofs);
2986         }
2987
2988         /* calc an adjustment based on distance from camera
2989            disabled per patch 14402 */
2990          d = 1.0f;
2991
2992 /*    if (ob) {
2993                 sub_v3_v3v3(diff, obofs, rv3d->ofs);
2994                 d = len_v3(diff);
2995         }
2996 */
2997
2998         reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
2999
3000         /*----------------------------------------------------
3001          * ndof device pan
3002          */
3003         psens *= 1.0f + d;
3004         curareaX = sbadjust * psens * fval[0];
3005         curareaY = sbadjust * psens * fval[1];
3006         dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
3007         dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
3008         dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
3009         add_v3_v3(rv3d->ofs, dvec);
3010
3011         /*----------------------------------------------------
3012          * ndof device dolly
3013          */
3014         len = zsens * sbadjust * fval[2];
3015
3016         if (rv3d->persp==RV3D_CAMOB) {
3017                 if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
3018                         rv3d->camzoom+= 10.0f * -len;
3019                 }
3020                 if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
3021                 else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
3022         }
3023         else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
3024                 rv3d->dist*=(1.0 + len);
3025         }
3026
3027
3028         /*----------------------------------------------------
3029          * ndof device turntable
3030          * derived from the turntable code in viewmove
3031          */
3032
3033         /* Get the 3x3 matrix and its inverse from the quaternion */
3034         quat_to_mat3( m,rv3d->viewquat);
3035         invert_m3_m3(m_inv,m);
3036
3037         /* Determine the direction of the x vector (for rotating up and down) */
3038         /* This can likely be compuated directly from the quaternion. */
3039         mul_m3_v3(m_inv,xvec);
3040         mul_m3_v3(m_inv,yvec);
3041         mul_m3_v3(m_inv,zvec);
3042
3043         /* Perform the up/down rotation */
3044         phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
3045         q1[0] = cos(phi);
3046         mul_v3_v3fl(q1+1, xvec, sin(phi));
3047         mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
3048
3049         if (use_sel) {
3050                 conjugate_qt(q1); /* conj == inv for unit quat */
3051                 sub_v3_v3(rv3d->ofs, obofs);
3052                 mul_qt_v3(q1, rv3d->ofs);
3053                 add_v3_v3(rv3d->ofs, obofs);
3054         }
3055
3056         /* Perform the orbital rotation */
3057         /* Perform the orbital rotation
3058            If the seen Up axis is parallel to the zoom axis, rotation should be
3059            achieved with a pure Roll motion (no Spin) on the device. When you start
3060            to tilt, moving from Top to Side view, Spinning will increasingly become
3061            more relevant while the Roll component will decrease. When a full
3062            Side view is reached, rotations around the world's Up axis are achieved
3063            with a pure Spin-only motion.  In other words the control of the spinning
3064            around the world's Up axis should move from the device's Spin axis to the
3065            device's Roll axis depending on the orientation of the world's Up axis
3066            relative to the screen. */
3067         //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
3068         phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
3069         q1[0] = cos(phi);
3070         q1[1] = q1[2] = 0.0;
3071         q1[3] = sin(phi);
3072         mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
3073
3074         if (use_sel) {
3075                 conjugate_qt(q1);
3076                 sub_v3_v3(rv3d->ofs, obofs);
3077                 mul_qt_v3(q1, rv3d->ofs);
3078                 add_v3_v3(rv3d->ofs, obofs);
3079         }
3080
3081         /*----------------------------------------------------
3082          * refresh the screen
3083          */
3084 // XXX    scrarea_do_windraw(curarea);
3085 }
3086
3087
3088
3089