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