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