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