2.5 Sculpt Branch Merge
[blender-staging.git] / source / blender / editors / space_view3d / view3d_edit.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_lamp_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_userdef_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_world_types.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_math.h"
50 #include "BLI_rand.h"
51
52 #include "BKE_action.h"
53 #include "BKE_context.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_object.h"
56 #include "BKE_global.h"
57 #include "BKE_paint.h"
58 #include "BKE_report.h"
59 #include "BKE_scene.h"
60 #include "BKE_screen.h"
61 #include "BKE_utildefines.h"
62
63 #include "RE_pipeline.h"        // make_stars
64
65 #include "BIF_gl.h"
66
67 #include "WM_api.h"
68 #include "WM_types.h"
69
70 #include "RNA_access.h"
71 #include "RNA_define.h"
72
73 #include "ED_particle.h"
74 #include "ED_retopo.h"
75 #include "ED_space_api.h"
76 #include "ED_screen.h"
77 #include "ED_transform.h"
78 #include "ED_types.h"
79
80 #include "UI_interface.h"
81 #include "UI_resources.h"
82 #include "UI_view2d.h"
83
84 #include "PIL_time.h" /* smoothview */
85
86 #include "view3d_intern.h"      // own include
87
88 /* ********************** view3d_edit: view manipulations ********************* */
89
90 /* ********************* box view support ***************** */
91
92 static void view3d_boxview_clip(ScrArea *sa)
93 {
94         ARegion *ar;
95         BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
96         float clip[6][4];
97         float x1= 0.0f, y1= 0.0f, z1= 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
98         int val;
99
100         /* create bounding box */
101         for(ar= sa->regionbase.first; ar; ar= ar->next) {
102                 if(ar->regiontype==RGN_TYPE_WINDOW) {
103                         RegionView3D *rv3d= ar->regiondata;
104
105                         if(rv3d->viewlock & RV3D_BOXCLIP) {
106                                 if(ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
107                                         if(ar->winx>ar->winy) x1= rv3d->dist;
108                                         else x1= ar->winx*rv3d->dist/ar->winy;
109
110                                         if(ar->winx>ar->winy) y1= ar->winy*rv3d->dist/ar->winx;
111                                         else y1= rv3d->dist;
112
113                                         ofs[0]= rv3d->ofs[0];
114                                         ofs[1]= rv3d->ofs[1];
115                                 }
116                                 else if(ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
117                                         ofs[2]= rv3d->ofs[2];
118
119                                         if(ar->winx>ar->winy) z1= ar->winy*rv3d->dist/ar->winx;
120                                         else z1= rv3d->dist;
121                                 }
122                         }
123                 }
124         }
125
126         for(val=0; val<8; val++) {
127                 if(ELEM4(val, 0, 3, 4, 7))
128                         bb->vec[val][0]= -x1 - ofs[0];
129                 else
130                         bb->vec[val][0]=  x1 - ofs[0];
131
132                 if(ELEM4(val, 0, 1, 4, 5))
133                         bb->vec[val][1]= -y1 - ofs[1];
134                 else
135                         bb->vec[val][1]=  y1 - ofs[1];
136
137                 if(val > 3)
138                         bb->vec[val][2]= -z1 - ofs[2];
139                 else
140                         bb->vec[val][2]=  z1 - ofs[2];
141         }
142
143         /* normals for plane equations */
144         normal_tri_v3( clip[0],bb->vec[0], bb->vec[1], bb->vec[4]);
145         normal_tri_v3( clip[1],bb->vec[1], bb->vec[2], bb->vec[5]);
146         normal_tri_v3( clip[2],bb->vec[2], bb->vec[3], bb->vec[6]);
147         normal_tri_v3( clip[3],bb->vec[3], bb->vec[0], bb->vec[7]);
148         normal_tri_v3( clip[4],bb->vec[4], bb->vec[5], bb->vec[6]);
149         normal_tri_v3( clip[5],bb->vec[0], bb->vec[2], bb->vec[1]);
150
151         /* then plane equations */
152         for(val=0; val<5; val++) {
153                 clip[val][3]= - clip[val][0]*bb->vec[val][0] - clip[val][1]*bb->vec[val][1] - clip[val][2]*bb->vec[val][2];
154         }
155         clip[5][3]= - clip[5][0]*bb->vec[0][0] - clip[5][1]*bb->vec[0][1] - clip[5][2]*bb->vec[0][2];
156
157         /* create bounding box */
158         for(ar= sa->regionbase.first; ar; ar= ar->next) {
159                 if(ar->regiontype==RGN_TYPE_WINDOW) {
160                         RegionView3D *rv3d= ar->regiondata;
161
162                         if(rv3d->viewlock & RV3D_BOXCLIP) {
163                                 rv3d->rflag |= RV3D_CLIPPING;
164                                 memcpy(rv3d->clip, clip, sizeof(clip));
165                         }
166                 }
167         }
168         MEM_freeN(bb);
169 }
170
171 /* sync center/zoom view of region to others, for view transforms */
172 static void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
173 {
174         ARegion *artest;
175         RegionView3D *rv3d= ar->regiondata;
176
177         for(artest= sa->regionbase.first; artest; artest= artest->next) {
178                 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
179                         RegionView3D *rv3dtest= artest->regiondata;
180
181                         if(rv3dtest->viewlock) {
182                                 rv3dtest->dist= rv3d->dist;
183
184                                 if( ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ) {
185                                         if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
186                                                 rv3dtest->ofs[0]= rv3d->ofs[0];
187                                         else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
188                                                 rv3dtest->ofs[1]= rv3d->ofs[1];
189                                 }
190                                 else if( ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK) ) {
191                                         if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
192                                                 rv3dtest->ofs[0]= rv3d->ofs[0];
193                                         else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
194                                                 rv3dtest->ofs[2]= rv3d->ofs[2];
195                                 }
196                                 else if( ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ) {
197                                         if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
198                                                 rv3dtest->ofs[1]= rv3d->ofs[1];
199                                         if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
200                                                 rv3dtest->ofs[2]= rv3d->ofs[2];
201                                 }
202
203                                 ED_region_tag_redraw(artest);
204                         }
205                 }
206         }
207         view3d_boxview_clip(sa);
208 }
209
210 /* for home, center etc */
211 void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
212 {
213         ARegion *artest;
214         RegionView3D *rv3d= ar->regiondata;
215
216         for(artest= sa->regionbase.first; artest; artest= artest->next) {
217                 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
218                         RegionView3D *rv3dtest= artest->regiondata;
219
220                         if(rv3dtest->viewlock) {
221                                 rv3dtest->dist= rv3d->dist;
222                                 VECCOPY(rv3dtest->ofs, rv3d->ofs);
223                                 ED_region_tag_redraw(artest);
224                         }
225                 }
226         }
227         view3d_boxview_clip(sa);
228 }
229
230 /* ************************** init for view ops **********************************/
231
232 typedef struct ViewOpsData {
233         ScrArea *sa;
234         ARegion *ar;
235         RegionView3D *rv3d;
236
237         float oldquat[4];
238         float trackvec[3];
239         float reverse, dist0;
240         float grid, far;
241         short axis_snap; /* view rotate only */
242
243         /* use for orbit selection and auto-dist */
244         float ofs[3], dyn_ofs[3];
245         short use_dyn_ofs;
246
247         int origx, origy, oldx, oldy;
248         int origkey; /* the key that triggered the operator */
249
250 } ViewOpsData;
251
252 #define TRACKBALLSIZE  (1.1)
253
254 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
255 {
256         float x, y, radius, d, z, t;
257
258         radius= TRACKBALLSIZE;
259
260         /* normalize x and y */
261         x= (rect->xmax + rect->xmin)/2 - mx;
262         x/= (float)((rect->xmax - rect->xmin)/4);
263         y= (rect->ymax + rect->ymin)/2 - my;
264         y/= (float)((rect->ymax - rect->ymin)/2);
265
266         d = sqrt(x*x + y*y);
267         if (d < radius*M_SQRT1_2)       /* Inside sphere */
268                 z = sqrt(radius*radius - d*d);
269         else
270         {                       /* On hyperbola */
271                 t = radius / M_SQRT2;
272                 z = t*t / d;
273         }
274
275         vec[0]= x;
276         vec[1]= y;
277         vec[2]= -z;             /* yah yah! */
278 }
279
280
281 static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
282 {
283         static float lastofs[3] = {0,0,0};
284         View3D *v3d = CTX_wm_view3d(C);
285         RegionView3D *rv3d;
286         ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
287
288         /* store data */
289         op->customdata= vod;
290         vod->sa= CTX_wm_area(C);
291         vod->ar= CTX_wm_region(C);
292         vod->rv3d= rv3d= vod->ar->regiondata;
293         vod->dist0= rv3d->dist;
294         QUATCOPY(vod->oldquat, rv3d->viewquat);
295         vod->origx= vod->oldx= event->x;
296         vod->origy= vod->oldy= event->y;
297         vod->origkey= event->type; /* the key that triggered the operator.  */
298         vod->use_dyn_ofs= (U.uiflag & USER_ORBIT_SELECTION) ? 1:0;
299
300         if (vod->use_dyn_ofs) {
301                 VECCOPY(vod->ofs, rv3d->ofs);
302                 /* If there's no selection, lastofs is unmodified and last value since static */
303                 calculateTransformCenter(C, event, V3D_CENTROID, lastofs);
304                 VECCOPY(vod->dyn_ofs, lastofs);
305                 mul_v3_fl(vod->dyn_ofs, -1.0f);
306         }
307         else if (U.uiflag & USER_ORBIT_ZBUF) {
308
309                 view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
310
311                 if((vod->use_dyn_ofs=view_autodist(CTX_data_scene(C), vod->ar, v3d, event->mval, vod->dyn_ofs))) {
312                         if (rv3d->persp==RV3D_PERSP) {
313                                 float my_origin[3]; /* original G.vd->ofs */
314                                 float my_pivot[3]; /* view */
315                                 float dvec[3];
316
317                                 // locals for dist correction
318                                 float mat[3][3];
319                                 float upvec[3];
320
321                                 VECCOPY(my_origin, rv3d->ofs);
322                                 negate_v3(my_origin);                           /* ofs is flipped */
323
324                                 /* Set the dist value to be the distance from this 3d point */
325                                 /* this means youll always be able to zoom into it and panning wont go bad when dist was zero */
326
327                                 /* remove dist value */
328                                 upvec[0] = upvec[1] = 0;
329                                 upvec[2] = rv3d->dist;
330                                 copy_m3_m4(mat, rv3d->viewinv);
331
332                                 mul_m3_v3(mat, upvec);
333                                 sub_v3_v3v3(my_pivot, rv3d->ofs, upvec);
334                                 negate_v3(my_pivot);                            /* ofs is flipped */
335
336                                 /* find a new ofs value that is allong the view axis (rather then the mouse location) */
337                                 closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin);
338                                 vod->dist0 = rv3d->dist = len_v3v3(my_pivot, dvec);
339
340                                 negate_v3(dvec);
341                                 VECCOPY(rv3d->ofs, dvec);
342                         }
343                         negate_v3(vod->dyn_ofs);
344                         VECCOPY(vod->ofs, rv3d->ofs);
345                 } else {
346                         vod->ofs[0] = vod->ofs[1] = vod->ofs[2] = 0.0f;
347                 }
348         }
349
350         /* lookup, we dont pass on v3d to prevent confusement */
351         vod->grid= v3d->grid;
352         vod->far= v3d->far;
353
354         calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
355
356         initgrabz(rv3d, -rv3d->ofs[0], -rv3d->ofs[1], -rv3d->ofs[2]);
357
358         vod->reverse= 1.0f;
359         if (rv3d->persmat[2][1] < 0.0f)
360                 vod->reverse= -1.0f;
361
362         rv3d->rflag |= RV3D_NAVIGATING;
363 }
364
365 static void viewops_data_free(bContext *C, wmOperator *op)
366 {
367         Paint *p = paint_get_active(CTX_data_scene(C));
368         ViewOpsData *vod= op->customdata;
369
370         vod->rv3d->rflag &= ~RV3D_NAVIGATING;
371
372         if(p && (p->flags & PAINT_FAST_NAVIGATE))
373                 ED_region_tag_redraw(vod->ar);
374
375         MEM_freeN(vod);
376         op->customdata= NULL;
377 }
378
379 /* ************************** viewrotate **********************************/
380
381 static const float thres = 0.93f; //cos(20 deg);
382
383 #define COS45 0.70710678118654746
384 #define SIN45 COS45
385
386 static float snapquats[39][6] = {
387         /*{q0, q1, q3, q4, view, oposite_direction}*/
388 {COS45, -SIN45, 0.0, 0.0, RV3D_VIEW_FRONT, 0},  //front
389 {0.0, 0.0, -SIN45, -SIN45, RV3D_VIEW_BACK, 0}, //back
390 {1.0, 0.0, 0.0, 0.0, RV3D_VIEW_TOP, 0},       //top
391 {0.0, -1.0, 0.0, 0.0, RV3D_VIEW_BOTTOM, 0},      //bottom
392 {0.5, -0.5, -0.5, -0.5, RV3D_VIEW_LEFT, 0},    //left
393 {0.5, -0.5, 0.5, 0.5, RV3D_VIEW_RIGHT, 0},      //right
394
395         /* some more 45 deg snaps */
396 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0, 0},
397 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0, 0},
398 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0, 0},
399 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0, 0},
400 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0, 0},
401 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0, 0},
402 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0, 0},
403 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0, 0},
404 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0, 0},
405 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0, 0},
406 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0, 0},
407 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0, 0},
408 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0, 0},
409 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0, 0},
410 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0, 0},
411 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0, 0},
412 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0, 0},
413 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0, 0},
414 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0, 0},
415 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0, 0},
416 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0, 0},
417 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0, 0},
418 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0, 0},
419 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0, 0},
420 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0, 0},
421 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0, 0},
422 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0, 0},
423 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0, 0},
424 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0, 0},
425 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0, 0},
426 {-COS45, 0.0, 0.0, SIN45, 0, 0},
427 {COS45, 0.0, 0.0, SIN45, 0, 0},
428 {0.0, 0.0, 0.0, 1.0, 0, 0}
429 };
430
431 enum {
432         VIEW_PASS= 0,
433         VIEW_APPLY,
434         VIEW_CONFIRM
435 };
436
437 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
438 #define VIEW_MODAL_CONFIRM                              1 /* used for all view operations */
439 #define VIEWROT_MODAL_AXIS_SNAP_ENABLE  2
440 #define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3
441
442
443 /* called in transform_ops.c, on each regeneration of keymaps  */
444 void viewrotate_modal_keymap(wmKeyConfig *keyconf)
445 {
446         static EnumPropertyItem modal_items[] = {
447         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Cancel", ""},
448
449         {VIEWROT_MODAL_AXIS_SNAP_ENABLE,        "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""},
450         {VIEWROT_MODAL_AXIS_SNAP_DISABLE,       "AXIS_SNAP_DISABLE", 0, "Enable Axis Snap", ""},
451
452         {0, NULL, 0, NULL, NULL}};
453
454         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Rotate Modal");
455
456         /* this function is called for each spacetype, only needs to add map once */
457         if(keymap) return;
458
459         keymap= WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items);
460
461         /* items for modal map */
462         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
463         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
464
465         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE);
466         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE);
467
468         /* assign map to operators */
469         WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate");
470
471 }
472
473 static void viewrotate_apply(ViewOpsData *vod, int x, int y)
474 {
475         RegionView3D *rv3d= vod->rv3d;
476
477         rv3d->view= 0; /* need to reset everytime because of view snapping */
478
479         if (U.flag & USER_TRACKBALL) {
480                 float phi, si, q1[4], dvec[3], newvec[3];
481
482                 calctrackballvec(&vod->ar->winrct, x, y, newvec);
483
484                 sub_v3_v3v3(dvec, newvec, vod->trackvec);
485
486                 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
487                 si/= (2.0*TRACKBALLSIZE);
488
489                 cross_v3_v3v3(q1+1, vod->trackvec, newvec);
490                 normalize_v3(q1+1);
491
492                 /* Allow for rotation beyond the interval
493                         * [-pi, pi] */
494                 while (si > 1.0)
495                         si -= 2.0;
496
497                 /* This relation is used instead of
498                         * phi = asin(si) so that the angle
499                         * of rotation is linearly proportional
500                         * to the distance that the mouse is
501                         * dragged. */
502                 phi = si * M_PI / 2.0;
503
504                 si= sin(phi);
505                 q1[0]= cos(phi);
506                 q1[1]*= si;
507                 q1[2]*= si;
508                 q1[3]*= si;
509                 mul_qt_qtqt(rv3d->viewquat, q1, vod->oldquat);
510
511                 if (vod->use_dyn_ofs) {
512                         /* compute the post multiplication quat, to rotate the offset correctly */
513                         QUATCOPY(q1, vod->oldquat);
514                         conjugate_qt(q1);
515                         mul_qt_qtqt(q1, q1, rv3d->viewquat);
516
517                         conjugate_qt(q1); /* conj == inv for unit quat */
518                         VECCOPY(rv3d->ofs, vod->ofs);
519                         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
520                         mul_qt_v3(q1, rv3d->ofs);
521                         add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
522                 }
523         }
524         else {
525                 /* New turntable view code by John Aughey */
526                 float si, phi, q1[4];
527                 float m[3][3];
528                 float m_inv[3][3];
529                 float xvec[3] = {1,0,0};
530                 /* Sensitivity will control how fast the viewport rotates.  0.0035 was
531                         obtained experimentally by looking at viewport rotation sensitivities
532                         on other modeling programs. */
533                 /* Perhaps this should be a configurable user parameter. */
534                 const float sensitivity = 0.0035;
535
536                 /* Get the 3x3 matrix and its inverse from the quaternion */
537                 quat_to_mat3( m,rv3d->viewquat);
538                 invert_m3_m3(m_inv,m);
539
540                 /* Determine the direction of the x vector (for rotating up and down) */
541                 /* This can likely be compuated directly from the quaternion. */
542                 mul_m3_v3(m_inv,xvec);
543
544                 /* Perform the up/down rotation */
545                 phi = sensitivity * -(y - vod->oldy);
546                 si = sin(phi);
547                 q1[0] = cos(phi);
548                 q1[1] = si * xvec[0];
549                 q1[2] = si * xvec[1];
550                 q1[3] = si * xvec[2];
551                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
552
553                 if (vod->use_dyn_ofs) {
554                         conjugate_qt(q1); /* conj == inv for unit quat */
555                         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
556                         mul_qt_v3(q1, rv3d->ofs);
557                         add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
558                 }
559
560                 /* Perform the orbital rotation */
561                 phi = sensitivity * vod->reverse * (x - vod->oldx);
562                 q1[0] = cos(phi);
563                 q1[1] = q1[2] = 0.0;
564                 q1[3] = sin(phi);
565                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
566
567                 if (vod->use_dyn_ofs) {
568                         conjugate_qt(q1);
569                         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
570                         mul_qt_v3(q1, rv3d->ofs);
571                         add_v3_v3v3(rv3d->ofs, rv3d->ofs, vod->dyn_ofs);
572                 }
573         }
574
575         /* check for view snap */
576         if (vod->axis_snap){
577                 int i;
578                 float viewmat[3][3];
579
580
581                 quat_to_mat3( viewmat,rv3d->viewquat);
582
583                 for (i = 0 ; i < 39; i++){
584                         float snapmat[3][3];
585                         float view = (int)snapquats[i][4];
586
587                         quat_to_mat3( snapmat,snapquats[i]);
588
589                         if ((dot_v3v3(snapmat[0], viewmat[0]) > thres) &&
590                                 (dot_v3v3(snapmat[1], viewmat[1]) > thres) &&
591                                 (dot_v3v3(snapmat[2], viewmat[2]) > thres)){
592
593                                 QUATCOPY(rv3d->viewquat, snapquats[i]);
594
595                                 rv3d->view = view;
596
597                                 break;
598                         }
599                 }
600         }
601         vod->oldx= x;
602         vod->oldy= y;
603
604         ED_region_tag_redraw(vod->ar);
605 }
606
607 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
608 {
609         ViewOpsData *vod= op->customdata;
610         short event_code= VIEW_PASS;
611
612         /* execute the events */
613         if(event->type==MOUSEMOVE) {
614                 event_code= VIEW_APPLY;
615         }
616         else if(event->type==EVT_MODAL_MAP) {
617                 switch (event->val) {
618                         case VIEW_MODAL_CONFIRM:
619                                 event_code= VIEW_CONFIRM;
620                                 break;
621                         case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
622                                 vod->axis_snap= TRUE;
623                                 event_code= VIEW_APPLY;
624                                 break;
625                         case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
626                                 vod->axis_snap= FALSE;
627                                 event_code= VIEW_APPLY;
628                                 break;
629                 }
630         }
631         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
632                 event_code= VIEW_CONFIRM;
633         }
634
635         if(event_code==VIEW_APPLY) {
636                 viewrotate_apply(vod, event->x, event->y);
637         }
638         else if (event_code==VIEW_CONFIRM) {
639                 request_depth_update(CTX_wm_region_view3d(C));
640                 viewops_data_free(C, op);
641
642                 return OPERATOR_FINISHED;
643         }
644
645         return OPERATOR_RUNNING_MODAL;
646 }
647
648 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
649 {
650         RegionView3D *rv3d= CTX_wm_region_view3d(C);
651         ViewOpsData *vod;
652
653         if(rv3d->viewlock)
654                 return OPERATOR_CANCELLED;
655
656         /* makes op->customdata */
657         viewops_data_create(C, op, event);
658         vod= op->customdata;
659
660         /* switch from camera view when: */
661         if(vod->rv3d->persp != RV3D_PERSP) {
662
663                 if (U.uiflag & USER_AUTOPERSP)
664                         vod->rv3d->persp= RV3D_PERSP;
665                 else if(vod->rv3d->persp==RV3D_CAMOB)
666                         vod->rv3d->persp= RV3D_PERSP;
667                 ED_region_tag_redraw(vod->ar);
668         }
669
670         /* add temp handler */
671         WM_event_add_modal_handler(C, op);
672
673         return OPERATOR_RUNNING_MODAL;
674 }
675
676
677 void VIEW3D_OT_rotate(wmOperatorType *ot)
678 {
679
680         /* identifiers */
681         ot->name= "Rotate view";
682         ot->description = "Rotate the view.";
683         ot->idname= "VIEW3D_OT_rotate";
684
685         /* api callbacks */
686         ot->invoke= viewrotate_invoke;
687         ot->modal= viewrotate_modal;
688         ot->poll= ED_operator_view3d_active;
689
690         /* flags */
691         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
692 }
693
694 /* ************************ viewmove ******************************** */
695
696
697 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
698
699 /* called in transform_ops.c, on each regeneration of keymaps  */
700 void viewmove_modal_keymap(wmKeyConfig *keyconf)
701 {
702         static EnumPropertyItem modal_items[] = {
703         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Confirm", ""},
704
705         {0, NULL, 0, NULL, NULL}};
706
707         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Move Modal");
708
709         /* this function is called for each spacetype, only needs to add map once */
710         if(keymap) return;
711
712         keymap= WM_modalkeymap_add(keyconf, "View3D Move Modal", modal_items);
713
714         /* items for modal map */
715         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
716         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
717
718         /* assign map to operators */
719         WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
720 }
721
722
723 static void viewmove_apply(ViewOpsData *vod, int x, int y)
724 {
725         if(vod->rv3d->persp==RV3D_CAMOB) {
726                 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
727
728                 vod->rv3d->camdx += (vod->oldx - x)/(max);
729                 vod->rv3d->camdy += (vod->oldy - y)/(max);
730                 CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
731                 CLAMP(vod->rv3d->camdy, -1.0f, 1.0f);
732 // XXX          preview3d_event= 0;
733         }
734         else {
735                 float dvec[3];
736
737                 window_to_3d_delta(vod->ar, dvec, x-vod->oldx, y-vod->oldy);
738                 add_v3_v3v3(vod->rv3d->ofs, vod->rv3d->ofs, dvec);
739
740                 if(vod->rv3d->viewlock & RV3D_BOXVIEW)
741                         view3d_boxview_sync(vod->sa, vod->ar);
742         }
743
744         vod->oldx= x;
745         vod->oldy= y;
746
747         ED_region_tag_redraw(vod->ar);
748 }
749
750
751 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
752 {
753
754         ViewOpsData *vod= op->customdata;
755         short event_code= VIEW_PASS;
756
757         /* execute the events */
758         if(event->type==MOUSEMOVE) {
759                 event_code= VIEW_APPLY;
760         }
761         else if(event->type==EVT_MODAL_MAP) {
762                 switch (event->val) {
763                         case VIEW_MODAL_CONFIRM:
764                                 event_code= VIEW_CONFIRM;
765                                 break;
766                 }
767         }
768         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
769                 event_code= VIEW_CONFIRM;
770         }
771
772         if(event_code==VIEW_APPLY) {
773                 viewmove_apply(vod, event->x, event->y);
774         }
775         else if (event_code==VIEW_CONFIRM) {
776                 request_depth_update(CTX_wm_region_view3d(C));
777
778                 viewops_data_free(C, op);
779
780                 return OPERATOR_FINISHED;
781         }
782
783         return OPERATOR_RUNNING_MODAL;
784 }
785
786 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
787 {
788         /* makes op->customdata */
789         viewops_data_create(C, op, event);
790
791         /* add temp handler */
792         WM_event_add_modal_handler(C, op);
793
794         return OPERATOR_RUNNING_MODAL;
795 }
796
797
798 void VIEW3D_OT_move(wmOperatorType *ot)
799 {
800
801         /* identifiers */
802         ot->name= "Move view";
803         ot->description = "Move the view.";
804         ot->idname= "VIEW3D_OT_move";
805
806         /* api callbacks */
807         ot->invoke= viewmove_invoke;
808         ot->modal= viewmove_modal;
809         ot->poll= ED_operator_view3d_active;
810
811         /* flags */
812         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
813 }
814
815 /* ************************ viewzoom ******************************** */
816
817 /* called in transform_ops.c, on each regeneration of keymaps  */
818 void viewzoom_modal_keymap(wmKeyConfig *keyconf)
819 {
820         static EnumPropertyItem modal_items[] = {
821         {VIEW_MODAL_CONFIRM,    "CONFIRM", 0, "Confirm", ""},
822
823         {0, NULL, 0, NULL, NULL}};
824
825         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Zoom Modal");
826
827         /* this function is called for each spacetype, only needs to add map once */
828         if(keymap) return;
829
830         keymap= WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items);
831
832         /* items for modal map */
833         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
834         WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
835
836         /* assign map to operators */
837         WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
838 }
839
840 static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
841 {
842         RegionView3D *rv3d= ar->regiondata;
843
844         if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
845                 float dvec[3];
846                 float tvec[3];
847                 float tpos[3];
848                 float new_dist;
849                 short vb[2], mouseloc[2];
850
851                 mouseloc[0]= mx - ar->winrct.xmin;
852                 mouseloc[1]= my - ar->winrct.ymin;
853
854                 /* find the current window width and height */
855                 vb[0] = ar->winx;
856                 vb[1] = ar->winy;
857
858                 tpos[0] = -rv3d->ofs[0];
859                 tpos[1] = -rv3d->ofs[1];
860                 tpos[2] = -rv3d->ofs[2];
861
862                 /* Project cursor position into 3D space */
863                 initgrabz(rv3d, tpos[0], tpos[1], tpos[2]);
864                 window_to_3d_delta(ar, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
865
866                 /* Calculate view target position for dolly */
867                 tvec[0] = -(tpos[0] + dvec[0]);
868                 tvec[1] = -(tpos[1] + dvec[1]);
869                 tvec[2] = -(tpos[2] + dvec[2]);
870
871                 /* Offset to target position and dolly */
872                 new_dist = rv3d->dist * dfac;
873
874                 VECCOPY(rv3d->ofs, tvec);
875                 rv3d->dist = new_dist;
876
877                 /* Calculate final offset */
878                 dvec[0] = tvec[0] + dvec[0] * dfac;
879                 dvec[1] = tvec[1] + dvec[1] * dfac;
880                 dvec[2] = tvec[2] + dvec[2] * dfac;
881
882                 VECCOPY(rv3d->ofs, dvec);
883         } else {
884                 rv3d->dist *= dfac;
885         }
886 }
887
888
889 static void viewzoom_apply(ViewOpsData *vod, int x, int y)
890 {
891         float zfac=1.0;
892
893         if(U.viewzoom==USER_ZOOM_CONT) {
894                 // oldstyle zoom
895                 zfac = 1.0+(float)(vod->origx - x + vod->origy - y)/1000.0;
896         }
897         else if(U.viewzoom==USER_ZOOM_SCALE) {
898                 int ctr[2], len1, len2;
899                 // method which zooms based on how far you move the mouse
900
901                 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
902                 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
903
904                 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
905                 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
906
907                 zfac = vod->dist0 * ((float)len2/len1) / vod->rv3d->dist;
908         }
909         else {  /* USER_ZOOM_DOLLY */
910                 float len1, len2;
911                 
912                 if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
913                         len1 = (vod->ar->winrct.xmax - x) + 5;
914                         len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
915                 }
916                 else {
917                         len1 = (vod->ar->winrct.ymax - y) + 5;
918                         len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
919                 }
920                 if (U.uiflag & USER_ZOOM_INVERT)
921                         SWAP(float, len1, len2);
922                 
923                 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->rv3d->dist;
924         }
925
926         if(zfac != 1.0 && zfac*vod->rv3d->dist > 0.001*vod->grid &&
927                                 zfac*vod->rv3d->dist < 10.0*vod->far)
928                 view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
929
930
931         if ((U.uiflag & USER_ORBIT_ZBUF) && (U.viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
932                 float upvec[3], mat[3][3];
933
934                 /* Secret apricot feature, translate the view when in continues mode */
935                 upvec[0] = upvec[1] = 0.0f;
936                 upvec[2] = (vod->dist0 - vod->rv3d->dist) * vod->grid;
937                 vod->rv3d->dist = vod->dist0;
938                 copy_m3_m4(mat, vod->rv3d->viewinv);
939                 mul_m3_v3(mat, upvec);
940                 add_v3_v3v3(vod->rv3d->ofs, vod->rv3d->ofs, upvec);
941         } else {
942                 /* these limits were in old code too */
943                 if(vod->rv3d->dist<0.001*vod->grid) vod->rv3d->dist= 0.001*vod->grid;
944                 if(vod->rv3d->dist>10.0*vod->far) vod->rv3d->dist=10.0*vod->far;
945         }
946
947 // XXX  if(vod->rv3d->persp==RV3D_ORTHO || vod->rv3d->persp==RV3D_CAMOB) preview3d_event= 0;
948
949         if(vod->rv3d->viewlock & RV3D_BOXVIEW)
950                 view3d_boxview_sync(vod->sa, vod->ar);
951
952         ED_region_tag_redraw(vod->ar);
953 }
954
955
956 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
957 {
958         ViewOpsData *vod= op->customdata;
959         short event_code= VIEW_PASS;
960
961         /* execute the events */
962         if(event->type==MOUSEMOVE) {
963                 event_code= VIEW_APPLY;
964         }
965         else if(event->type==EVT_MODAL_MAP) {
966                 switch (event->val) {
967                         case VIEW_MODAL_CONFIRM:
968                                 event_code= VIEW_CONFIRM;
969                                 break;
970                 }
971         }
972         else if(event->type==vod->origkey && event->val==KM_RELEASE) {
973                 event_code= VIEW_CONFIRM;
974         }
975
976         if(event_code==VIEW_APPLY) {
977                 viewzoom_apply(vod, event->x, event->y);
978         }
979         else if (event_code==VIEW_CONFIRM) {
980                 request_depth_update(CTX_wm_region_view3d(C));
981                 viewops_data_free(C, op);
982
983                 return OPERATOR_FINISHED;
984         }
985
986         return OPERATOR_RUNNING_MODAL;
987 }
988
989 static int viewzoom_exec(bContext *C, wmOperator *op)
990 {
991         View3D *v3d = CTX_wm_view3d(C);
992         RegionView3D *rv3d= CTX_wm_region_view3d(C);
993         int delta= RNA_int_get(op->ptr, "delta");
994         int mx = RNA_int_get(op->ptr, "mx");
995         int my = RNA_int_get(op->ptr, "my");
996
997         if(delta < 0) {
998                 /* this min and max is also in viewmove() */
999                 if(rv3d->persp==RV3D_CAMOB) {
1000                         rv3d->camzoom-= 10;
1001                         if(rv3d->camzoom<-30) rv3d->camzoom= -30;
1002                 }
1003                 else if(rv3d->dist<10.0*v3d->far) {
1004                         view_zoom_mouseloc(CTX_wm_region(C), 1.2f, mx, my);
1005                 }
1006         }
1007         else {
1008                 if(rv3d->persp==RV3D_CAMOB) {
1009                         rv3d->camzoom+= 10;
1010                         if(rv3d->camzoom>300) rv3d->camzoom= 300;
1011                 }
1012                 else if(rv3d->dist> 0.001*v3d->grid) {
1013                         view_zoom_mouseloc(CTX_wm_region(C), .83333f, mx, my);
1014                 }
1015         }
1016
1017         if(rv3d->viewlock & RV3D_BOXVIEW)
1018                 view3d_boxview_sync(CTX_wm_area(C), CTX_wm_region(C));
1019
1020         request_depth_update(CTX_wm_region_view3d(C));
1021         ED_region_tag_redraw(CTX_wm_region(C));
1022
1023         return OPERATOR_FINISHED;
1024 }
1025
1026 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
1027 {
1028         int delta= RNA_int_get(op->ptr, "delta");
1029         
1030         /* if one or the other zoom position aren't set, set from event */
1031         if (!RNA_property_is_set(op->ptr, "mx") || !RNA_property_is_set(op->ptr, "my"))
1032         {
1033                 RNA_int_set(op->ptr, "mx", event->x);
1034                 RNA_int_set(op->ptr, "my", event->y);
1035         }
1036
1037         if(delta) {
1038                 viewzoom_exec(C, op);
1039         }
1040         else {
1041                 /* makes op->customdata */
1042                 viewops_data_create(C, op, event);
1043
1044                 /* add temp handler */
1045                 WM_event_add_modal_handler(C, op);
1046
1047                 return OPERATOR_RUNNING_MODAL;
1048         }
1049         return OPERATOR_FINISHED;
1050 }
1051
1052
1053 void VIEW3D_OT_zoom(wmOperatorType *ot)
1054 {
1055         /* identifiers */
1056         ot->name= "Zoom view";
1057         ot->description = "Zoom in/out in the view.";
1058         ot->idname= "VIEW3D_OT_zoom";
1059
1060         /* api callbacks */
1061         ot->invoke= viewzoom_invoke;
1062         ot->exec= viewzoom_exec;
1063         ot->modal= viewzoom_modal;
1064         ot->poll= ED_operator_view3d_active;
1065
1066         /* flags */
1067         ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1068
1069         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1070         RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
1071         RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
1072 }
1073
1074 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1075 {
1076         ARegion *ar= CTX_wm_region(C);
1077         View3D *v3d = CTX_wm_view3d(C);
1078         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1079         Scene *scene= CTX_data_scene(C);
1080         Base *base;
1081         float *curs;
1082
1083         int center= RNA_boolean_get(op->ptr, "center");
1084
1085         float size, min[3], max[3], afm[3];
1086         int ok= 1, onedone=0;
1087
1088         if(center) {
1089                 min[0]= min[1]= min[2]= 0.0f;
1090                 max[0]= max[1]= max[2]= 0.0f;
1091
1092                 /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
1093                 curs= give_cursor(scene, v3d);
1094                 curs[0]= curs[1]= curs[2]= 0.0;
1095         }
1096         else {
1097                 INIT_MINMAX(min, max);
1098         }
1099
1100         for(base= scene->base.first; base; base= base->next) {
1101                 if(base->lay & v3d->lay) {
1102                         onedone= 1;
1103                         minmax_object(base->object, min, max);
1104                 }
1105         }
1106         if(!onedone) return OPERATOR_FINISHED; /* TODO - should this be cancel? */
1107
1108         afm[0]= (max[0]-min[0]);
1109         afm[1]= (max[1]-min[1]);
1110         afm[2]= (max[2]-min[2]);
1111         size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
1112         if(size==0.0) ok= 0;
1113
1114         if(ok) {
1115                 float new_dist;
1116                 float new_ofs[3];
1117
1118                 new_dist = size;
1119                 new_ofs[0]= -(min[0]+max[0])/2.0f;
1120                 new_ofs[1]= -(min[1]+max[1])/2.0f;
1121                 new_ofs[2]= -(min[2]+max[2])/2.0f;
1122
1123                 // correction for window aspect ratio
1124                 if(ar->winy>2 && ar->winx>2) {
1125                         size= (float)ar->winx/(float)ar->winy;
1126                         if(size<1.0) size= 1.0f/size;
1127                         new_dist*= size;
1128                 }
1129
1130                 if (rv3d->persp==RV3D_CAMOB) {
1131                         rv3d->persp= RV3D_PERSP;
1132                         smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL);
1133                 }
1134         else {
1135             smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1136         }
1137         }
1138 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1139
1140         if(rv3d->viewlock & RV3D_BOXVIEW)
1141                 view3d_boxview_copy(CTX_wm_area(C), ar);
1142
1143         return OPERATOR_FINISHED;
1144 }
1145
1146 void VIEW3D_OT_view_all(wmOperatorType *ot)
1147 {
1148         /* identifiers */
1149         ot->name= "View All";
1150         ot->description = "View all objects in scene.";
1151         ot->idname= "VIEW3D_OT_view_all";
1152
1153         /* api callbacks */
1154         ot->exec= viewhome_exec;
1155         ot->poll= ED_operator_view3d_active;
1156
1157         /* flags */
1158         ot->flag= 0;
1159
1160         RNA_def_boolean(ot->srna, "center", 0, "Center", "");
1161 }
1162
1163 static int viewcenter_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
1164 {
1165         ARegion *ar= CTX_wm_region(C);
1166         View3D *v3d = CTX_wm_view3d(C);
1167         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1168         Scene *scene= CTX_data_scene(C);
1169         Object *ob= OBACT;
1170         Object *obedit= CTX_data_edit_object(C);
1171         float size, min[3], max[3], afm[3];
1172         int ok=0;
1173
1174         /* SMOOTHVIEW */
1175         float new_ofs[3];
1176         float new_dist;
1177
1178         INIT_MINMAX(min, max);
1179
1180         if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
1181                 /* hardcoded exception, we look for the one selected armature */
1182                 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1183                 Base *base;
1184                 for(base=scene->base.first; base; base= base->next) {
1185                         if(TESTBASELIB(v3d, base)) {
1186                                 if(base->object->type==OB_ARMATURE)
1187                                         if(base->object->mode & OB_MODE_POSE)
1188                                                 break;
1189                         }
1190                 }
1191                 if(base)
1192                         ob= base->object;
1193         }
1194
1195
1196         if(obedit) {
1197                 ok = minmax_verts(obedit, min, max);    /* only selected */
1198         }
1199         else if(ob && (ob->mode & OB_MODE_POSE)) {
1200                 if(ob->pose) {
1201                         bArmature *arm= ob->data;
1202                         bPoseChannel *pchan;
1203                         float vec[3];
1204
1205                         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1206                                 if(pchan->bone->flag & BONE_SELECTED) {
1207                                         if(pchan->bone->layer & arm->layer) {
1208                                                 ok= 1;
1209                                                 VECCOPY(vec, pchan->pose_head);
1210                                                 mul_m4_v3(ob->obmat, vec);
1211                                                 DO_MINMAX(vec, min, max);
1212                                                 VECCOPY(vec, pchan->pose_tail);
1213                                                 mul_m4_v3(ob->obmat, vec);
1214                                                 DO_MINMAX(vec, min, max);
1215                                         }
1216                                 }
1217                         }
1218                 }
1219         }
1220         else if (paint_facesel_test(ob)) {
1221 // XXX          ok= minmax_tface(min, max);
1222         }
1223         else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1224                 ok= PE_minmax(scene, min, max);
1225         }
1226         else {
1227                 Base *base= FIRSTBASE;
1228                 while(base) {
1229                         if(TESTBASE(v3d, base))  {
1230                                 minmax_object(base->object, min, max);
1231                                 /* account for duplis */
1232                                 minmax_object_duplis(scene, base->object, min, max);
1233
1234                                 ok= 1;
1235                         }
1236                         base= base->next;
1237                 }
1238         }
1239
1240         if(ok==0) return OPERATOR_FINISHED;
1241
1242         afm[0]= (max[0]-min[0]);
1243         afm[1]= (max[1]-min[1]);
1244         afm[2]= (max[2]-min[2]);
1245         size= MAX3(afm[0], afm[1], afm[2]);
1246         /* perspective should be a bit farther away to look nice */
1247         if(rv3d->persp==RV3D_ORTHO)
1248                 size*= 0.7;
1249
1250         if(size <= v3d->near*1.5f) size= v3d->near*1.5f;
1251
1252         new_ofs[0]= -(min[0]+max[0])/2.0f;
1253         new_ofs[1]= -(min[1]+max[1])/2.0f;
1254         new_ofs[2]= -(min[2]+max[2])/2.0f;
1255
1256         new_dist = size;
1257
1258         /* correction for window aspect ratio */
1259         if(ar->winy>2 && ar->winx>2) {
1260                 size= (float)ar->winx/(float)ar->winy;
1261                 if(size<1.0f) size= 1.0f/size;
1262                 new_dist*= size;
1263         }
1264
1265         if (rv3d->persp==RV3D_CAMOB) {
1266                 rv3d->persp= RV3D_PERSP;
1267                 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1268         }
1269         else {
1270                 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1271         }
1272
1273 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1274         if(rv3d->viewlock & RV3D_BOXVIEW)
1275                 view3d_boxview_copy(CTX_wm_area(C), ar);
1276
1277         return OPERATOR_FINISHED;
1278 }
1279
1280 void VIEW3D_OT_view_center(wmOperatorType *ot)
1281 {
1282
1283         /* identifiers */
1284         ot->name= "View Selected";
1285         ot->description = "Move the view to the selection center.";
1286         ot->idname= "VIEW3D_OT_view_center";
1287
1288         /* api callbacks */
1289         ot->exec= viewcenter_exec;
1290         ot->poll= ED_operator_view3d_active;
1291
1292         /* flags */
1293         ot->flag= 0;
1294 }
1295
1296 static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
1297 {
1298         View3D *v3d = CTX_wm_view3d(C);
1299         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1300         Scene *scene= CTX_data_scene(C);
1301         
1302         if (rv3d) {
1303                 if (rv3d->persp==RV3D_CAMOB) {
1304                         /* center the camera offset */
1305                         rv3d->camdx= rv3d->camdy= 0.0;
1306                 }
1307                 else {
1308                         /* non camera center */
1309                         float *curs= give_cursor(scene, v3d);
1310                         float new_ofs[3];
1311                         
1312                         new_ofs[0]= -curs[0];
1313                         new_ofs[1]= -curs[1];
1314                         new_ofs[2]= -curs[2];
1315                         
1316                         smooth_view(C, NULL, NULL, new_ofs, NULL, NULL, NULL);
1317                 }
1318                 
1319                 if (rv3d->viewlock & RV3D_BOXVIEW)
1320                         view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
1321         }
1322         
1323         return OPERATOR_FINISHED;
1324 }
1325
1326 void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
1327 {
1328         /* identifiers */
1329         ot->name= "Center View to Cursor";
1330         ot->description= "Centers the view so that the cursor is in the middle of the view.";
1331         ot->idname= "VIEW3D_OT_view_center_cursor";
1332         
1333         /* api callbacks */
1334         ot->exec= viewcenter_cursor_exec;
1335         ot->poll= ED_operator_view3d_active;
1336         
1337         /* flags */
1338         ot->flag= 0;
1339 }
1340
1341 /* ********************* Set render border operator ****************** */
1342
1343 static int render_border_exec(bContext *C, wmOperator *op)
1344 {
1345         View3D *v3d = CTX_wm_view3d(C);
1346         ARegion *ar= CTX_wm_region(C);
1347         Scene *scene= CTX_data_scene(C);
1348
1349         rcti rect;
1350         rctf vb;
1351
1352         /* get border select values using rna */
1353         rect.xmin= RNA_int_get(op->ptr, "xmin");
1354         rect.ymin= RNA_int_get(op->ptr, "ymin");
1355         rect.xmax= RNA_int_get(op->ptr, "xmax");
1356         rect.ymax= RNA_int_get(op->ptr, "ymax");
1357
1358         /* calculate range */
1359         calc_viewborder(scene, ar, v3d, &vb);
1360
1361         scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1362         scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1363         scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1364         scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1365
1366         /* actually set border */
1367         CLAMP(scene->r.border.xmin, 0.0, 1.0);
1368         CLAMP(scene->r.border.ymin, 0.0, 1.0);
1369         CLAMP(scene->r.border.xmax, 0.0, 1.0);
1370         CLAMP(scene->r.border.ymax, 0.0, 1.0);
1371
1372         /* drawing a border surrounding the entire camera view switches off border rendering
1373          * or the border covers no pixels */
1374         if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1375                 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1376            (scene->r.border.xmin == scene->r.border.xmax ||
1377                 scene->r.border.ymin == scene->r.border.ymax ))
1378         {
1379                 scene->r.mode &= ~R_BORDER;
1380         } else {
1381                 scene->r.mode |= R_BORDER;
1382         }
1383
1384         return OPERATOR_FINISHED;
1385
1386 }
1387
1388 static int view3d_render_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1389 {
1390         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1391
1392         /* if not in camera view do not exec the operator*/
1393         if (rv3d->persp == RV3D_CAMOB) return WM_border_select_invoke(C, op, event);
1394         else return OPERATOR_PASS_THROUGH;
1395 }
1396
1397 void VIEW3D_OT_render_border(wmOperatorType *ot)
1398 {
1399         /* identifiers */
1400         ot->name= "Set Render Border";
1401         ot->description = "Set the boundries of the border render and enables border render .";
1402         ot->idname= "VIEW3D_OT_render_border";
1403
1404         /* api callbacks */
1405         ot->invoke= view3d_render_border_invoke;
1406         ot->exec= render_border_exec;
1407         ot->modal= WM_border_select_modal;
1408
1409         ot->poll= ED_operator_view3d_active;
1410
1411         /* flags */
1412         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1413
1414         /* rna */
1415         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1416         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1417         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1418         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1419
1420 }
1421 /* ********************* Border Zoom operator ****************** */
1422
1423 static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
1424 {
1425         ARegion *ar= CTX_wm_region(C);
1426         View3D *v3d = CTX_wm_view3d(C);
1427         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1428         Scene *scene= CTX_data_scene(C);
1429
1430         /* Zooms in on a border drawn by the user */
1431         rcti rect;
1432         float dvec[3], vb[2], xscale, yscale, scale;
1433
1434         /* SMOOTHVIEW */
1435         float new_dist;
1436         float new_ofs[3];
1437
1438         /* ZBuffer depth vars */
1439         bglMats mats;
1440         float depth, depth_close= MAXFLOAT;
1441         int had_depth = 0;
1442         double cent[2],  p[3];
1443         int xs, ys;
1444
1445         /* note; otherwise opengl won't work */
1446         view3d_operator_needs_opengl(C);
1447
1448         /* get border select values using rna */
1449         rect.xmin= RNA_int_get(op->ptr, "xmin");
1450         rect.ymin= RNA_int_get(op->ptr, "ymin");
1451         rect.xmax= RNA_int_get(op->ptr, "xmax");
1452         rect.ymax= RNA_int_get(op->ptr, "ymax");
1453
1454         /* Get Z Depths, needed for perspective, nice for ortho */
1455         bgl_get_mats(&mats);
1456         draw_depth(scene, ar, v3d, NULL);
1457
1458         /* force updating */
1459         if (rv3d->depths) {
1460                 had_depth = 1;
1461                 rv3d->depths->damaged = 1;
1462         }
1463
1464         view3d_update_depths(ar, v3d);
1465
1466         /* Constrain rect to depth bounds */
1467         if (rect.xmin < 0) rect.xmin = 0;
1468         if (rect.ymin < 0) rect.ymin = 0;
1469         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1470         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1471
1472         /* Find the closest Z pixel */
1473         for (xs=rect.xmin; xs < rect.xmax; xs++) {
1474                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1475                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1476                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1477                                 if (depth_close > depth) {
1478                                         depth_close = depth;
1479                                 }
1480                         }
1481                 }
1482         }
1483
1484         if (had_depth==0) {
1485                 MEM_freeN(rv3d->depths->depths);
1486                 rv3d->depths->depths = NULL;
1487         }
1488         rv3d->depths->damaged = 1;
1489
1490         cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1491         cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1492
1493         if (rv3d->persp==RV3D_PERSP) {
1494                 double p_corner[3];
1495
1496                 /* no depths to use, we cant do anything! */
1497                 if (depth_close==MAXFLOAT){
1498                         BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1499                         return OPERATOR_CANCELLED;
1500                 }
1501                 /* convert border to 3d coordinates */
1502                 if ((   !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1503                         (       !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])))
1504                         return OPERATOR_CANCELLED;
1505
1506                 dvec[0] = p[0]-p_corner[0];
1507                 dvec[1] = p[1]-p_corner[1];
1508                 dvec[2] = p[2]-p_corner[2];
1509
1510                 new_dist = len_v3(dvec);
1511                 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1512
1513                 new_ofs[0] = -p[0];
1514                 new_ofs[1] = -p[1];
1515                 new_ofs[2] = -p[2];
1516
1517         } else { /* othographic */
1518                 /* find the current window width and height */
1519                 vb[0] = ar->winx;
1520                 vb[1] = ar->winy;
1521
1522                 new_dist = rv3d->dist;
1523
1524                 /* convert the drawn rectangle into 3d space */
1525                 if (depth_close!=MAXFLOAT && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1526                         new_ofs[0] = -p[0];
1527                         new_ofs[1] = -p[1];
1528                         new_ofs[2] = -p[2];
1529                 } else {
1530                         /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1531                         new_ofs[0] = rv3d->ofs[0];
1532                         new_ofs[1] = rv3d->ofs[1];
1533                         new_ofs[2] = rv3d->ofs[2];
1534
1535                         initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1536
1537                         window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1538                         /* center the view to the center of the rectangle */
1539                         sub_v3_v3v3(new_ofs, new_ofs, dvec);
1540                 }
1541
1542                 /* work out the ratios, so that everything selected fits when we zoom */
1543                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1544                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1545                 scale = (xscale >= yscale)?xscale:yscale;
1546
1547                 /* zoom in as required, or as far as we can go */
1548                 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1549         }
1550
1551         smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1552
1553         if(rv3d->viewlock & RV3D_BOXVIEW)
1554                 view3d_boxview_sync(CTX_wm_area(C), ar);
1555
1556         return OPERATOR_FINISHED;
1557 }
1558
1559 static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1560 {
1561         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1562
1563         /* if in camera view do not exec the operator so we do not conflict with set render border*/
1564         if (rv3d->persp != RV3D_CAMOB)
1565                 return WM_border_select_invoke(C, op, event);
1566         else
1567                 return OPERATOR_PASS_THROUGH;
1568 }
1569
1570 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1571 {
1572
1573         /* identifiers */
1574         ot->name= "Border Zoom";
1575         ot->description = "Zoom in the view to the nearest object contained in the border.";
1576         ot->idname= "VIEW3D_OT_zoom_border";
1577
1578         /* api callbacks */
1579         ot->invoke= view3d_zoom_border_invoke;
1580         ot->exec= view3d_zoom_border_exec;
1581         ot->modal= WM_border_select_modal;
1582
1583         ot->poll= ED_operator_view3d_active;
1584
1585         /* flags */
1586         ot->flag= 0;
1587
1588         /* rna */
1589         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1590         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1591         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1592         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1593
1594 }
1595 /* ********************* Changing view operator ****************** */
1596
1597 static EnumPropertyItem prop_view_items[] = {
1598         {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1599         {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1600         {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1601         {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1602         {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1603         {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1604         {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1605         {0, NULL, 0, NULL, NULL}};
1606
1607
1608 /* would like to make this a generic function - outside of transform */
1609
1610 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo, int align_active)
1611 {
1612         View3D *v3d = CTX_wm_view3d(C);
1613         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1614         float new_quat[4];
1615
1616         new_quat[0]= q1; new_quat[1]= q2;
1617         new_quat[2]= q3; new_quat[3]= q4;
1618
1619         if(align_active) {
1620                 /* align to active object */
1621                 Object *obact= CTX_data_active_object(C);
1622                 if (obact==NULL) {
1623                         /* no active object, ignore this option */
1624                         align_active= FALSE;
1625                 }
1626                 else {
1627                         float obact_quat[4];
1628                         float twmat[3][3];
1629
1630                         /* same as transform manipulator when normal is set */
1631                         ED_getTransformOrientationMatrix(C, twmat, TRUE);
1632
1633                         mat3_to_quat( obact_quat,twmat);
1634                         invert_qt(obact_quat);
1635                         mul_qt_qtqt(new_quat, new_quat, obact_quat);
1636
1637                         rv3d->view= view= 0;
1638                 }
1639         }
1640
1641         if(align_active==FALSE) {
1642                 /* normal operation */
1643                 if(rv3d->viewlock) {
1644                         /* only pass on if */
1645                         if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
1646                         else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
1647                         else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
1648                         else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
1649                         else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
1650                         else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
1651                         else return;
1652                 }
1653
1654                 rv3d->view= view;
1655         }
1656
1657         if(rv3d->viewlock) {
1658                 ED_region_tag_redraw(CTX_wm_region(C));
1659                 return;
1660         }
1661
1662         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1663
1664                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1665                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1666
1667                 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1668         }
1669         else {
1670
1671                 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1672                 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1673
1674                 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1675         }
1676
1677 }
1678
1679 static int viewnumpad_exec(bContext *C, wmOperator *op)
1680 {
1681         View3D *v3d = CTX_wm_view3d(C);
1682         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1683         Scene *scene= CTX_data_scene(C);
1684         static int perspo=RV3D_PERSP;
1685         int viewnum, align_active, nextperspo;
1686
1687         viewnum = RNA_enum_get(op->ptr, "type");
1688         align_active = RNA_boolean_get(op->ptr, "align_active");
1689
1690
1691         /* Use this to test if we started out with a camera */
1692
1693         if (rv3d->persp == RV3D_CAMOB) {
1694                 nextperspo= rv3d->lpersp;
1695         } else {
1696                 nextperspo= perspo;
1697         }
1698
1699         switch (viewnum) {
1700                 case RV3D_VIEW_BOTTOM :
1701                         axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1702                         break;
1703
1704                 case RV3D_VIEW_BACK:
1705                         axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, nextperspo, align_active);
1706                         break;
1707
1708                 case RV3D_VIEW_LEFT:
1709                         axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, nextperspo, align_active);
1710                         break;
1711
1712                 case RV3D_VIEW_TOP:
1713                         axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1714                         break;
1715
1716                 case RV3D_VIEW_FRONT:
1717                         axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, nextperspo, align_active);
1718                         break;
1719
1720                 case RV3D_VIEW_RIGHT:
1721                         axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, nextperspo, align_active);
1722                         break;
1723
1724                 case RV3D_VIEW_CAMERA:
1725                         if(rv3d->viewlock==0) {
1726                                 /* lastview -  */
1727
1728                                 if(rv3d->persp != RV3D_CAMOB) {
1729                                         /* store settings of current view before allowing overwriting with camera view */
1730                                         QUATCOPY(rv3d->lviewquat, rv3d->viewquat);
1731                                         rv3d->lview= rv3d->view;
1732                                         rv3d->lpersp= rv3d->persp;
1733
1734         #if 0
1735                                         if(G.qual==LR_ALTKEY) {
1736                                                 if(oldcamera && is_an_active_object(oldcamera)) {
1737                                                         v3d->camera= oldcamera;
1738                                                 }
1739                                                 handle_view3d_lock();
1740                                         }
1741         #endif
1742
1743                                         if(BASACT) {
1744                                                 /* check both G.vd as G.scene cameras */
1745                                                 if((v3d->camera==NULL || scene->camera==NULL) && OBACT->type==OB_CAMERA) {
1746                                                         v3d->camera= OBACT;
1747                                                         /*handle_view3d_lock();*/
1748                                                 }
1749                                         }
1750
1751                                         if(v3d->camera==NULL) {
1752                                                 v3d->camera= scene_find_camera(scene);
1753                                                 /*handle_view3d_lock();*/
1754                                         }
1755                                         rv3d->persp= RV3D_CAMOB;
1756                                         smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
1757
1758                                 }
1759                                 else{
1760                                         /* return to settings of last view */
1761                                         /* does smooth_view too */
1762                                         axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
1763                                 }
1764                         }
1765                         break;
1766
1767                 default :
1768                         break;
1769         }
1770
1771         if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
1772
1773         return OPERATOR_FINISHED;
1774 }
1775 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
1776 {
1777         /* identifiers */
1778         ot->name= "View numpad";
1779         ot->description = "Set the view.";
1780         ot->idname= "VIEW3D_OT_viewnumpad";
1781
1782         /* api callbacks */
1783         ot->exec= viewnumpad_exec;
1784         ot->poll= ED_operator_view3d_active;
1785
1786         /* flags */
1787         ot->flag= 0;
1788
1789         RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
1790         RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
1791 }
1792
1793 static EnumPropertyItem prop_view_orbit_items[] = {
1794         {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
1795         {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
1796         {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
1797         {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
1798         {0, NULL, 0, NULL, NULL}};
1799
1800 static int vieworbit_exec(bContext *C, wmOperator *op)
1801 {
1802         ARegion *ar= CTX_wm_region(C);
1803         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1804         float phi, si, q1[4];
1805         int orbitdir;
1806
1807         orbitdir = RNA_enum_get(op->ptr, "type");
1808
1809         if(rv3d->viewlock==0) {
1810
1811                 if(rv3d->persp != RV3D_CAMOB) {
1812                         if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
1813                                 /* z-axis */
1814                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1815                                 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
1816                                 si= (float)sin(phi);
1817                                 q1[0]= (float)cos(phi);
1818                                 q1[1]= q1[2]= 0.0;
1819                                 q1[3]= si;
1820                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
1821                                 rv3d->view= 0;
1822                         }
1823                         if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
1824                                 /* horizontal axis */
1825                                 VECCOPY(q1+1, rv3d->viewinv[0]);
1826
1827                                 normalize_v3(q1+1);
1828                                 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
1829                                 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
1830                                 si= (float)sin(phi);
1831                                 q1[0]= (float)cos(phi);
1832                                 q1[1]*= si;
1833                                 q1[2]*= si;
1834                                 q1[3]*= si;
1835                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
1836                                 rv3d->view= 0;
1837                         }
1838                         ED_region_tag_redraw(ar);
1839                 }
1840         }
1841
1842         return OPERATOR_FINISHED;
1843 }
1844
1845 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
1846 {
1847         /* identifiers */
1848         ot->name= "View Orbit";
1849         ot->description = "Orbit the view.";
1850         ot->idname= "VIEW3D_OT_view_orbit";
1851
1852         /* api callbacks */
1853         ot->exec= vieworbit_exec;
1854         ot->poll= ED_operator_view3d_active;
1855
1856         /* flags */
1857         ot->flag= 0;
1858         RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
1859 }
1860
1861 static EnumPropertyItem prop_view_pan_items[] = {
1862         {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
1863         {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
1864         {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
1865         {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
1866         {0, NULL, 0, NULL, NULL}};
1867
1868 static int viewpan_exec(bContext *C, wmOperator *op)
1869 {
1870         ARegion *ar= CTX_wm_region(C);
1871         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1872         float vec[3];
1873         int pandir;
1874
1875         pandir = RNA_enum_get(op->ptr, "type");
1876
1877         initgrabz(rv3d, 0.0, 0.0, 0.0);
1878
1879         if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
1880         else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
1881         else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
1882         else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
1883         rv3d->ofs[0]+= vec[0];
1884         rv3d->ofs[1]+= vec[1];
1885         rv3d->ofs[2]+= vec[2];
1886
1887         if(rv3d->viewlock & RV3D_BOXVIEW)
1888                 view3d_boxview_sync(CTX_wm_area(C), ar);
1889
1890         ED_region_tag_redraw(ar);
1891
1892         return OPERATOR_FINISHED;
1893 }
1894
1895 void VIEW3D_OT_view_pan(wmOperatorType *ot)
1896 {
1897         /* identifiers */
1898         ot->name= "View Pan";
1899         ot->description = "Pan the view.";
1900         ot->idname= "VIEW3D_OT_view_pan";
1901
1902         /* api callbacks */
1903         ot->exec= viewpan_exec;
1904         ot->poll= ED_operator_view3d_active;
1905
1906         /* flags */
1907         ot->flag= 0;
1908         RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
1909 }
1910
1911 static int viewpersportho_exec(bContext *C, wmOperator *op)
1912 {
1913         ARegion *ar= CTX_wm_region(C);
1914         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1915
1916         if(rv3d->viewlock==0) {
1917                 if(rv3d->persp!=RV3D_ORTHO)
1918                         rv3d->persp=RV3D_ORTHO;
1919                 else rv3d->persp=RV3D_PERSP;
1920                 ED_region_tag_redraw(ar);
1921         }
1922
1923         return OPERATOR_FINISHED;
1924
1925 }
1926
1927 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
1928 {
1929         /* identifiers */
1930         ot->name= "View Persp/Ortho";
1931         ot->description = "Switch the current view from perspective/orthographic.";
1932         ot->idname= "VIEW3D_OT_view_persportho";
1933
1934         /* api callbacks */
1935         ot->exec= viewpersportho_exec;
1936         ot->poll= ED_operator_view3d_active;
1937
1938         /* flags */
1939         ot->flag= 0;
1940 }
1941
1942
1943 /* ********************* set clipping operator ****************** */
1944
1945 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
1946 {
1947         int val;
1948
1949         for(val=0; val<4; val++) {
1950
1951                 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
1952
1953                 clip[val][3]=
1954                         - clip[val][0]*clipbb->vec[val][0]
1955                         - clip[val][1]*clipbb->vec[val][1]
1956                         - clip[val][2]*clipbb->vec[val][2];
1957         }
1958 }
1959
1960 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
1961 {
1962         BoundBox clipbb_local;
1963         float imat[4][4];
1964         int i;
1965
1966         invert_m4_m4(imat, mat);
1967
1968         for(i=0; i<8; i++) {
1969                 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
1970         }
1971
1972         calc_clipping_plane(clip_local, &clipbb_local);
1973 }
1974
1975 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
1976 {
1977         if(rv3d->rflag & RV3D_CLIPPING)
1978                 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
1979 }
1980
1981 static int view3d_clipping_exec(bContext *C, wmOperator *op)
1982 {
1983         RegionView3D *rv3d= CTX_wm_region_view3d(C);
1984         ViewContext vc;
1985         bglMats mats;
1986         rcti rect;
1987
1988         rect.xmin= RNA_int_get(op->ptr, "xmin");
1989         rect.ymin= RNA_int_get(op->ptr, "ymin");
1990         rect.xmax= RNA_int_get(op->ptr, "xmax");
1991         rect.ymax= RNA_int_get(op->ptr, "ymax");
1992
1993         rv3d->rflag |= RV3D_CLIPPING;
1994         rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
1995
1996         /* note; otherwise opengl won't work */
1997         view3d_operator_needs_opengl(C);
1998
1999         view3d_set_viewcontext(C, &vc);
2000         view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
2001         view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
2002
2003         return OPERATOR_FINISHED;
2004 }
2005
2006 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
2007 {
2008         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2009         ARegion *ar= CTX_wm_region(C);
2010
2011         if(rv3d->rflag & RV3D_CLIPPING) {
2012                 rv3d->rflag &= ~RV3D_CLIPPING;
2013                 ED_region_tag_redraw(ar);
2014                 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
2015                 rv3d->clipbb= NULL;
2016                 return OPERATOR_FINISHED;
2017         }
2018         else {
2019                 return WM_border_select_invoke(C, op, event);
2020         }
2021 }
2022
2023 /* toggles */
2024 void VIEW3D_OT_clip_border(wmOperatorType *ot)
2025 {
2026
2027         /* identifiers */
2028         ot->name= "Clipping Border";
2029         ot->description = "Set the view clipping border.";
2030         ot->idname= "VIEW3D_OT_clip_border";
2031
2032         /* api callbacks */
2033         ot->invoke= view3d_clipping_invoke;
2034         ot->exec= view3d_clipping_exec;
2035         ot->modal= WM_border_select_modal;
2036
2037         ot->poll= ED_operator_view3d_active;
2038
2039         /* flags */
2040         ot->flag= 0;
2041
2042         /* rna */
2043         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2044         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2045         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2046         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2047 }
2048
2049 /* ***************** 3d cursor cursor op ******************* */
2050
2051 /* mx my in region coords */
2052 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
2053 {
2054         Scene *scene= CTX_data_scene(C);
2055         ARegion *ar= CTX_wm_region(C);
2056         View3D *v3d = CTX_wm_view3d(C);
2057         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2058         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2059         short mx, my, mval[2];
2060 //      short ctrl= 0; // XXX
2061
2062         fp= give_cursor(scene, v3d);
2063
2064 //      if(obedit && ctrl) lr_click= 1;
2065         VECCOPY(oldcurs, fp);
2066
2067         mx= event->x - ar->winrct.xmin;
2068         my= event->y - ar->winrct.ymin;
2069         project_short_noclip(ar, fp, mval);
2070
2071         initgrabz(rv3d, fp[0], fp[1], fp[2]);
2072
2073         if(mval[0]!=IS_CLIPPED) {
2074
2075                 window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2076                 sub_v3_v3v3(fp, fp, dvec);
2077         }
2078         else {
2079
2080                 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2081                 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2082
2083                 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2084                 fz= fz/rv3d->zfac;
2085
2086                 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2087                 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2088                 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2089         }
2090
2091         if(v3d && v3d->localvd)
2092                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2093         else
2094                 WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene);
2095
2096         return OPERATOR_FINISHED;
2097 }
2098
2099 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2100 {
2101
2102         /* identifiers */
2103         ot->name= "Set 3D Cursor";
2104         ot->description = "Set the location of the 3D cursor.";
2105         ot->idname= "VIEW3D_OT_cursor3d";
2106
2107         /* api callbacks */
2108         ot->invoke= set_3dcursor_invoke;
2109
2110         ot->poll= ED_operator_view3d_active;
2111     
2112         /* flags */
2113         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2114     
2115         /* rna later */
2116
2117 }
2118
2119 /* ***************** manipulator op ******************* */
2120
2121
2122 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2123 {
2124         View3D *v3d = CTX_wm_view3d(C);
2125
2126         if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2127         if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2128
2129         /* only no modifier or shift */
2130         if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2131
2132         /* note; otherwise opengl won't work */
2133         view3d_operator_needs_opengl(C);
2134
2135         if(0==BIF_do_manipulator(C, event, op))
2136                 return OPERATOR_PASS_THROUGH;
2137
2138         return OPERATOR_FINISHED;
2139 }
2140
2141 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2142 {
2143
2144         /* identifiers */
2145         ot->name= "3D Manipulator";
2146         ot->description = "Manipulate selected item by axis.";
2147         ot->idname= "VIEW3D_OT_manipulator";
2148
2149         /* api callbacks */
2150         ot->invoke= manipulator_invoke;
2151
2152         ot->poll= ED_operator_view3d_active;
2153
2154         /* rna later */
2155         RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
2156 }
2157
2158
2159
2160 /* ************************* below the line! *********************** */
2161
2162
2163 /* XXX todo Zooms in on a border drawn by the user */
2164 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2165 {
2166         RegionView3D *rv3d= ar->regiondata;
2167         bglMats mats; /* ZBuffer depth vars */
2168         rcti rect;
2169         float depth, depth_close= MAXFLOAT;
2170         int had_depth = 0;
2171         double cent[2],  p[3];
2172         int xs, ys;
2173
2174         rect.xmax = mval[0] + 4;
2175         rect.ymax = mval[1] + 4;
2176
2177         rect.xmin = mval[0] - 4;
2178         rect.ymin = mval[1] - 4;
2179
2180         /* Get Z Depths, needed for perspective, nice for ortho */
2181         bgl_get_mats(&mats);
2182         draw_depth(scene, ar, v3d, NULL);
2183
2184         /* force updating */
2185         if (rv3d->depths) {
2186                 had_depth = 1;
2187                 rv3d->depths->damaged = 1;
2188         }
2189
2190         view3d_update_depths(ar, v3d);
2191
2192         /* Constrain rect to depth bounds */
2193         if (rect.xmin < 0) rect.xmin = 0;
2194         if (rect.ymin < 0) rect.ymin = 0;
2195         if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
2196         if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
2197
2198         /* Find the closest Z pixel */
2199         for (xs=rect.xmin; xs < rect.xmax; xs++) {
2200                 for (ys=rect.ymin; ys < rect.ymax; ys++) {
2201                         depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
2202                         if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
2203                                 if (depth_close > depth) {
2204                                         depth_close = depth;
2205                                 }
2206                         }
2207                 }
2208         }
2209
2210         if (depth_close==MAXFLOAT)
2211                 return 0;
2212
2213         if (had_depth==0) {
2214                 MEM_freeN(rv3d->depths->depths);
2215                 rv3d->depths->depths = NULL;
2216         }
2217         rv3d->depths->damaged = 1;
2218
2219         cent[0] = (double)mval[0];
2220         cent[1] = (double)mval[1];
2221
2222         if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2223                 return 0;
2224
2225         mouse_worldloc[0] = (float)p[0];
2226         mouse_worldloc[1] = (float)p[1];
2227         mouse_worldloc[2] = (float)p[2];
2228         return 1;
2229 }
2230
2231 int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d) //, float *autodist )
2232 {
2233         RegionView3D *rv3d= ar->regiondata;
2234
2235         /* Get Z Depths, needed for perspective, nice for ortho */
2236         draw_depth(scene, ar, v3d, NULL);
2237
2238         /* force updating */
2239         if (rv3d->depths) {
2240                 rv3d->depths->damaged = 1;
2241         }
2242
2243         view3d_update_depths(ar, v3d);
2244         return 1;
2245 }
2246
2247 // no 4x4 sampling, run view_autodist_init first
2248 int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2249 {
2250         RegionView3D *rv3d= ar->regiondata;
2251         bglMats mats; /* ZBuffer depth vars, could cache? */
2252         float depth;
2253         double cent[2],  p[3];
2254
2255         if (mval[0] < 0) return 0;
2256         if (mval[1] < 0) return 0;
2257         if (mval[0] >= rv3d->depths->w) return 0;
2258         if (mval[1] >= rv3d->depths->h) return 0;
2259
2260         /* Get Z Depths, needed for perspective, nice for ortho */
2261         bgl_get_mats(&mats);
2262         depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
2263
2264         if (depth==MAXFLOAT)
2265                 return 0;
2266
2267         cent[0] = (double)mval[0];
2268         cent[1] = (double)mval[1];
2269
2270         if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2271                 return 0;
2272
2273         mouse_worldloc[0] = (float)p[0];
2274         mouse_worldloc[1] = (float)p[1];
2275         mouse_worldloc[2] = (float)p[2];
2276         return 1;
2277 }
2278
2279 /* ********************* NDOF ************************ */
2280 /* note: this code is confusing and unclear... (ton) */
2281 /* **************************************************** */
2282
2283 // ndof scaling will be moved to user setting.
2284 // In the mean time this is just a place holder.
2285
2286 // Note: scaling in the plugin and ghostwinlay.c
2287 // should be removed. With driver default setting,
2288 // each axis returns approx. +-200 max deflection.
2289
2290 // The values I selected are based on the older
2291 // polling i/f. With event i/f, the sensistivity
2292 // can be increased for improved response from
2293 // small deflections of the device input.
2294
2295
2296 // lukep notes : i disagree on the range.
2297 // the normal 3Dconnection driver give +/-400
2298 // on defaut range in other applications
2299 // and up to +/- 1000 if set to maximum
2300 // because i remove the scaling by delta,
2301 // which was a bad idea as it depend of the system
2302 // speed and os, i changed the scaling values, but
2303 // those are still not ok
2304
2305
2306 float ndof_axis_scale[6] = {
2307         +0.01,  // Tx
2308         +0.01,  // Tz
2309         +0.01,  // Ty
2310         +0.0015,        // Rx
2311         +0.0015,        // Rz
2312         +0.0015 // Ry
2313 };
2314
2315 void filterNDOFvalues(float *sbval)
2316 {
2317         int i=0;
2318         float max  = 0.0;
2319
2320         for (i =0; i<6;i++)
2321                 if (fabs(sbval[i]) > max)
2322                         max = fabs(sbval[i]);
2323         for (i =0; i<6;i++)
2324                 if (fabs(sbval[i]) != max )
2325                         sbval[i]=0.0;
2326 }
2327
2328 // statics for controlling rv3d->dist corrections.
2329 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2330 // viewmove restores based on dz_flag state.
2331
2332 int dz_flag = 0;
2333 float m_dist;
2334
2335 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2336 {
2337         RegionView3D *rv3d= ar->regiondata;
2338     int i;
2339     float phi;
2340     float dval[7];
2341         // static fval[6] for low pass filter; device input vector is dval[6]
2342         static float fval[6];
2343     float tvec[3],rvec[3];
2344     float q1[4];
2345         float mat[3][3];
2346         float upvec[3];
2347
2348
2349     /*----------------------------------------------------
2350          * sometimes this routine is called from headerbuttons
2351      * viewmove needs to refresh the screen
2352      */
2353 // XXX  areawinset(ar->win);
2354
2355
2356         // fetch the current state of the ndof device
2357 // XXX  getndof(dval);
2358
2359         if (v3d->ndoffilter)
2360                 filterNDOFvalues(fval);
2361
2362         // Scale input values
2363
2364 //      if(dval[6] == 0) return; // guard against divide by zero
2365
2366         for(i=0;i<6;i++) {
2367
2368                 // user scaling
2369                 dval[i] = dval[i] * ndof_axis_scale[i];
2370         }
2371
2372
2373         // low pass filter with zero crossing reset
2374
2375         for(i=0;i<6;i++) {
2376                 if((dval[i] * fval[i]) >= 0)
2377                         dval[i] = (fval[i] * 15 + dval[i]) / 16;
2378                 else
2379                         fval[i] = 0;
2380         }
2381
2382
2383         // force perspective mode. This is a hack and is
2384         // incomplete. It doesn't actually effect the view
2385         // until the first draw and doesn't update the menu
2386         // to reflect persp mode.
2387
2388         rv3d->persp = RV3D_PERSP;
2389
2390
2391         // Correct the distance jump if rv3d->dist != 0
2392
2393         // This is due to a side effect of the original
2394         // mouse view rotation code. The rotation point is
2395         // set a distance in front of the viewport to
2396         // make rotating with the mouse look better.
2397         // The distance effect is written at a low level
2398         // in the view management instead of the mouse
2399         // view function. This means that all other view
2400         // movement devices must subtract this from their
2401         // view transformations.
2402
2403         if(rv3d->dist != 0.0) {
2404                 dz_flag = 1;
2405                 m_dist = rv3d->dist;
2406                 upvec[0] = upvec[1] = 0;
2407                 upvec[2] = rv3d->dist;
2408                 copy_m3_m4(mat, rv3d->viewinv);
2409                 mul_m3_v3(mat, upvec);
2410                 sub_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2411                 rv3d->dist = 0.0;
2412         }
2413
2414
2415         // Apply rotation
2416         // Rotations feel relatively faster than translations only in fly mode, so
2417         // we have no choice but to fix that here (not in the plugins)
2418         rvec[0] = -0.5 * dval[3];
2419         rvec[1] = -0.5 * dval[4];
2420         rvec[2] = -0.5 * dval[5];
2421
2422         // rotate device x and y by view z
2423
2424         copy_m3_m4(mat, rv3d->viewinv);
2425         mat[2][2] = 0.0f;
2426         mul_m3_v3(mat, rvec);
2427
2428         // rotate the view
2429
2430         phi = normalize_v3(rvec);
2431         if(phi != 0) {
2432                 axis_angle_to_quat(q1,rvec,phi);
2433                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2434         }
2435
2436
2437         // Apply translation
2438
2439         tvec[0] = dval[0];
2440         tvec[1] = dval[1];
2441         tvec[2] = -dval[2];
2442
2443         // the next three lines rotate the x and y translation coordinates
2444         // by the current z axis angle
2445
2446         copy_m3_m4(mat, rv3d->viewinv);
2447         mat[2][2] = 0.0f;
2448         mul_m3_v3(mat, tvec);
2449
2450         // translate the view
2451
2452         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, tvec);
2453
2454
2455         /*----------------------------------------------------
2456      * refresh the screen XXX
2457       */
2458
2459         // update render preview window
2460
2461 // XXX  BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2462 }
2463
2464 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2465 {
2466         RegionView3D *rv3d= ar->regiondata;
2467         float fval[7];
2468         float dvec[3];
2469         float sbadjust = 1.0f;
2470         float len;
2471         short use_sel = 0;
2472         Object *ob = OBACT;
2473         float m[3][3];
2474         float m_inv[3][3];
2475         float xvec[3] = {1,0,0};
2476         float yvec[3] = {0,-1,0};
2477         float zvec[3] = {0,0,1};
2478         float phi, si;
2479         float q1[4];
2480         float obofs[3];
2481         float reverse;
2482         //float diff[4];
2483         float d, curareaX, curareaY;
2484         float mat[3][3];
2485         float upvec[3];
2486
2487     /* Sensitivity will control how fast the view rotates.  The value was
2488      * obtained experimentally by tweaking until the author didn't get dizzy watching.
2489      * Perhaps this should be a configurable user parameter.
2490      */
2491         float psens = 0.005f * (float) U.ndof_pan;   /* pan sensitivity */
2492         float rsens = 0.005f * (float) U.ndof_rotate;  /* rotate sensitivity */
2493         float zsens = 0.3f;   /* zoom sensitivity */
2494
2495         const float minZoom = -30.0f;
2496         const float maxZoom = 300.0f;
2497
2498         //reset view type
2499         rv3d->view = 0;
2500 //printf("passing here \n");
2501 //
2502         if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
2503                 use_sel = 1;
2504         }
2505
2506         if((dz_flag)||rv3d->dist==0) {
2507                 dz_flag = 0;
2508                 rv3d->dist = m_dist;
2509                 upvec[0] = upvec[1] = 0;
2510                 upvec[2] = rv3d->dist;
2511                 copy_m3_m4(mat, rv3d->viewinv);
2512                 mul_m3_v3(mat, upvec);
2513                 add_v3_v3v3(rv3d->ofs, rv3d->ofs, upvec);
2514         }
2515
2516     /*----------------------------------------------------
2517          * sometimes this routine is called from headerbuttons
2518      * viewmove needs to refresh the screen
2519      */
2520 // XXX  areawinset(curarea->win);
2521
2522     /*----------------------------------------------------
2523      * record how much time has passed. clamp at 10 Hz
2524      * pretend the previous frame occured at the clamped time
2525      */
2526 //    now = PIL_check_seconds_timer();
2527  //   frametime = (now - prevTime);
2528  //   if (frametime > 0.1f){        /* if more than 1/10s */
2529  //       frametime = 1.0f/60.0;      /* clamp at 1/60s so no jumps when starting to move */
2530 //    }
2531 //    prevTime = now;
2532  //   sbadjust *= 60 * frametime;             /* normalize ndof device adjustments to 100Hz for framerate independence */
2533
2534     /* fetch the current state of the ndof device & enforce dominant mode if selected */
2535 // XXX    getndof(fval);
2536         if (v3d->ndoffilter)
2537                 filterNDOFvalues(fval);
2538
2539
2540     // put scaling back here, was previously in ghostwinlay
2541         fval[0] = fval[0] * (1.0f/600.0f);
2542         fval[1] = fval[1] * (1.0f/600.0f);
2543         fval[2] = fval[2] * (1.0f/1100.0f);
2544         fval[3] = fval[3] * 0.00005f;
2545         fval[4] =-fval[4] * 0.00005f;
2546         fval[5] = fval[5] * 0.00005f;
2547         fval[6] = fval[6] / 1000000.0f;
2548
2549     // scale more if not in perspective mode
2550         if (rv3d->persp == RV3D_ORTHO) {
2551                 fval[0] = fval[0] * 0.05f;
2552                 fval[1] = fval[1] * 0.05f;
2553                 fval[2] = fval[2] * 0.05f;
2554                 fval[3] = fval[3] * 0.9f;
2555                 fval[4] = fval[4] * 0.9f;
2556                 fval[5] = fval[5] * 0.9f;
2557                 zsens *= 8;
2558         }
2559
2560     /* set object offset */
2561         if (ob) {
2562                 obofs[0] = -ob->obmat[3][0];
2563                 obofs[1] = -ob->obmat[3][1];
2564                 obofs[2] = -ob->obmat[3][2];
2565         }
2566         else {
2567                 VECCOPY(obofs, rv3d->ofs);
2568         }
2569
2570     /* calc an adjustment based on distance from camera
2571        disabled per patch 14402 */
2572      d = 1.0f;
2573
2574 /*    if (ob) {
2575         sub_v3_v3v3(diff, obofs, rv3d->ofs);
2576         d = len_v3(diff);
2577     }
2578 */
2579
2580     reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
2581
2582     /*----------------------------------------------------
2583      * ndof device pan
2584      */
2585     psens *= 1.0f + d;
2586     curareaX = sbadjust * psens * fval[0];
2587     curareaY = sbadjust * psens * fval[1];
2588     dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
2589     dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
2590     dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
2591     add_v3_v3v3(rv3d->ofs, rv3d->ofs, dvec);
2592
2593     /*----------------------------------------------------
2594      * ndof device dolly
2595      */
2596     len = zsens * sbadjust * fval[2];
2597
2598     if (rv3d->persp==RV3D_CAMOB) {
2599         if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
2600             rv3d->camzoom+= 10.0f * -len;
2601         }
2602         if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
2603         else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
2604     }
2605     else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
2606         rv3d->dist*=(1.0 + len);
2607     }
2608
2609
2610     /*----------------------------------------------------
2611      * ndof device turntable
2612      * derived from the turntable code in viewmove
2613      */
2614
2615     /* Get the 3x3 matrix and its inverse from the quaternion */
2616     quat_to_mat3( m,rv3d->viewquat);
2617     invert_m3_m3(m_inv,m);
2618
2619     /* Determine the direction of the x vector (for rotating up and down) */
2620     /* This can likely be compuated directly from the quaternion. */
2621     mul_m3_v3(m_inv,xvec);
2622     mul_m3_v3(m_inv,yvec);
2623     mul_m3_v3(m_inv,zvec);
2624
2625     /* Perform the up/down rotation */
2626     phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
2627     si = sin(phi);
2628     q1[0] = cos(phi);
2629     q1[1] = si * xvec[0];
2630     q1[2] = si * xvec[1];
2631     q1[3] = si * xvec[2];
2632     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2633
2634     if (use_sel) {
2635         conjugate_qt(q1); /* conj == inv for unit quat */
2636         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2637         mul_qt_v3(q1, rv3d->ofs);
2638         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2639     }
2640
2641     /* Perform the orbital rotation */
2642     /* Perform the orbital rotation
2643        If the seen Up axis is parallel to the zoom axis, rotation should be
2644        achieved with a pure Roll motion (no Spin) on the device. When you start
2645        to tilt, moving from Top to Side view, Spinning will increasingly become
2646        more relevant while the Roll component will decrease. When a full
2647        Side view is reached, rotations around the world's Up axis are achieved
2648        with a pure Spin-only motion.  In other words the control of the spinning
2649        around the world's Up axis should move from the device's Spin axis to the
2650        device's Roll axis depending on the orientation of the world's Up axis
2651        relative to the screen. */
2652     //phi = sbadjust * rsens * reverse * fval[4];  /* spin the knob, y axis */
2653     phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
2654     q1[0] = cos(phi);
2655     q1[1] = q1[2] = 0.0;
2656     q1[3] = sin(phi);
2657     mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2658
2659     if (use_sel) {
2660         conjugate_qt(q1);
2661         sub_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2662         mul_qt_v3(q1, rv3d->ofs);
2663         add_v3_v3v3(rv3d->ofs, rv3d->ofs, obofs);
2664     }
2665
2666     /*----------------------------------------------------
2667      * refresh the screen
2668      */
2669 // XXX    scrarea_do_windraw(curarea);
2670 }
2671
2672
2673
2674