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