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