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