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