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