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