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