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