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