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