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