bugfix [#24122] Shift-C doesn't work in "Camera View"
[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 view3d_all_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                 /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
1293                 curs= give_cursor(scene, v3d);
1294                 zero_v3(min);
1295                 zero_v3(max);
1296                 zero_v3(curs);
1297         }
1298         else {
1299                 INIT_MINMAX(min, max);
1300         }
1301
1302         for(base= scene->base.first; base; base= base->next) {
1303                 if(base->lay & v3d->lay) {
1304                         onedone= 1;
1305                         minmax_object(base->object, min, max);
1306                 }
1307         }
1308         if(!onedone) {
1309                 ED_region_tag_redraw(ar);
1310                 /* TODO - should this be cancel?
1311                  * I think no, because we always move the cursor, with or without
1312                  * object, but in this case there is no change in the scene,
1313                  * only the cursor so I choice a ED_region_tag like
1314                  * smooth_view do for the center_cursor.
1315                  * See bug #22640
1316                  */
1317                 return OPERATOR_FINISHED;
1318         }
1319
1320         sub_v3_v3v3(afm, max, min);
1321         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
1322         if(size==0.0) ok= 0;
1323
1324         if(ok) {
1325                 float new_dist;
1326                 float new_ofs[3];
1327
1328                 new_dist = size;
1329                 new_ofs[0]= -(min[0]+max[0])/2.0f;
1330                 new_ofs[1]= -(min[1]+max[1])/2.0f;
1331                 new_ofs[2]= -(min[2]+max[2])/2.0f;
1332
1333                 // correction for window aspect ratio
1334                 if(ar->winy>2 && ar->winx>2) {
1335                         size= (float)ar->winx/(float)ar->winy;
1336                         if(size<1.0) size= 1.0f/size;
1337                         new_dist*= size;
1338                 }
1339
1340                 if (rv3d->persp==RV3D_CAMOB) {
1341                         rv3d->persp= RV3D_PERSP;
1342                         smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1343                 }
1344                 else {
1345                         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1346                 }
1347         }
1348 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1349
1350         if(rv3d->viewlock & RV3D_BOXVIEW)
1351                 view3d_boxview_copy(CTX_wm_area(C), ar);
1352                 
1353         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
1354
1355         return OPERATOR_FINISHED;
1356 }
1357
1358
1359 void VIEW3D_OT_view_all(wmOperatorType *ot)
1360 {
1361         /* identifiers */
1362         ot->name= "View All";
1363         ot->description = "View all objects in scene";
1364         ot->idname= "VIEW3D_OT_view_all";
1365
1366         /* api callbacks */
1367         ot->exec= view3d_all_exec;
1368         ot->poll= ED_operator_view3d_active;
1369
1370         /* flags */
1371         ot->flag= 0;
1372
1373         RNA_def_boolean(ot->srna, "center", 0, "Center", "");
1374 }
1375
1376
1377 static int viewselected_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
1378 {
1379         ARegion *ar= CTX_wm_region(C);
1380         View3D *v3d = CTX_wm_view3d(C);
1381         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1382         Scene *scene= CTX_data_scene(C);
1383         Object *ob= OBACT;
1384         Object *obedit= CTX_data_edit_object(C);
1385         float size, min[3], max[3], afm[3];
1386         int ok=0, ok_dist=1;
1387
1388         /* SMOOTHVIEW */
1389         float new_ofs[3];
1390         float new_dist;
1391
1392         INIT_MINMAX(min, max);
1393
1394         if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
1395                 /* hardcoded exception, we look for the one selected armature */
1396                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1397                 Base *base;
1398                 for(base=scene->base.first; base; base= base->next) {
1399                         if(TESTBASELIB(v3d, base)) {
1400                                 if(base->object->type==OB_ARMATURE)
1401                                         if(base->object->mode & OB_MODE_POSE)
1402                                                 break;
1403                         }
1404                 }
1405                 if(base)
1406                         ob= base->object;
1407         }
1408
1409
1410         if(obedit) {
1411                 ok = minmax_verts(obedit, min, max);    /* only selected */
1412         }
1413         else if(ob && (ob->mode & OB_MODE_POSE)) {
1414                 if(ob->pose) {
1415                         bArmature *arm= ob->data;
1416                         bPoseChannel *pchan;
1417                         float vec[3];
1418
1419                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1420                                 if(pchan->bone->flag & BONE_SELECTED) {
1421                                         if(pchan->bone->layer & arm->layer) {
1422                                                 bPoseChannel *pchan_tx= pchan->custom_tx ? pchan->custom_tx : pchan;
1423                                                 ok= 1;
1424                                                 mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head);
1425                                                 DO_MINMAX(vec, min, max);
1426                                                 mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail);
1427                                                 DO_MINMAX(vec, min, max);
1428                                         }
1429                                 }
1430                         }
1431                 }
1432         }
1433         else if (paint_facesel_test(ob)) {
1434                 ok= minmax_tface(ob, min, max);
1435         }
1436         else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1437                 ok= PE_minmax(scene, min, max);
1438         }
1439         else {
1440                 Base *base= FIRSTBASE;
1441                 while(base) {
1442                         if(TESTBASE(v3d, base))  {
1443
1444                                 /* account for duplis */
1445                                 if (minmax_object_duplis(scene, base->object, min, max)==0)
1446                                         minmax_object(base->object, min, max); /* use if duplis not found */
1447
1448                                 ok= 1;
1449                         }
1450                         base= base->next;
1451                 }
1452         }
1453
1454         if(ok==0) return OPERATOR_FINISHED;
1455
1456         sub_v3_v3v3(afm, max, min);
1457         size= MAX3(afm[0], afm[1], afm[2]);
1458
1459         if(rv3d->persp==RV3D_ORTHO) {
1460                 if(size < 0.0001f) { /* if its a sinble point. dont even re-scale */
1461                         ok_dist= 0;
1462                 }
1463                 else {
1464                         /* perspective should be a bit farther away to look nice */
1465                         size*= 0.7f;
1466                 }
1467         }
1468         else {
1469                 if(size <= v3d->near*1.5f) {
1470                         size= v3d->near*1.5f;
1471                 }
1472         }
1473
1474         add_v3_v3v3(new_ofs, min, max);
1475         mul_v3_fl(new_ofs, -0.5f);
1476
1477         new_dist = size;
1478
1479         /* correction for window aspect ratio */
1480         if(ar->winy>2 && ar->winx>2) {
1481                 size= (float)ar->winx/(float)ar->winy;
1482                 if(size<1.0f) size= 1.0f/size;
1483                 new_dist*= size;
1484         }
1485
1486         if (rv3d->persp==RV3D_CAMOB) {
1487                 rv3d->persp= RV3D_PERSP;
1488                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1489         }
1490         else {
1491                 smooth_view(C, NULL, NULL, new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL);
1492         }
1493
1494 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1495         if(rv3d->viewlock & RV3D_BOXVIEW)
1496                 view3d_boxview_copy(CTX_wm_area(C), ar);
1497
1498         return OPERATOR_FINISHED;
1499 }
1500
1501 void VIEW3D_OT_view_selected(wmOperatorType *ot)
1502 {
1503
1504         /* identifiers */
1505         ot->name= "View Selected";
1506         ot->description = "Move the view to the selection center";
1507         ot->idname= "VIEW3D_OT_view_selected";
1508
1509         /* api callbacks */
1510         ot->exec= viewselected_exec;
1511         ot->poll= ED_operator_region_view3d_active;
1512
1513         /* flags */
1514         ot->flag= 0;
1515 }
1516
1517 static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
1518 {
1519         View3D *v3d = CTX_wm_view3d(C);
1520         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1521         Scene *scene= CTX_data_scene(C);
1522         
1523         if (rv3d) {
1524                 /* non camera center */
1525                 float new_ofs[3];
1526                 negate_v3_v3(new_ofs, give_cursor(scene, v3d));
1527                 smooth_view(C, NULL, NULL, new_ofs, NULL, NULL, NULL);
1528                 
1529                 if (rv3d->viewlock & RV3D_BOXVIEW)
1530                         view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
1531         }
1532         
1533         return OPERATOR_FINISHED;
1534 }
1535
1536 void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
1537 {
1538         /* identifiers */
1539         ot->name= "Center View to Cursor";
1540         ot->description= "Centers the view so that the cursor is in the middle of the view";
1541         ot->idname= "VIEW3D_OT_view_center_cursor";
1542         
1543         /* api callbacks */
1544         ot->exec= viewcenter_cursor_exec;
1545         ot->poll= ED_operator_view3d_active;
1546         
1547         /* flags */
1548         ot->flag= 0;
1549 }
1550
1551 static int view3d_center_camera_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1552 {
1553         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1554
1555         rv3d->camdx= rv3d->camdy= 0.0f;
1556
1557         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, CTX_wm_view3d(C));
1558
1559         return OPERATOR_FINISHED;
1560 }
1561
1562 void VIEW3D_OT_view_center_camera(wmOperatorType *ot)
1563 {
1564         /* identifiers */
1565         ot->name= "View Camera Center";
1566         ot->description = "Center the camera view";
1567         ot->idname= "VIEW3D_OT_view_center_camera";
1568
1569         /* api callbacks */
1570         ot->exec= view3d_center_camera_exec;
1571         ot->poll= view3d_camera_active_poll;
1572
1573         /* flags */
1574         ot->flag= 0;
1575 }
1576
1577 /* ********************* Set render border operator ****************** */
1578
1579 static int render_border_exec(bContext *C, wmOperator *op)
1580 {
1581         View3D *v3d = CTX_wm_view3d(C);
1582         ARegion *ar= CTX_wm_region(C);
1583         RegionView3D *rv3d= ED_view3d_context_rv3d(C);
1584         Scene *scene= CTX_data_scene(C);
1585
1586         rcti rect;
1587         rctf vb;
1588
1589         /* get border select values using rna */
1590         rect.xmin= RNA_int_get(op->ptr, "xmin");
1591         rect.ymin= RNA_int_get(op->ptr, "ymin");
1592         rect.xmax= RNA_int_get(op->ptr, "xmax");
1593         rect.ymax= RNA_int_get(op->ptr, "ymax");
1594
1595         /* calculate range */
1596         view3d_calc_camera_border(scene, ar, rv3d, v3d, &vb);
1597
1598         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1599         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1600         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1601         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1602
1603         /* actually set border */
1604         CLAMP(scene->r.border.xmin, 0.0, 1.0);
1605         CLAMP(scene->r.border.ymin, 0.0, 1.0);
1606         CLAMP(scene->r.border.xmax, 0.0, 1.0);
1607         CLAMP(scene->r.border.ymax, 0.0, 1.0);
1608
1609         /* drawing a border surrounding the entire camera view switches off border rendering
1610          * or the border covers no pixels */
1611         if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1612                 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1613            (scene->r.border.xmin == scene->r.border.xmax ||
1614                 scene->r.border.ymin == scene->r.border.ymax ))
1615         {
1616                 scene->r.mode &= ~R_BORDER;
1617         } else {
1618                 scene->r.mode |= R_BORDER;
1619         }
1620         
1621         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, NULL);
1622
1623         return OPERATOR_FINISHED;
1624
1625 }
1626
1627 void VIEW3D_OT_render_border(wmOperatorType *ot)
1628 {
1629         /* identifiers */
1630         ot->name= "Set Render Border";
1631         ot->description = "Set the boundries of the border render and enables border render ";
1632         ot->idname= "VIEW3D_OT_render_border";
1633
1634         /* api callbacks */
1635         ot->invoke= WM_border_select_invoke;
1636         ot->exec= render_border_exec;
1637         ot->modal= WM_border_select_modal;
1638
1639         ot->poll= view3d_camera_active_poll;
1640
1641         /* flags */
1642         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1643
1644         /* rna */
1645         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1646         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1647         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1648         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1649
1650 }
1651 /* ********************* Border Zoom operator ****************** */
1652
1653 static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
1654 {
1655         ARegion *ar= CTX_wm_region(C);
1656         View3D *v3d = CTX_wm_view3d(C);
1657         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1658         Scene *scene= CTX_data_scene(C);
1659
1660         /* Zooms in on a border drawn by the user */
1661         rcti rect;
1662         float dvec[3], vb[2], xscale, yscale, scale;
1663
1664         /* SMOOTHVIEW */
1665         float new_dist;
1666         float new_ofs[3];
1667
1668         /* ZBuffer depth vars */
1669         bglMats mats;
1670         float depth, depth_close= FLT_MAX;
1671         int had_depth = 0;
1672         double cent[2],  p[3];
1673         int xs, ys;
1674
1675         /* note; otherwise opengl won't work */
1676         view3d_operator_needs_opengl(C);
1677
1678         /* get border select values using rna */
1679         rect.xmin= RNA_int_get(op->ptr, "xmin");
1680         rect.ymin= RNA_int_get(op->ptr, "ymin");
1681         rect.xmax= RNA_int_get(op->ptr, "xmax");
1682         rect.ymax= RNA_int_get(op->ptr, "ymax");
1683
1684         /* Get Z Depths, needed for perspective, nice for ortho */
1685         bgl_get_mats(&mats);
1686         draw_depth(scene, ar, v3d, NULL);
1687
1688         /* force updating */
1689         if (rv3d->depths) {
1690                 had_depth = 1;
1691                 rv3d->depths->damaged = 1;
1692         }
1693
1694         view3d_update_depths(ar, v3d);
1695
1696         /* Constrain rect to depth bounds */
1697         if (rect.xmin < 0) rect.xmin = 0;
1698         if (rect.ymin < 0) rect.ymin = 0;
1699         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1700         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1701
1702         /* Find the closest Z pixel */
1703         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1704                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1705                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1706                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1707                                 if (depth_close > depth) {
1708                                         depth_close = depth;
1709                                 }
1710                         }
1711                 }
1712         }
1713
1714         if (had_depth==0) {
1715                 MEM_freeN(rv3d->depths->depths);
1716                 rv3d->depths->depths = NULL;
1717         }
1718         rv3d->depths->damaged = 1;
1719
1720         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1721         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1722
1723         if (rv3d->persp==RV3D_PERSP) {
1724                 double p_corner[3];
1725
1726                 /* no depths to use, we cant do anything! */
1727                 if (depth_close==FLT_MAX){
1728                         BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1729                         return OPERATOR_CANCELLED;
1730                 }
1731                 /* convert border to 3d coordinates */
1732                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1733                         (       !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])))
1734                         return OPERATOR_CANCELLED;
1735
1736                 dvec[0] = p[0]-p_corner[0];
1737                 dvec[1] = p[1]-p_corner[1];
1738                 dvec[2] = p[2]-p_corner[2];
1739
1740                 new_dist = len_v3(dvec);
1741                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1742
1743                 new_ofs[0] = -p[0];
1744                 new_ofs[1] = -p[1];
1745                 new_ofs[2] = -p[2];
1746
1747         } else { /* othographic */
1748                 /* find the current window width and height */
1749                 vb[0] = ar->winx;
1750                 vb[1] = ar->winy;
1751
1752                 new_dist = rv3d->dist;
1753
1754                 /* convert the drawn rectangle into 3d space */
1755                 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])) {
1756                         new_ofs[0] = -p[0];
1757                         new_ofs[1] = -p[1];
1758                         new_ofs[2] = -p[2];
1759                 } else {
1760                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1761                         copy_v3_v3(new_ofs, rv3d->ofs);
1762
1763                         initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1764
1765                         window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1766                         /* center the view to the center of the rectangle */
1767                         sub_v3_v3(new_ofs, dvec);
1768                 }
1769
1770                 /* work out the ratios, so that everything selected fits when we zoom */
1771                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1772                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1773                 scale = (xscale >= yscale)?xscale:yscale;
1774
1775                 /* zoom in as required, or as far as we can go */
1776                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1777         }
1778
1779         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1780
1781         if(rv3d->viewlock & RV3D_BOXVIEW)
1782                 view3d_boxview_sync(CTX_wm_area(C), ar);
1783
1784         return OPERATOR_FINISHED;
1785 }
1786
1787 static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1788 {
1789         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1790
1791         /* if in camera view do not exec the operator so we do not conflict with set render border*/
1792         if (rv3d->persp != RV3D_CAMOB)
1793                 return WM_border_select_invoke(C, op, event);
1794         else
1795                 return OPERATOR_PASS_THROUGH;
1796 }
1797
1798 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1799 {
1800         /* identifiers */
1801         ot->name= "Border Zoom";
1802         ot->description = "Zoom in the view to the nearest object contained in the border";
1803         ot->idname= "VIEW3D_OT_zoom_border";
1804
1805         /* api callbacks */
1806         ot->invoke= view3d_zoom_border_invoke;
1807         ot->exec= view3d_zoom_border_exec;
1808         ot->modal= WM_border_select_modal;
1809
1810         ot->poll= ED_operator_region_view3d_active;
1811
1812         /* flags */
1813         ot->flag= 0;
1814
1815         /* rna */
1816         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1817         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1818         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1819         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1820
1821 }
1822 /* ********************* Changing view operator ****************** */
1823
1824 static EnumPropertyItem prop_view_items[] = {
1825         {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1826         {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1827         {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1828         {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1829         {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1830         {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1831         {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1832         {0, NULL, 0, NULL, NULL}};
1833
1834
1835 /* would like to make this a generic function - outside of transform */
1836
1837 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo, int align_active)
1838 {
1839         View3D *v3d = CTX_wm_view3d(C);
1840         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1841         float new_quat[4];
1842
1843         new_quat[0]= q1; new_quat[1]= q2;
1844         new_quat[2]= q3; new_quat[3]= q4;
1845
1846         if(align_active) {
1847                 /* align to active object */
1848                 Object *obact= CTX_data_active_object(C);
1849                 if (obact==NULL) {
1850                         /* no active object, ignore this option */
1851                         align_active= FALSE;
1852                 }
1853                 else {
1854                         float obact_quat[4];
1855                         float twmat[3][3];
1856
1857                         /* same as transform manipulator when normal is set */
1858                         ED_getTransformOrientationMatrix(C, twmat, TRUE);
1859
1860                         mat3_to_quat( obact_quat,twmat);
1861                         invert_qt(obact_quat);
1862                         mul_qt_qtqt(new_quat, new_quat, obact_quat);
1863
1864                         rv3d->view= view= 0;
1865                 }
1866         }
1867
1868         if(align_active==FALSE) {
1869                 /* normal operation */
1870                 if(rv3d->viewlock) {
1871                         /* only pass on if */
1872                         if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
1873                         else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
1874                         else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
1875                         else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
1876                         else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
1877                         else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
1878                         else return;
1879                 }
1880
1881                 rv3d->view= view;
1882         }
1883
1884         if(rv3d->viewlock) {
1885                 ED_region_tag_redraw(CTX_wm_region(C));
1886                 return;
1887         }
1888
1889         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1890
1891                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= view ? RV3D_ORTHO : RV3D_PERSP;
1892                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1893
1894                 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1895         }
1896         else {
1897
1898                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= view ? RV3D_ORTHO : RV3D_PERSP;
1899                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1900
1901                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1902         }
1903
1904 }
1905
1906 static int viewnumpad_exec(bContext *C, wmOperator *op)
1907 {
1908         View3D *v3d = CTX_wm_view3d(C);
1909         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1910         Scene *scene= CTX_data_scene(C);
1911         static int perspo=RV3D_PERSP;
1912         int viewnum, align_active, nextperspo;
1913
1914         viewnum = RNA_enum_get(op->ptr, "type");
1915         align_active = RNA_boolean_get(op->ptr, "align_active");
1916
1917
1918         /* Use this to test if we started out with a camera */
1919
1920         if (rv3d->persp == RV3D_CAMOB) {
1921                 nextperspo= rv3d->lpersp;
1922         } else {
1923                 nextperspo= perspo;
1924         }
1925
1926         switch (viewnum) {
1927                 case RV3D_VIEW_BOTTOM :
1928                         axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1929                         break;
1930
1931                 case RV3D_VIEW_BACK:
1932                         axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, nextperspo, align_active);
1933                         break;
1934
1935                 case RV3D_VIEW_LEFT:
1936                         axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, nextperspo, align_active);
1937                         break;
1938
1939                 case RV3D_VIEW_TOP:
1940                         axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1941                         break;
1942
1943                 case RV3D_VIEW_FRONT:
1944                         axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, nextperspo, align_active);
1945                         break;
1946
1947                 case RV3D_VIEW_RIGHT:
1948                         axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, nextperspo, align_active);
1949                         break;
1950
1951                 case RV3D_VIEW_CAMERA:
1952                         if(rv3d->viewlock==0) {
1953                                 /* lastview -  */
1954
1955                                 if(rv3d->persp != RV3D_CAMOB) {
1956                                         Object *ob= OBACT;
1957
1958                                         if (!rv3d->smooth_timer) {
1959                                                 /* store settings of current view before allowing overwriting with camera view
1960                                                  * only if we're not currently in a view transition */
1961                                                 copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
1962                                                 rv3d->lview= rv3d->view;
1963                                                 rv3d->lpersp= rv3d->persp;
1964                                         }
1965
1966         #if 0
1967                                         if(G.qual==LR_ALTKEY) {
1968                                                 if(oldcamera && is_an_active_object(oldcamera)) {
1969                                                         v3d->camera= oldcamera;
1970                                                 }
1971                                                 handle_view3d_lock();
1972                                         }
1973         #endif
1974                                         
1975                                         /* first get the default camera for the view lock type */
1976                                         if(v3d->scenelock) {
1977                                                 /* sets the camera view if available */
1978                                                 v3d->camera= scene->camera;                                             
1979                                         }
1980                                         else {
1981                                                 /* use scene camera if one is not set (even though we're unlocked) */
1982                                                 if(v3d->camera==NULL) {
1983                                                         v3d->camera= scene->camera;
1984                                                 }
1985                                         }
1986
1987                                         /* if the camera isnt found, check a number of options */
1988                                         if(v3d->camera==NULL && ob && ob->type==OB_CAMERA)
1989                                                 v3d->camera= ob;
1990                                         
1991                                         if(v3d->camera==NULL)
1992                                                 v3d->camera= scene_find_camera(scene);          
1993
1994                                         /* couldnt find any useful camera, bail out */
1995                                         if(v3d->camera==NULL)
1996                                                 return OPERATOR_CANCELLED;
1997                                         
1998                                         /* important these dont get out of sync for locked scenes */
1999                                         if(v3d->scenelock)
2000                                                 scene->camera= v3d->camera;
2001
2002                                         /* finally do snazzy view zooming */
2003                                         rv3d->persp= RV3D_CAMOB;
2004                                         smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
2005
2006                                 }
2007                                 else{
2008                                         /* return to settings of last view */
2009                                         /* does smooth_view too */
2010                                         axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
2011                                 }
2012                         }
2013                         break;
2014
2015                 default :
2016                         break;
2017         }
2018
2019         if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
2020
2021         return OPERATOR_FINISHED;
2022 }
2023 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
2024 {
2025         /* identifiers */
2026         ot->name= "View numpad";
2027         ot->description = "Set the view";
2028         ot->idname= "VIEW3D_OT_viewnumpad";
2029
2030         /* api callbacks */
2031         ot->exec= viewnumpad_exec;
2032         ot->poll= ED_operator_region_view3d_active;
2033
2034         /* flags */
2035         ot->flag= 0;
2036
2037         RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
2038         RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
2039 }
2040
2041 static EnumPropertyItem prop_view_orbit_items[] = {
2042         {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
2043         {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
2044         {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
2045         {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
2046         {0, NULL, 0, NULL, NULL}};
2047
2048 static int vieworbit_exec(bContext *C, wmOperator *op)
2049 {
2050         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2051         float phi, q1[4], new_quat[4];
2052         int orbitdir;
2053
2054         orbitdir = RNA_enum_get(op->ptr, "type");
2055
2056         if(rv3d->viewlock==0) {
2057
2058                 if(rv3d->persp != RV3D_CAMOB) {
2059                         if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
2060                                 float si;
2061                                 /* z-axis */
2062                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
2063                                 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
2064                                 si= (float)sin(phi);
2065                                 q1[0]= (float)cos(phi);
2066                                 q1[1]= q1[2]= 0.0;
2067                                 q1[3]= si;
2068                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
2069                                 rv3d->view= 0;
2070                         }
2071                         else if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
2072                                 /* horizontal axis */
2073                                 copy_v3_v3(q1+1, rv3d->viewinv[0]);
2074
2075                                 normalize_v3(q1+1);
2076                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
2077                                 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
2078                                 q1[0]= (float)cos(phi);
2079                                 mul_v3_fl(q1+1, sin(phi));
2080                                 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
2081                                 rv3d->view= 0;
2082                         }
2083
2084                         smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
2085                 }
2086         }
2087
2088         return OPERATOR_FINISHED;
2089 }
2090
2091 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
2092 {
2093         /* identifiers */
2094         ot->name= "View Orbit";
2095         ot->description = "Orbit the view";
2096         ot->idname= "VIEW3D_OT_view_orbit";
2097
2098         /* api callbacks */
2099         ot->exec= vieworbit_exec;
2100         ot->poll= view3d_rotate_poll;
2101
2102         /* flags */
2103         ot->flag= 0;
2104         RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
2105 }
2106
2107 static EnumPropertyItem prop_view_pan_items[] = {
2108         {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
2109         {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
2110         {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
2111         {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
2112         {0, NULL, 0, NULL, NULL}};
2113
2114 static int viewpan_exec(bContext *C, wmOperator *op)
2115 {
2116         ARegion *ar= CTX_wm_region(C);
2117         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2118         float vec[3];
2119         int pandir;
2120
2121         pandir = RNA_enum_get(op->ptr, "type");
2122
2123         initgrabz(rv3d, 0.0, 0.0, 0.0);
2124
2125         if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
2126         else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
2127         else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
2128         else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
2129         rv3d->ofs[0]+= vec[0];
2130         rv3d->ofs[1]+= vec[1];
2131         rv3d->ofs[2]+= vec[2];
2132
2133         if(rv3d->viewlock & RV3D_BOXVIEW)
2134                 view3d_boxview_sync(CTX_wm_area(C), ar);
2135
2136         ED_region_tag_redraw(ar);
2137
2138         return OPERATOR_FINISHED;
2139 }
2140
2141 void VIEW3D_OT_view_pan(wmOperatorType *ot)
2142 {
2143         /* identifiers */
2144         ot->name= "View Pan";
2145         ot->description = "Pan the view";
2146         ot->idname= "VIEW3D_OT_view_pan";
2147
2148         /* api callbacks */
2149         ot->exec= viewpan_exec;
2150         ot->poll= ED_operator_region_view3d_active;
2151
2152         /* flags */
2153         ot->flag= 0;
2154         RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
2155 }
2156
2157 static int viewpersportho_exec(bContext *C, wmOperator *op)
2158 {
2159         ARegion *ar= CTX_wm_region(C);
2160         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2161
2162         if(rv3d->viewlock==0) {
2163                 if(rv3d->persp!=RV3D_ORTHO)
2164                         rv3d->persp=RV3D_ORTHO;
2165                 else rv3d->persp=RV3D_PERSP;
2166                 ED_region_tag_redraw(ar);
2167         }
2168
2169         return OPERATOR_FINISHED;
2170
2171 }
2172
2173 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
2174 {
2175         /* identifiers */
2176         ot->name= "View Persp/Ortho";
2177         ot->description = "Switch the current view from perspective/orthographic";
2178         ot->idname= "VIEW3D_OT_view_persportho";
2179
2180         /* api callbacks */
2181         ot->exec= viewpersportho_exec;
2182         ot->poll= ED_operator_region_view3d_active;
2183
2184         /* flags */
2185         ot->flag= 0;
2186 }
2187
2188 /* ******************** add background image operator **************** */
2189
2190 static BGpic *add_background_image(bContext *C)
2191 {
2192         View3D *v3d= CTX_wm_view3d(C);
2193         
2194         BGpic *bgpic= MEM_callocN(sizeof(BGpic), "Background Image");
2195         bgpic->size= 5.0;
2196         bgpic->blend= 0.5;
2197         bgpic->iuser.fie_ima= 2;
2198         bgpic->iuser.ok= 1;
2199         bgpic->view= 0; /* 0 for all */
2200         
2201         BLI_addtail(&v3d->bgpicbase, bgpic);
2202         
2203         return bgpic;
2204 }
2205
2206 static int add_background_image_exec(bContext *C, wmOperator *op)
2207 {
2208         add_background_image(C);
2209
2210         return OPERATOR_FINISHED;
2211 }
2212
2213 static int add_background_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
2214 {
2215         Scene *scene= CTX_data_scene(C);
2216         View3D *v3d= CTX_wm_view3d(C);
2217         Image *ima= NULL;
2218         BGpic *bgpic;
2219         char name[32];
2220         
2221         /* check input variables */
2222         if(RNA_property_is_set(op->ptr, "filepath")) {
2223                 char path[FILE_MAX];
2224                 
2225                 RNA_string_get(op->ptr, "filepath", path);
2226                 ima= BKE_add_image_file(path, scene ? scene->r.cfra : 1);
2227         }
2228         else if(RNA_property_is_set(op->ptr, "name")) {
2229                 RNA_string_get(op->ptr, "name", name);
2230                 ima= (Image *)find_id("IM", name);
2231         }
2232         
2233         bgpic = add_background_image(C);
2234         
2235         if (ima) {
2236                 bgpic->ima = ima;
2237                 
2238                 if(ima->id.us==0) id_us_plus(&ima->id);
2239                 else id_lib_extern(&ima->id);
2240                 
2241                 if (!(v3d->flag & V3D_DISPBGPICS))
2242                         v3d->flag |= V3D_DISPBGPICS;
2243         }
2244         
2245         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2246         
2247         return OPERATOR_FINISHED;
2248 }
2249
2250 void VIEW3D_OT_add_background_image(wmOperatorType *ot)
2251 {
2252         /* identifiers */
2253         ot->name   = "Add Background Image";
2254         ot->description= "Add a new background image";
2255         ot->idname = "VIEW3D_OT_add_background_image";
2256
2257         /* api callbacks */
2258         ot->invoke = add_background_image_invoke;
2259         ot->exec   = add_background_image_exec;
2260         ot->poll   = ED_operator_view3d_active;
2261
2262         /* flags */
2263         ot->flag   = 0;
2264         
2265         /* properties */
2266         RNA_def_string(ot->srna, "name", "Image", 24, "Name", "Image name to assign.");
2267         RNA_def_string(ot->srna, "filepath", "Path", FILE_MAX, "Filepath", "Path to image file");
2268 }
2269
2270
2271 /* ***** remove image operator ******* */
2272 static int remove_background_image_exec(bContext *C, wmOperator *op)
2273 {
2274         BGpic *bgpic_rem = CTX_data_pointer_get_type(C, "bgpic", &RNA_BackgroundImage).data;
2275         View3D *vd = CTX_wm_view3d(C);
2276         int index = RNA_int_get(op->ptr, "index");
2277
2278         bgpic_rem = BLI_findlink(&vd->bgpicbase, index);
2279         if(bgpic_rem) {
2280                 BLI_remlink(&vd->bgpicbase, bgpic_rem);
2281                 if(bgpic_rem->ima) bgpic_rem->ima->id.us--;
2282                 MEM_freeN(bgpic_rem);
2283         }
2284
2285         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, vd);
2286
2287         return OPERATOR_FINISHED;
2288 }
2289
2290 void VIEW3D_OT_remove_background_image(wmOperatorType *ot)
2291 {
2292         /* identifiers */
2293         ot->name   = "Remove Background Image";
2294         ot->description= "Remove a background image from the 3D view";
2295         ot->idname = "VIEW3D_OT_remove_background_image";
2296
2297         /* api callbacks */
2298         ot->exec   = remove_background_image_exec;
2299         ot->poll   = ED_operator_view3d_active;
2300
2301         /* flags */
2302         ot->flag   = 0;
2303
2304         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove ", 0, INT_MAX);
2305 }
2306
2307 /* ********************* set clipping operator ****************** */
2308
2309 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
2310 {
2311         int val;
2312
2313         for(val=0; val<4; val++) {
2314
2315                 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
2316
2317                 clip[val][3]=
2318                         - clip[val][0]*clipbb->vec[val][0]
2319                         - clip[val][1]*clipbb->vec[val][1]
2320                         - clip[val][2]*clipbb->vec[val][2];
2321         }
2322 }
2323
2324 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
2325 {
2326         BoundBox clipbb_local;
2327         float imat[4][4];
2328         int i;
2329
2330         invert_m4_m4(imat, mat);
2331
2332         for(i=0; i<8; i++) {
2333                 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
2334         }
2335
2336         calc_clipping_plane(clip_local, &clipbb_local);
2337 }
2338
2339 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
2340 {
2341         if(rv3d->rflag & RV3D_CLIPPING)
2342                 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
2343 }
2344
2345 static int view3d_clipping_exec(bContext *C, wmOperator *op)
2346 {
2347         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2348         ViewContext vc;
2349         bglMats mats;
2350         rcti rect;
2351
2352         rect.xmin= RNA_int_get(op->ptr, "xmin");
2353         rect.ymin= RNA_int_get(op->ptr, "ymin");
2354         rect.xmax= RNA_int_get(op->ptr, "xmax");
2355         rect.ymax= RNA_int_get(op->ptr, "ymax");
2356
2357         rv3d->rflag |= RV3D_CLIPPING;
2358         rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
2359
2360         /* note; otherwise opengl won't work */
2361         view3d_operator_needs_opengl(C);
2362
2363         view3d_set_viewcontext(C, &vc);
2364         view3d_get_transformation(vc.ar, vc.rv3d, NULL, &mats); /* NULL because we don't want it in object space */
2365         view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
2366
2367         return OPERATOR_FINISHED;
2368 }
2369
2370 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
2371 {
2372         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2373         ARegion *ar= CTX_wm_region(C);
2374
2375         if(rv3d->rflag & RV3D_CLIPPING) {
2376                 rv3d->rflag &= ~RV3D_CLIPPING;
2377                 ED_region_tag_redraw(ar);
2378                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
2379                 rv3d->clipbb= NULL;
2380                 return OPERATOR_FINISHED;
2381         }
2382         else {
2383                 return WM_border_select_invoke(C, op, event);
2384         }
2385 }
2386
2387 /* toggles */
2388 void VIEW3D_OT_clip_border(wmOperatorType *ot)
2389 {
2390
2391         /* identifiers */
2392         ot->name= "Clipping Border";
2393         ot->description = "Set the view clipping border";
2394         ot->idname= "VIEW3D_OT_clip_border";
2395
2396         /* api callbacks */
2397         ot->invoke= view3d_clipping_invoke;
2398         ot->exec= view3d_clipping_exec;
2399         ot->modal= WM_border_select_modal;
2400
2401         ot->poll= ED_operator_region_view3d_active;
2402
2403         /* flags */
2404         ot->flag= 0;
2405
2406         /* rna */
2407         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2408         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2409         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2410         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2411 }
2412
2413 /* ***************** 3d cursor cursor op ******************* */
2414
2415 /* mx my in region coords */
2416 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
2417 {
2418         Scene *scene= CTX_data_scene(C);
2419         ARegion *ar= CTX_wm_region(C);
2420         View3D *v3d = CTX_wm_view3d(C);
2421         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2422         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2423         short mx, my, mval[2];
2424 //      short ctrl= 0; // XXX
2425         int flip;
2426         fp= give_cursor(scene, v3d);
2427
2428 //      if(obedit && ctrl) lr_click= 1;
2429         copy_v3_v3(oldcurs, fp);
2430
2431         mx= event->x - ar->winrct.xmin;
2432         my= event->y - ar->winrct.ymin;
2433
2434         project_short_noclip(ar, fp, mval);
2435         flip= initgrabz(rv3d, fp[0], fp[1], fp[2]);
2436         
2437         /* reset the depth based on the view offset */
2438         if(flip) {
2439                 negate_v3_v3(fp, rv3d->ofs);
2440
2441                 /* re initialize */
2442                 project_short_noclip(ar, fp, mval);
2443                 flip= initgrabz(rv3d, fp[0], fp[1], fp[2]);
2444         }
2445
2446         if(mval[0]!=IS_CLIPPED) {
2447                 short depth_used = 0;
2448
2449                 if (U.uiflag & USER_ORBIT_ZBUF) { /* maybe this should be accessed some other way */
2450                         short mval_depth[2] = {mx, my};
2451                         view3d_operator_needs_opengl(C);
2452                         if (view_autodist(scene, ar, v3d, mval_depth, fp))
2453                                 depth_used= 1;
2454                 }
2455
2456                 if(depth_used==0) {
2457                         window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2458                         sub_v3_v3(fp, dvec);
2459                 }
2460         }
2461         else {
2462
2463                 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2464                 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2465
2466                 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2467                 fz= fz/rv3d->zfac;
2468
2469                 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2470                 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2471                 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2472         }
2473
2474         if(v3d && v3d->localvd)
2475                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2476         else
2477                 WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene);
2478
2479         return OPERATOR_FINISHED;
2480 }
2481
2482 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2483 {
2484
2485         /* identifiers */
2486         ot->name= "Set 3D Cursor";
2487         ot->description = "Set the location of the 3D cursor";
2488         ot->idname= "VIEW3D_OT_cursor3d";
2489
2490         /* api callbacks */
2491         ot->invoke= set_3dcursor_invoke;
2492
2493         ot->poll= ED_operator_view3d_active;
2494     
2495         /* flags */
2496 //      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2497     
2498         /* rna later */
2499
2500 }
2501
2502 /* ***************** manipulator op ******************* */
2503
2504
2505 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2506 {
2507         View3D *v3d = CTX_wm_view3d(C);
2508
2509         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2510         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2511
2512         /* only no modifier or shift */
2513         if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2514
2515         /* note; otherwise opengl won't work */
2516         view3d_operator_needs_opengl(C);
2517
2518         if(0==BIF_do_manipulator(C, event, op))
2519                 return OPERATOR_PASS_THROUGH;
2520
2521         return OPERATOR_FINISHED;
2522 }
2523
2524 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2525 {
2526
2527         /* identifiers */
2528         ot->name= "3D Manipulator";
2529         ot->description = "Manipulate selected item by axis";
2530         ot->idname= "VIEW3D_OT_manipulator";
2531
2532         /* api callbacks */
2533         ot->invoke= manipulator_invoke;
2534
2535         ot->poll= ED_operator_view3d_active;
2536
2537         /* properties to pass to transform */
2538         Transform_Properties(ot, P_CONSTRAINT);
2539 }
2540
2541 static int enable_manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2542 {
2543         View3D *v3d = CTX_wm_view3d(C);
2544
2545         v3d->twtype=0;
2546         
2547         if (RNA_boolean_get(op->ptr, "translate"))
2548                 v3d->twtype |= V3D_MANIP_TRANSLATE;
2549         if (RNA_boolean_get(op->ptr, "rotate"))
2550                 v3d->twtype |= V3D_MANIP_ROTATE;
2551         if (RNA_boolean_get(op->ptr, "scale"))
2552                 v3d->twtype |= V3D_MANIP_SCALE;
2553                 
2554         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2555
2556         return OPERATOR_FINISHED;
2557 }
2558
2559 void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
2560 {
2561         /* identifiers */
2562         ot->name= "Enable 3D Manipulator";
2563         ot->description = "Enable the transform manipulator for use";
2564         ot->idname= "VIEW3D_OT_enable_manipulator";
2565         
2566         /* api callbacks */
2567         ot->invoke= enable_manipulator_invoke;
2568         ot->poll= ED_operator_view3d_active;
2569         
2570         /* rna later */
2571         RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator");
2572         RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator");
2573         RNA_def_boolean(ot->srna, "scale", 0, "Scale", "Enable the scale manipulator");
2574 }
2575
2576 /* ************************* below the line! *********************** */
2577
2578
2579 static float view_autodist_depth_margin(ARegion *ar, short *mval, int margin)
2580 {
2581         RegionView3D *rv3d= ar->regiondata;
2582         float depth= FLT_MAX;
2583
2584         if(margin==0) {
2585                 if (mval[0] < 0) return 0;
2586                 if (mval[1] < 0) return 0;
2587                 if (mval[0] >= rv3d->depths->w) return 0;
2588                 if (mval[1] >= rv3d->depths->h) return 0;
2589
2590                 /* Get Z Depths, needed for perspective, nice for ortho */
2591                 depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
2592                 if(depth >= rv3d->depths->depth_range[1] || depth <= rv3d->depths->depth_range[0]) {
2593                         depth= FLT_MAX;
2594                 }
2595         }
2596         else {
2597                 rcti rect;
2598                 float depth_close= FLT_MAX;
2599                 int xs, ys;
2600
2601                 rect.xmax = mval[0] + margin;
2602                 rect.ymax = mval[1] + margin;
2603
2604                 rect.xmin = mval[0] - margin;
2605                 rect.ymin = mval[1] - margin;
2606
2607                 /* Constrain rect to depth bounds */
2608                 if (rect.xmin < 0) rect.xmin = 0;
2609                 if (rect.ymin < 0) rect.ymin = 0;
2610                 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
2611                 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
2612
2613                 /* Find the closest Z pixel */
2614                 for (xs=rect.xmin; xs < rect.xmax; xs++) {
2615                         for (ys=rect.ymin; ys < rect.ymax; ys++) {
2616                                 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
2617                                 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
2618                                         if (depth_close > depth) {
2619                                                 depth_close = depth;
2620                                         }
2621                                 }
2622                         }
2623                 }
2624
2625                 depth= depth_close;
2626         }
2627
2628         return depth;
2629 }
2630
2631 /* XXX todo Zooms in on a border drawn by the user */
2632 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2633 {
2634         RegionView3D *rv3d= ar->regiondata;
2635         bglMats mats; /* ZBuffer depth vars */
2636         float depth_close= FLT_MAX;
2637         int had_depth = 0;
2638         double cent[2],  p[3];
2639
2640         /* Get Z Depths, needed for perspective, nice for ortho */
2641         bgl_get_mats(&mats);
2642         draw_depth(scene, ar, v3d, NULL);
2643
2644         /* force updating */
2645         if (rv3d->depths) {
2646                 had_depth = 1;
2647                 rv3d->depths->damaged = 1;
2648         }
2649
2650         view3d_update_depths(ar, v3d);
2651
2652         depth_close= view_autodist_depth_margin(ar, mval, 4);
2653
2654         if (depth_close==FLT_MAX)
2655                 return 0;
2656
2657         if (had_depth==0) {
2658                 MEM_freeN(rv3d->depths->depths);
2659                 rv3d->depths->depths = NULL;
2660         }
2661         rv3d->depths->damaged = 1;
2662
2663         cent[0] = (double)mval[0];
2664         cent[1] = (double)mval[1];
2665
2666         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2667                 return 0;
2668
2669         mouse_worldloc[0] = (float)p[0];
2670         mouse_worldloc[1] = (float)p[1];
2671         mouse_worldloc[2] = (float)p[2];
2672         return 1;
2673 }
2674
2675 int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode) //, float *autodist )
2676 {
2677         RegionView3D *rv3d= ar->regiondata;
2678
2679         /* Get Z Depths, needed for perspective, nice for ortho */
2680         switch(mode) {
2681         case 0:
2682                 draw_depth(scene, ar, v3d, NULL);
2683                 break;
2684         case 1:
2685                 draw_depth_gpencil(scene, ar, v3d);
2686                 break;
2687         }
2688
2689         /* force updating */
2690         if (rv3d->depths) {
2691                 rv3d->depths->damaged = 1;
2692         }
2693
2694         view3d_update_depths(ar, v3d);
2695         return 1;
2696 }
2697
2698 // no 4x4 sampling, run view_autodist_init first
2699 int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3], int margin, float *force_depth) //, float *autodist )
2700 {
2701         bglMats mats; /* ZBuffer depth vars, could cache? */
2702         float depth;
2703         double cent[2],  p[3];
2704
2705         /* Get Z Depths, needed for perspective, nice for ortho */
2706         if(force_depth)
2707                 depth= *force_depth;
2708         else
2709                 depth= view_autodist_depth_margin(ar, mval, margin);
2710
2711         if (depth==FLT_MAX)
2712                 return 0;
2713
2714         cent[0] = (double)mval[0];
2715         cent[1] = (double)mval[1];
2716
2717         bgl_get_mats(&mats);
2718         if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2719                 return 0;
2720
2721         mouse_worldloc[0] = (float)p[0];
2722         mouse_worldloc[1] = (float)p[1];
2723         mouse_worldloc[2] = (float)p[2];
2724         return 1;
2725 }
2726
2727 int view_autodist_depth(struct ARegion *ar, short *mval, int margin, float *depth)
2728 {
2729         *depth= view_autodist_depth_margin(ar, mval, margin);
2730
2731         return (*depth==FLT_MAX) ? 0:1;
2732                 return 0;
2733 }
2734
2735 /* ********************* NDOF ************************ */
2736 /* note: this code is confusing and unclear... (ton) */
2737 /* **************************************************** */
2738
2739 // ndof scaling will be moved to user setting.
2740 // In the mean time this is just a place holder.
2741
2742 // Note: scaling in the plugin and ghostwinlay.c
2743 // should be removed. With driver default setting,
2744 // each axis returns approx. +-200 max deflection.
2745
2746 // The values I selected are based on the older
2747 // polling i/f. With event i/f, the sensistivity
2748 // can be increased for improved response from
2749 // small deflections of the device input.
2750
2751
2752 // lukep notes : i disagree on the range.
2753 // the normal 3Dconnection driver give +/-400
2754 // on defaut range in other applications
2755 // and up to +/- 1000 if set to maximum
2756 // because i remove the scaling by delta,
2757 // which was a bad idea as it depend of the system
2758 // speed and os, i changed the scaling values, but
2759 // those are still not ok
2760
2761
2762 float ndof_axis_scale[6] = {
2763         +0.01,  // Tx
2764         +0.01,  // Tz
2765         +0.01,  // Ty
2766         +0.0015,        // Rx
2767         +0.0015,        // Rz
2768         +0.0015 // Ry
2769 };
2770
2771 void filterNDOFvalues(float *sbval)
2772 {
2773         int i=0;
2774         float max  = 0.0;
2775
2776         for (i =0; i<6;i++)
2777                 if (fabs(sbval[i]) > max)
2778                         max = fabs(sbval[i]);
2779         for (i =0; i<6;i++)
2780                 if (fabs(sbval[i]) != max )
2781                         sbval[i]=0.0;
2782 }
2783
2784 // statics for controlling rv3d->dist corrections.
2785 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2786 // viewmove restores based on dz_flag state.
2787
2788 int dz_flag = 0;
2789 float m_dist;
2790
2791 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2792 {
2793         RegionView3D *rv3d= ar->regiondata;
2794         int i;
2795         float phi;
2796         float dval[7];
2797         // static fval[6] for low pass filter; device input vector is dval[6]
2798         static float fval[6];
2799         float tvec[3],rvec[3];
2800         float q1[4];
2801         float mat[3][3];
2802         float upvec[3];
2803
2804
2805         /*----------------------------------------------------
2806          * sometimes this routine is called from headerbuttons
2807          * viewmove needs to refresh the screen
2808          */
2809 // XXX  areawinset(ar->win);
2810
2811
2812         // fetch the current state of the ndof device
2813 // XXX  getndof(dval);
2814
2815         if (v3d->ndoffilter)
2816                 filterNDOFvalues(fval);
2817
2818         // Scale input values
2819
2820 //      if(dval[6] == 0) return; // guard against divide by zero
2821
2822         for(i=0;i<6;i++) {
2823
2824                 // user scaling
2825                 dval[i] = dval[i] * ndof_axis_scale[i];
2826         }
2827
2828
2829         // low pass filter with zero crossing reset
2830
2831         for(i=0;i<6;i++) {
2832                 if((dval[i] * fval[i]) >= 0)
2833                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
2834                 else
2835                         fval[i] = 0;
2836         }
2837
2838
2839         // force perspective mode. This is a hack and is
2840         // incomplete. It doesn't actually effect the view
2841         // until the first draw and doesn't update the menu
2842         // to reflect persp mode.
2843
2844         rv3d->persp = RV3D_PERSP;
2845
2846
2847         // Correct the distance jump if rv3d->dist != 0
2848
2849         // This is due to a side effect of the original
2850         // mouse view rotation code. The rotation point is
2851         // set a distance in front of the viewport to
2852         // make rotating with the mouse look better.
2853         // The distance effect is written at a low level
2854         // in the view management instead of the mouse
2855         // view function. This means that all other view
2856         // movement devices must subtract this from their
2857         // view transformations.
2858
2859         if(rv3d->dist != 0.0) {
2860                 dz_flag = 1;
2861                 m_dist = rv3d->dist;
2862                 upvec[0] = upvec[1] = 0;
2863                 upvec[2] = rv3d->dist;
2864                 copy_m3_m4(mat, rv3d->viewinv);
2865                 mul_m3_v3(mat, upvec);
2866                 sub_v3_v3(rv3d->ofs, upvec);
2867                 rv3d->dist = 0.0;
2868         }
2869
2870
2871         // Apply rotation
2872         // Rotations feel relatively faster than translations only in fly mode, so
2873         // we have no choice but to fix that here (not in the plugins)
2874         rvec[0] = -0.5 * dval[3];
2875         rvec[1] = -0.5 * dval[4];
2876         rvec[2] = -0.5 * dval[5];
2877
2878         // rotate device x and y by view z
2879
2880         copy_m3_m4(mat, rv3d->viewinv);
2881         mat[2][2] = 0.0f;
2882         mul_m3_v3(mat, rvec);
2883
2884         // rotate the view
2885
2886         phi = normalize_v3(rvec);
2887         if(phi != 0) {
2888                 axis_angle_to_quat(q1,rvec,phi);
2889                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2890         }
2891
2892
2893         // Apply translation
2894
2895         tvec[0] = dval[0];
2896         tvec[1] = dval[1];
2897         tvec[2] = -dval[2];
2898
2899         // the next three lines rotate the x and y translation coordinates
2900         // by the current z axis angle
2901
2902         copy_m3_m4(mat, rv3d->viewinv);
2903         mat[2][2] = 0.0f;
2904         mul_m3_v3(mat, tvec);
2905
2906         // translate the view
2907
2908         sub_v3_v3(rv3d->ofs, tvec);
2909
2910
2911         /*----------------------------------------------------
2912          * refresh the screen XXX
2913           */
2914
2915         // update render preview window
2916
2917 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2918 }
2919
2920 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2921 {
2922         RegionView3D *rv3d= ar->regiondata;
2923         float fval[7];
2924         float dvec[3];
2925         float sbadjust = 1.0f;
2926         float len;
2927         short use_sel = 0;
2928         Object *ob = OBACT;
2929         float m[3][3];
2930         float m_inv[3][3];
2931         float xvec[3] = {1,0,0};
2932         float yvec[3] = {0,-1,0};
2933         float zvec[3] = {0,0,1};
2934         float phi;
2935         float q1[4];
2936         float obofs[3];
2937         float reverse;
2938         //float diff[4];
2939         float d, curareaX, curareaY;
2940         float mat[3][3];
2941         float upvec[3];
2942
2943         /* Sensitivity will control how fast the view rotates.  The value was
2944          * obtained experimentally by tweaking until the author didn't get dizzy watching.
2945          * Perhaps this should be a configurable user parameter.
2946          */
2947         float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
2948         float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
2949         float zsens = 0.3f;   /* zoom sensitivity */
2950
2951         const float minZoom = -30.0f;
2952         const float maxZoom = 300.0f;
2953
2954         //reset view type
2955         rv3d->view = 0;
2956 //printf("passing here \n");
2957 //
2958         if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
2959                 use_sel = 1;
2960         }
2961
2962         if((dz_flag)||rv3d->dist==0) {
2963                 dz_flag = 0;
2964                 rv3d->dist = m_dist;
2965                 upvec[0] = upvec[1] = 0;
2966                 upvec[2] = rv3d->dist;
2967                 copy_m3_m4(mat, rv3d->viewinv);
2968                 mul_m3_v3(mat, upvec);
2969                 add_v3_v3(rv3d->ofs, upvec);
2970         }
2971
2972         /*----------------------------------------------------
2973          * sometimes this routine is called from headerbuttons
2974          * viewmove needs to refresh the screen
2975          */
2976 // XXX  areawinset(curarea->win);
2977
2978         /*----------------------------------------------------
2979          * record how much time has passed. clamp at 10 Hz
2980          * pretend the previous frame occurred at the clamped time
2981          */
2982 //    now = PIL_check_seconds_timer();
2983  //   frametime = (now - prevTime);
2984  //   if (frametime > 0.1f){        /* if more than 1/10s */
2985  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
2986 //    }
2987 //    prevTime = now;
2988  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
2989
2990         /* fetch the current state of the ndof device & enforce dominant mode if selected */
2991 // XXX    getndof(fval);
2992         if (v3d->ndoffilter)
2993                 filterNDOFvalues(fval);
2994
2995
2996         // put scaling back here, was previously in ghostwinlay
2997         fval[0] = fval[0] * (1.0f/600.0f);
2998         fval[1] = fval[1] * (1.0f/600.0f);
2999         fval[2] = fval[2] * (1.0f/1100.0f);
3000         fval[3] = fval[3] * 0.00005f;
3001         fval[4] =-fval[4] * 0.00005f;
3002         fval[5] = fval[5] * 0.00005f;
3003         fval[6] = fval[6] / 1000000.0f;
3004
3005         // scale more if not in perspective mode
3006         if (rv3d->persp == RV3D_ORTHO) {
3007                 fval[0] = fval[0] * 0.05f;
3008                 fval[1] = fval[1] * 0.05f;
3009                 fval[2] = fval[2] * 0.05f;
3010                 fval[3] = fval[3] * 0.9f;
3011                 fval[4] = fval[4] * 0.9f;
3012                 fval[5] = fval[5] * 0.9f;
3013                 zsens *= 8;
3014         }
3015
3016         /* set object offset */
3017         if (ob) {
3018                 obofs[0] = -ob->obmat[3][0];
3019                 obofs[1] = -ob->obmat[3][1];
3020                 obofs[2] = -ob->obmat[3][2];
3021         }
3022         else {
3023                 copy_v3_v3(obofs, rv3d->ofs);
3024         }
3025
3026         /* calc an adjustment based on distance from camera
3027            disabled per patch 14402 */
3028          d = 1.0f;
3029
3030 /*    if (ob) {
3031                 sub_v3_v3v3(diff, obofs, rv3d->ofs);
3032                 d = len_v3(diff);
3033         }
3034 */
3035
3036         reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
3037
3038         /*----------------------------------------------------
3039          * ndof device pan
3040          */
3041         psens *= 1.0f + d;
3042         curareaX = sbadjust * psens * fval[0];
3043         curareaY = sbadjust * psens * fval[1];
3044         dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
3045         dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
3046         dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
3047         add_v3_v3(rv3d->ofs, dvec);
3048
3049         /*----------------------------------------------------
3050          * ndof device dolly
3051          */
3052         len = zsens * sbadjust * fval[2];
3053
3054         if (rv3d->persp==RV3D_CAMOB) {
3055                 if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
3056                         rv3d->camzoom+= 10.0f * -len;
3057                 }
3058                 if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
3059                 else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
3060         }
3061         else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
3062                 rv3d->dist*=(1.0 + len);
3063         }
3064
3065
3066         /*----------------------------------------------------
3067          * ndof device turntable
3068          * derived from the turntable code in viewmove
3069          */
3070
3071         /* Get the 3x3 matrix and its inverse from the quaternion */
3072         quat_to_mat3( m,rv3d->viewquat);
3073         invert_m3_m3(m_inv,m);
3074
3075         /* Determine the direction of the x vector (for rotating up and down) */
3076         /* This can likely be compuated directly from the quaternion. */
3077         mul_m3_v3(m_inv,xvec);
3078         mul_m3_v3(m_inv,yvec);
3079         mul_m3_v3(m_inv,zvec);
3080
3081         /* Perform the up/down rotation */
3082         phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
3083         q1[0] = cos(phi);
3084         mul_v3_v3fl(q1+1, xvec, sin(phi));
3085         mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
3086
3087         if (use_sel) {
3088                 conjugate_qt(q1); /* conj == inv for unit quat */
3089                 sub_v3_v3(rv3d->ofs, obofs);
3090                 mul_qt_v3(q1, rv3d->ofs);
3091                 add_v3_v3(rv3d->ofs, obofs);
3092         }
3093
3094         /* Perform the orbital rotation */
3095         /* Perform the orbital rotation
3096            If the seen Up axis is parallel to the zoom axis, rotation should be
3097            achieved with a pure Roll motion (no Spin) on the device. When you start
3098            to tilt, moving from Top to Side view, Spinning will increasingly become
3099            more relevant while the Roll component will decrease. When a full
3100            Side view is reached, rotations around the world's Up axis are achieved
3101            with a pure Spin-only motion.  In other words the control of the spinning
3102            around the world's Up axis should move from the device's Spin axis to the
3103            device's Roll axis depending on the orientation of the world's Up axis
3104            relative to the screen. */
3105         //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
3106         phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
3107         q1[0] = cos(phi);
3108         q1[1] = q1[2] = 0.0;
3109         q1[3] = sin(phi);
3110         mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
3111
3112         if (use_sel) {
3113                 conjugate_qt(q1);
3114                 sub_v3_v3(rv3d->ofs, obofs);
3115                 mul_qt_v3(q1, rv3d->ofs);
3116                 add_v3_v3(rv3d->ofs, obofs);
3117         }
3118
3119         /*----------------------------------------------------
3120          * refresh the screen
3121          */
3122 // XXX    scrarea_do_windraw(curarea);
3123 }
3124
3125
3126
3127