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