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