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