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