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