4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * Contributor(s): Blender Foundation
26 * ***** END GPL LICENSE BLOCK *****
34 #include "DNA_armature_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_scene_types.h"
38 #include "MEM_guardedalloc.h"
40 #include "BLI_blenlib.h"
44 #include "BKE_action.h"
45 #include "BKE_context.h"
46 #include "BKE_depsgraph.h"
47 #include "BKE_object.h"
48 #include "BKE_global.h"
49 #include "BKE_paint.h"
50 #include "BKE_report.h"
51 #include "BKE_scene.h"
52 #include "BKE_screen.h"
53 #include "BKE_utildefines.h"
61 #include "RNA_access.h"
62 #include "RNA_define.h"
64 #include "ED_particle.h"
65 #include "ED_retopo.h"
66 #include "ED_screen.h"
67 #include "ED_transform.h"
71 #include "PIL_time.h" /* smoothview */
73 #include "view3d_intern.h" // own include
75 /* ********************** view3d_edit: view manipulations ********************* */
77 /* ********************* box view support ***************** */
79 static void view3d_boxview_clip(ScrArea *sa)
82 BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb");
84 float x1= 0.0f, y1= 0.0f, z1= 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f};
87 /* create bounding box */
88 for(ar= sa->regionbase.first; ar; ar= ar->next) {
89 if(ar->regiontype==RGN_TYPE_WINDOW) {
90 RegionView3D *rv3d= ar->regiondata;
92 if(rv3d->viewlock & RV3D_BOXCLIP) {
93 if(ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM)) {
94 if(ar->winx>ar->winy) x1= rv3d->dist;
95 else x1= ar->winx*rv3d->dist/ar->winy;
97 if(ar->winx>ar->winy) y1= ar->winy*rv3d->dist/ar->winx;
99 copy_v2_v2(ofs, rv3d->ofs);
101 else if(ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK)) {
102 ofs[2]= rv3d->ofs[2];
104 if(ar->winx>ar->winy) z1= ar->winy*rv3d->dist/ar->winx;
111 for(val=0; val<8; val++) {
112 if(ELEM4(val, 0, 3, 4, 7))
113 bb->vec[val][0]= -x1 - ofs[0];
115 bb->vec[val][0]= x1 - ofs[0];
117 if(ELEM4(val, 0, 1, 4, 5))
118 bb->vec[val][1]= -y1 - ofs[1];
120 bb->vec[val][1]= y1 - ofs[1];
123 bb->vec[val][2]= -z1 - ofs[2];
125 bb->vec[val][2]= z1 - ofs[2];
128 /* normals for plane equations */
129 normal_tri_v3( clip[0],bb->vec[0], bb->vec[1], bb->vec[4]);
130 normal_tri_v3( clip[1],bb->vec[1], bb->vec[2], bb->vec[5]);
131 normal_tri_v3( clip[2],bb->vec[2], bb->vec[3], bb->vec[6]);
132 normal_tri_v3( clip[3],bb->vec[3], bb->vec[0], bb->vec[7]);
133 normal_tri_v3( clip[4],bb->vec[4], bb->vec[5], bb->vec[6]);
134 normal_tri_v3( clip[5],bb->vec[0], bb->vec[2], bb->vec[1]);
136 /* then plane equations */
137 for(val=0; val<5; val++) {
138 clip[val][3]= - clip[val][0]*bb->vec[val][0] - clip[val][1]*bb->vec[val][1] - clip[val][2]*bb->vec[val][2];
140 clip[5][3]= - clip[5][0]*bb->vec[0][0] - clip[5][1]*bb->vec[0][1] - clip[5][2]*bb->vec[0][2];
142 /* create bounding box */
143 for(ar= sa->regionbase.first; ar; ar= ar->next) {
144 if(ar->regiontype==RGN_TYPE_WINDOW) {
145 RegionView3D *rv3d= ar->regiondata;
147 if(rv3d->viewlock & RV3D_BOXCLIP) {
148 rv3d->rflag |= RV3D_CLIPPING;
149 memcpy(rv3d->clip, clip, sizeof(clip));
150 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
151 rv3d->clipbb= MEM_dupallocN(bb);
158 /* sync center/zoom view of region to others, for view transforms */
159 static void view3d_boxview_sync(ScrArea *sa, ARegion *ar)
162 RegionView3D *rv3d= ar->regiondata;
164 for(artest= sa->regionbase.first; artest; artest= artest->next) {
165 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
166 RegionView3D *rv3dtest= artest->regiondata;
168 if(rv3dtest->viewlock) {
169 rv3dtest->dist= rv3d->dist;
171 if( ELEM(rv3d->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM) ) {
172 if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
173 rv3dtest->ofs[0]= rv3d->ofs[0];
174 else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
175 rv3dtest->ofs[1]= rv3d->ofs[1];
177 else if( ELEM(rv3d->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK) ) {
178 if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
179 rv3dtest->ofs[0]= rv3d->ofs[0];
180 else if( ELEM(rv3dtest->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT))
181 rv3dtest->ofs[2]= rv3d->ofs[2];
183 else if( ELEM(rv3d->view, RV3D_VIEW_RIGHT, RV3D_VIEW_LEFT) ) {
184 if( ELEM(rv3dtest->view, RV3D_VIEW_TOP, RV3D_VIEW_BOTTOM))
185 rv3dtest->ofs[1]= rv3d->ofs[1];
186 if( ELEM(rv3dtest->view, RV3D_VIEW_FRONT, RV3D_VIEW_BACK))
187 rv3dtest->ofs[2]= rv3d->ofs[2];
190 ED_region_tag_redraw(artest);
194 view3d_boxview_clip(sa);
197 /* for home, center etc */
198 void view3d_boxview_copy(ScrArea *sa, ARegion *ar)
201 RegionView3D *rv3d= ar->regiondata;
203 for(artest= sa->regionbase.first; artest; artest= artest->next) {
204 if(artest!=ar && artest->regiontype==RGN_TYPE_WINDOW) {
205 RegionView3D *rv3dtest= artest->regiondata;
207 if(rv3dtest->viewlock) {
208 rv3dtest->dist= rv3d->dist;
209 copy_v3_v3(rv3dtest->ofs, rv3d->ofs);
210 ED_region_tag_redraw(artest);
214 view3d_boxview_clip(sa);
217 void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar)
219 RegionView3D *rv3d= ar->regiondata;
222 /* this function copies flags from the first of the 3 other quadview
223 regions to the 2 other, so it assumes this is the region whose
224 properties are always being edited, weak */
225 viewlock= rv3d->viewlock;
227 if((viewlock & RV3D_LOCKED)==0)
229 else if((viewlock & RV3D_BOXVIEW)==0)
230 viewlock &= ~RV3D_BOXCLIP;
232 for(; ar; ar= ar->prev) {
233 if(ar->alignment==RGN_ALIGN_QSPLIT) {
234 rv3d= ar->regiondata;
235 rv3d->viewlock= viewlock;
239 if(rv3d->viewlock & RV3D_BOXVIEW)
240 view3d_boxview_copy(sa, sa->regionbase.last);
242 ED_area_tag_redraw(sa);
245 /* ************************** init for view ops **********************************/
247 typedef struct ViewOpsData {
252 /* needed for continuous zoom */
254 double timer_lastdraw;
258 float reverse, dist0;
260 short axis_snap; /* view rotate only */
262 /* use for orbit selection and auto-dist */
263 float ofs[3], dyn_ofs[3];
266 int origx, origy, oldx, oldy;
267 int origkey; /* the key that triggered the operator */
271 #define TRACKBALLSIZE (1.1)
273 static void calctrackballvec(rcti *rect, int mx, int my, float *vec)
275 float x, y, radius, d, z, t;
277 radius= TRACKBALLSIZE;
279 /* normalize x and y */
280 x= (rect->xmax + rect->xmin)/2 - mx;
281 x/= (float)((rect->xmax - rect->xmin)/4);
282 y= (rect->ymax + rect->ymin)/2 - my;
283 y/= (float)((rect->ymax - rect->ymin)/2);
286 if (d < radius*M_SQRT1_2) /* Inside sphere */
287 z = sqrt(radius*radius - d*d);
290 t = radius / M_SQRT2;
296 vec[2]= -z; /* yah yah! */
300 static void viewops_data_create(bContext *C, wmOperator *op, wmEvent *event)
302 static float lastofs[3] = {0,0,0};
303 View3D *v3d = CTX_wm_view3d(C);
305 ViewOpsData *vod= MEM_callocN(sizeof(ViewOpsData), "viewops data");
309 vod->sa= CTX_wm_area(C);
310 vod->ar= CTX_wm_region(C);
311 vod->rv3d= rv3d= vod->ar->regiondata;
312 vod->dist0= rv3d->dist;
313 copy_qt_qt(vod->oldquat, rv3d->viewquat);
314 vod->origx= vod->oldx= event->x;
315 vod->origy= vod->oldy= event->y;
316 vod->origkey= event->type; /* the key that triggered the operator. */
317 vod->use_dyn_ofs= (U.uiflag & USER_ORBIT_SELECTION) ? 1:0;
319 if (vod->use_dyn_ofs) {
320 copy_v3_v3(vod->ofs, rv3d->ofs);
321 /* If there's no selection, lastofs is unmodified and last value since static */
322 calculateTransformCenter(C, V3D_CENTROID, lastofs);
323 negate_v3_v3(vod->dyn_ofs, lastofs);
325 else if (U.uiflag & USER_ORBIT_ZBUF) {
327 view3d_operator_needs_opengl(C); /* needed for zbuf drawing */
329 if((vod->use_dyn_ofs=view_autodist(CTX_data_scene(C), vod->ar, v3d, event->mval, vod->dyn_ofs))) {
330 if (rv3d->persp==RV3D_PERSP) {
331 float my_origin[3]; /* original G.vd->ofs */
332 float my_pivot[3]; /* view */
335 // locals for dist correction
339 negate_v3_v3(my_origin, rv3d->ofs); /* ofs is flipped */
341 /* Set the dist value to be the distance from this 3d point */
342 /* this means youll always be able to zoom into it and panning wont go bad when dist was zero */
344 /* remove dist value */
345 upvec[0] = upvec[1] = 0;
346 upvec[2] = rv3d->dist;
347 copy_m3_m4(mat, rv3d->viewinv);
349 mul_m3_v3(mat, upvec);
350 sub_v3_v3v3(my_pivot, rv3d->ofs, upvec);
351 negate_v3(my_pivot); /* ofs is flipped */
353 /* find a new ofs value that is allong the view axis (rather then the mouse location) */
354 closest_to_line_v3(dvec, vod->dyn_ofs, my_pivot, my_origin);
355 vod->dist0 = rv3d->dist = len_v3v3(my_pivot, dvec);
357 negate_v3_v3(rv3d->ofs, dvec);
359 negate_v3(vod->dyn_ofs);
360 copy_v3_v3(vod->ofs, rv3d->ofs);
362 vod->ofs[0] = vod->ofs[1] = vod->ofs[2] = 0.0f;
366 /* lookup, we dont pass on v3d to prevent confusement */
367 vod->grid= v3d->grid;
370 calctrackballvec(&vod->ar->winrct, event->x, event->y, vod->trackvec);
372 initgrabz(rv3d, -rv3d->ofs[0], -rv3d->ofs[1], -rv3d->ofs[2]);
375 if (rv3d->persmat[2][1] < 0.0f)
378 rv3d->rflag |= RV3D_NAVIGATING;
381 static void viewops_data_free(bContext *C, wmOperator *op)
383 Paint *p = paint_get_active(CTX_data_scene(C));
384 ViewOpsData *vod= op->customdata;
386 vod->rv3d->rflag &= ~RV3D_NAVIGATING;
388 if(p && (p->flags & PAINT_FAST_NAVIGATE))
389 ED_region_tag_redraw(vod->ar);
392 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), vod->timer);
395 op->customdata= NULL;
398 /* ************************** viewrotate **********************************/
400 static const float thres = 0.93f; //cos(20 deg);
402 #define COS45 0.70710678118654746
405 static float snapquats[39][5] = {
406 /*{q0, q1, q3, q4, view}*/
407 {COS45, -SIN45, 0.0, 0.0, RV3D_VIEW_FRONT}, //front
408 {0.0, 0.0, -SIN45, -SIN45, RV3D_VIEW_BACK}, //back
409 {1.0, 0.0, 0.0, 0.0, RV3D_VIEW_TOP}, //top
410 {0.0, -1.0, 0.0, 0.0, RV3D_VIEW_BOTTOM}, //bottom
411 {0.5, -0.5, -0.5, -0.5, RV3D_VIEW_RIGHT}, //left
412 {0.5, -0.5, 0.5, 0.5, RV3D_VIEW_LEFT}, //right
414 /* some more 45 deg snaps */
415 {0.65328145027160645, -0.65328145027160645, 0.27059805393218994, 0.27059805393218994, 0},
416 {0.92387950420379639, 0.0, 0.0, 0.38268342614173889, 0},
417 {0.0, -0.92387950420379639, 0.38268342614173889, 0.0, 0},
418 {0.35355335474014282, -0.85355335474014282, 0.35355338454246521, 0.14644660055637360, 0},
419 {0.85355335474014282, -0.35355335474014282, 0.14644660055637360, 0.35355338454246521, 0},
420 {0.49999994039535522, -0.49999994039535522, 0.49999997019767761, 0.49999997019767761, 0},
421 {0.27059802412986755, -0.65328145027160645, 0.65328145027160645, 0.27059802412986755, 0},
422 {0.65328145027160645, -0.27059802412986755, 0.27059802412986755, 0.65328145027160645, 0},
423 {0.27059799432754517, -0.27059799432754517, 0.65328139066696167, 0.65328139066696167, 0},
424 {0.38268336653709412, 0.0, 0.0, 0.92387944459915161, 0},
425 {0.0, -0.38268336653709412, 0.92387944459915161, 0.0, 0},
426 {0.14644658565521240, -0.35355335474014282, 0.85355335474014282, 0.35355335474014282, 0},
427 {0.35355335474014282, -0.14644658565521240, 0.35355335474014282, 0.85355335474014282, 0},
428 {0.0, 0.0, 0.92387944459915161, 0.38268336653709412, 0},
429 {-0.0, 0.0, 0.38268336653709412, 0.92387944459915161, 0},
430 {-0.27059802412986755, 0.27059802412986755, 0.65328133106231689, 0.65328133106231689, 0},
431 {-0.38268339633941650, 0.0, 0.0, 0.92387938499450684, 0},
432 {0.0, 0.38268339633941650, 0.92387938499450684, 0.0, 0},
433 {-0.14644658565521240, 0.35355338454246521, 0.85355329513549805, 0.35355332493782043, 0},
434 {-0.35355338454246521, 0.14644658565521240, 0.35355332493782043, 0.85355329513549805, 0},
435 {-0.49999991059303284, 0.49999991059303284, 0.49999985098838806, 0.49999985098838806, 0},
436 {-0.27059799432754517, 0.65328145027160645, 0.65328139066696167, 0.27059799432754517, 0},
437 {-0.65328145027160645, 0.27059799432754517, 0.27059799432754517, 0.65328139066696167, 0},
438 {-0.65328133106231689, 0.65328133106231689, 0.27059793472290039, 0.27059793472290039, 0},
439 {-0.92387932538986206, 0.0, 0.0, 0.38268333673477173, 0},
440 {0.0, 0.92387932538986206, 0.38268333673477173, 0.0, 0},
441 {-0.35355329513549805, 0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0},
442 {-0.85355329513549805, 0.35355329513549805, 0.14644657075405121, 0.35355329513549805, 0},
443 {-0.38268330693244934, 0.92387938499450684, 0.0, 0.0, 0},
444 {-0.92387938499450684, 0.38268330693244934, 0.0, 0.0, 0},
445 {-COS45, 0.0, 0.0, SIN45, 0},
446 {COS45, 0.0, 0.0, SIN45, 0},
447 {0.0, 0.0, 0.0, 1.0, 0}
456 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
457 #define VIEW_MODAL_CONFIRM 1 /* used for all view operations */
458 #define VIEWROT_MODAL_AXIS_SNAP_ENABLE 2
459 #define VIEWROT_MODAL_AXIS_SNAP_DISABLE 3
460 #define VIEWROT_MODAL_SWITCH_ZOOM 4
461 #define VIEWROT_MODAL_SWITCH_MOVE 5
462 #define VIEWROT_MODAL_SWITCH_ROTATE 6
464 /* called in transform_ops.c, on each regeneration of keymaps */
465 void viewrotate_modal_keymap(wmKeyConfig *keyconf)
467 static EnumPropertyItem modal_items[] = {
468 {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
470 {VIEWROT_MODAL_AXIS_SNAP_ENABLE, "AXIS_SNAP_ENABLE", 0, "Enable Axis Snap", ""},
471 {VIEWROT_MODAL_AXIS_SNAP_DISABLE, "AXIS_SNAP_DISABLE", 0, "Disable Axis Snap", ""},
473 {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
474 {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
476 {0, NULL, 0, NULL, NULL}};
478 wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Rotate Modal");
480 /* this function is called for each spacetype, only needs to add map once */
483 keymap= WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items);
485 /* items for modal map */
486 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
487 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
489 WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_ENABLE);
490 WM_modalkeymap_add_item(keymap, LEFTALTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_AXIS_SNAP_DISABLE);
492 /* disabled mode switching for now, can re-implement better, later on
493 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
494 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
495 WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
498 /* assign map to operators */
499 WM_modalkeymap_assign(keymap, "VIEW3D_OT_rotate");
503 static void viewrotate_apply(ViewOpsData *vod, int x, int y)
505 RegionView3D *rv3d= vod->rv3d;
507 rv3d->view= 0; /* need to reset everytime because of view snapping */
509 if (U.flag & USER_TRACKBALL) {
510 float phi, si, q1[4], dvec[3], newvec[3];
512 calctrackballvec(&vod->ar->winrct, x, y, newvec);
514 sub_v3_v3v3(dvec, newvec, vod->trackvec);
516 si= sqrt(dvec[0]*dvec[0]+ dvec[1]*dvec[1]+ dvec[2]*dvec[2]);
517 si/= (2.0*TRACKBALLSIZE);
519 cross_v3_v3v3(q1+1, vod->trackvec, newvec);
522 /* Allow for rotation beyond the interval
527 /* This relation is used instead of
528 * phi = asin(si) so that the angle
529 * of rotation is linearly proportional
530 * to the distance that the mouse is
532 phi = si * M_PI / 2.0;
535 mul_v3_fl(q1+1, sin(phi));
536 mul_qt_qtqt(rv3d->viewquat, q1, vod->oldquat);
538 if (vod->use_dyn_ofs) {
539 /* compute the post multiplication quat, to rotate the offset correctly */
540 copy_qt_qt(q1, vod->oldquat);
542 mul_qt_qtqt(q1, q1, rv3d->viewquat);
544 conjugate_qt(q1); /* conj == inv for unit quat */
545 copy_v3_v3(rv3d->ofs, vod->ofs);
546 sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
547 mul_qt_v3(q1, rv3d->ofs);
548 add_v3_v3(rv3d->ofs, vod->dyn_ofs);
552 /* New turntable view code by John Aughey */
556 float xvec[3] = {1,0,0};
557 /* Sensitivity will control how fast the viewport rotates. 0.0035 was
558 obtained experimentally by looking at viewport rotation sensitivities
559 on other modeling programs. */
560 /* Perhaps this should be a configurable user parameter. */
561 const float sensitivity = 0.0035;
563 /* Get the 3x3 matrix and its inverse from the quaternion */
564 quat_to_mat3( m,rv3d->viewquat);
565 invert_m3_m3(m_inv,m);
567 /* Determine the direction of the x vector (for rotating up and down) */
568 /* This can likely be computed directly from the quaternion. */
569 mul_m3_v3(m_inv,xvec);
571 /* Perform the up/down rotation */
572 phi = sensitivity * -(y - vod->oldy);
574 mul_v3_v3fl(q1+1, xvec, sin(phi));
575 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
577 if (vod->use_dyn_ofs) {
578 conjugate_qt(q1); /* conj == inv for unit quat */
579 sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
580 mul_qt_v3(q1, rv3d->ofs);
581 add_v3_v3(rv3d->ofs, vod->dyn_ofs);
584 /* Perform the orbital rotation */
585 phi = sensitivity * vod->reverse * (x - vod->oldx);
589 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
591 if (vod->use_dyn_ofs) {
593 sub_v3_v3(rv3d->ofs, vod->dyn_ofs);
594 mul_qt_v3(q1, rv3d->ofs);
595 add_v3_v3(rv3d->ofs, vod->dyn_ofs);
599 /* check for view snap */
602 float viewquat_inv[4];
603 float zaxis[3]={0,0,1};
604 invert_qt_qt(viewquat_inv, rv3d->viewquat);
606 mul_qt_v3(viewquat_inv, zaxis);
608 for (i = 0 ; i < 39; i++){
610 float view = (int)snapquats[i][4];
611 float viewquat_inv_test[4];
612 float zaxis_test[3]={0,0,1};
614 invert_qt_qt(viewquat_inv_test, snapquats[i]);
615 mul_qt_v3(viewquat_inv_test, zaxis_test);
617 if(angle_v3v3(zaxis_test, zaxis) < DEG2RAD(45/3)) {
618 /* find the best roll */
619 float quat_roll[4], quat_final[4], quat_best[4];
620 float viewquat_align[4]; /* viewquat aligned to zaxis_test */
621 float viewquat_align_inv[4]; /* viewquat aligned to zaxis_test */
622 float best_angle = FLT_MAX;
625 /* viewquat_align is the original viewquat aligned to the snapped axis
626 * for testing roll */
627 rotation_between_vecs_to_quat(viewquat_align, zaxis_test, zaxis);
628 normalize_qt(viewquat_align);
629 mul_qt_qtqt(viewquat_align, rv3d->viewquat, viewquat_align);
630 normalize_qt(viewquat_align);
631 invert_qt_qt(viewquat_align_inv, viewquat_align);
634 for(j= 0; j<8; j++) {
636 float xaxis1[3]={1,0,0};
637 float xaxis2[3]={1,0,0};
638 float quat_final_inv[4];
640 axis_angle_to_quat(quat_roll, zaxis_test, j * DEG2RAD(45.0));
641 normalize_qt(quat_roll);
643 mul_qt_qtqt(quat_final, snapquats[i], quat_roll);
644 normalize_qt(quat_final);
646 /* compare 2 vector angles to find the least roll */
647 invert_qt_qt(quat_final_inv, quat_final);
648 mul_qt_v3(viewquat_align_inv, xaxis1);
649 mul_qt_v3(quat_final_inv, xaxis2);
650 angle= angle_v3v3(xaxis1, xaxis2);
652 if(angle <= best_angle) {
654 copy_qt_qt(quat_best, quat_final);
655 if(j) view= 0; /* view grid assumes certain up axis */
659 copy_qt_qt(rv3d->viewquat, quat_best);
660 rv3d->view= view; /* if we snap to a rolled camera the grid is invalid */
669 ED_region_tag_redraw(vod->ar);
672 static int viewrotate_modal(bContext *C, wmOperator *op, wmEvent *event)
674 ViewOpsData *vod= op->customdata;
675 short event_code= VIEW_PASS;
677 /* execute the events */
678 if(event->type==MOUSEMOVE) {
679 event_code= VIEW_APPLY;
681 else if(event->type==EVT_MODAL_MAP) {
682 switch (event->val) {
683 case VIEW_MODAL_CONFIRM:
684 event_code= VIEW_CONFIRM;
686 case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
687 vod->axis_snap= TRUE;
688 event_code= VIEW_APPLY;
690 case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
691 vod->axis_snap= FALSE;
692 event_code= VIEW_APPLY;
694 case VIEWROT_MODAL_SWITCH_ZOOM:
695 WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
696 event_code= VIEW_CONFIRM;
698 case VIEWROT_MODAL_SWITCH_MOVE:
699 WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
700 event_code= VIEW_CONFIRM;
704 else if(event->type==vod->origkey && event->val==KM_RELEASE) {
705 event_code= VIEW_CONFIRM;
708 if(event_code==VIEW_APPLY) {
709 viewrotate_apply(vod, event->x, event->y);
711 else if (event_code==VIEW_CONFIRM) {
712 request_depth_update(CTX_wm_region_view3d(C));
713 viewops_data_free(C, op);
715 return OPERATOR_FINISHED;
718 return OPERATOR_RUNNING_MODAL;
721 static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
723 RegionView3D *rv3d= CTX_wm_region_view3d(C);
727 return OPERATOR_CANCELLED;
729 /* makes op->customdata */
730 viewops_data_create(C, op, event);
733 /* switch from camera view when: */
734 if(vod->rv3d->persp != RV3D_PERSP) {
736 if (U.uiflag & USER_AUTOPERSP)
737 vod->rv3d->persp= RV3D_PERSP;
738 else if(vod->rv3d->persp==RV3D_CAMOB) {
740 /* changed since 2.4x, use the camera view */
741 View3D *v3d = CTX_wm_view3d(C);
743 view3d_settings_from_ob(v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, NULL);
745 vod->rv3d->persp= RV3D_PERSP;
747 ED_region_tag_redraw(vod->ar);
750 if (event->type == MOUSEPAN) {
751 viewrotate_apply(vod, event->prevx, event->prevy);
752 request_depth_update(CTX_wm_region_view3d(C));
754 viewops_data_free(C, op);
756 return OPERATOR_FINISHED;
758 else if (event->type == MOUSEROTATE) {
759 /* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
760 viewrotate_apply(vod, event->prevx, event->y);
761 request_depth_update(CTX_wm_region_view3d(C));
763 viewops_data_free(C, op);
765 return OPERATOR_FINISHED;
768 /* add temp handler */
769 WM_event_add_modal_handler(C, op);
771 return OPERATOR_RUNNING_MODAL;
775 static int view3d_camera_active_poll(bContext *C)
777 if(ED_operator_view3d_active(C)) {
778 RegionView3D *rv3d= CTX_wm_region_view3d(C);
779 if(rv3d && rv3d->persp==RV3D_CAMOB) {
787 static int view3d_rotate_poll(bContext *C)
789 if (!ED_operator_view3d_active(C)) {
792 RegionView3D *rv3d= CTX_wm_region_view3d(C);
793 /* rv3d is null in menus, but it's ok when the menu is clicked on */
794 /* XXX of course, this doesn't work with quadview
795 * Maybe having exec return PASSTHROUGH would be better than polling here
796 * Poll functions are full of problems anyway.
798 return rv3d == NULL || rv3d->viewlock == 0;
802 void VIEW3D_OT_rotate(wmOperatorType *ot)
806 ot->name= "Rotate view";
807 ot->description = "Rotate the view";
808 ot->idname= "VIEW3D_OT_rotate";
811 ot->invoke= viewrotate_invoke;
812 ot->modal= viewrotate_modal;
813 ot->poll= view3d_rotate_poll;
816 ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
819 /* ************************ viewmove ******************************** */
822 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
824 /* called in transform_ops.c, on each regeneration of keymaps */
825 void viewmove_modal_keymap(wmKeyConfig *keyconf)
827 static EnumPropertyItem modal_items[] = {
828 {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
830 {VIEWROT_MODAL_SWITCH_ZOOM, "SWITCH_TO_ZOOM", 0, "Switch to Zoom"},
831 {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
833 {0, NULL, 0, NULL, NULL}};
835 wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Move Modal");
837 /* this function is called for each spacetype, only needs to add map once */
840 keymap= WM_modalkeymap_add(keyconf, "View3D Move Modal", modal_items);
842 /* items for modal map */
843 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
844 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
846 /* disabled mode switching for now, can re-implement better, later on
847 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
848 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ZOOM);
849 WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
852 /* assign map to operators */
853 WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
857 static void viewmove_apply(ViewOpsData *vod, int x, int y)
859 if(vod->rv3d->persp==RV3D_CAMOB) {
860 float max= (float)MAX2(vod->ar->winx, vod->ar->winy);
862 vod->rv3d->camdx += (vod->oldx - x)/(max);
863 vod->rv3d->camdy += (vod->oldy - y)/(max);
864 CLAMP(vod->rv3d->camdx, -1.0f, 1.0f);
865 CLAMP(vod->rv3d->camdy, -1.0f, 1.0f);
866 // XXX preview3d_event= 0;
871 window_to_3d_delta(vod->ar, dvec, x-vod->oldx, y-vod->oldy);
872 add_v3_v3(vod->rv3d->ofs, dvec);
874 if(vod->rv3d->viewlock & RV3D_BOXVIEW)
875 view3d_boxview_sync(vod->sa, vod->ar);
881 ED_region_tag_redraw(vod->ar);
885 static int viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
888 ViewOpsData *vod= op->customdata;
889 short event_code= VIEW_PASS;
891 /* execute the events */
892 if(event->type==MOUSEMOVE) {
893 event_code= VIEW_APPLY;
895 else if(event->type==EVT_MODAL_MAP) {
896 switch (event->val) {
897 case VIEW_MODAL_CONFIRM:
898 event_code= VIEW_CONFIRM;
900 case VIEWROT_MODAL_SWITCH_ZOOM:
901 WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL);
902 event_code= VIEW_CONFIRM;
904 case VIEWROT_MODAL_SWITCH_ROTATE:
905 WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
906 event_code= VIEW_CONFIRM;
910 else if(event->type==vod->origkey && event->val==KM_RELEASE) {
911 event_code= VIEW_CONFIRM;
914 if(event_code==VIEW_APPLY) {
915 viewmove_apply(vod, event->x, event->y);
917 else if (event_code==VIEW_CONFIRM) {
918 request_depth_update(CTX_wm_region_view3d(C));
920 viewops_data_free(C, op);
922 return OPERATOR_FINISHED;
925 return OPERATOR_RUNNING_MODAL;
928 static int viewmove_invoke(bContext *C, wmOperator *op, wmEvent *event)
930 /* makes op->customdata */
931 viewops_data_create(C, op, event);
933 if (event->type == MOUSEPAN) {
934 ViewOpsData *vod= op->customdata;
935 viewmove_apply(vod, event->prevx, event->prevy);
936 request_depth_update(CTX_wm_region_view3d(C));
938 viewops_data_free(C, op);
940 return OPERATOR_FINISHED;
943 /* add temp handler */
944 WM_event_add_modal_handler(C, op);
946 return OPERATOR_RUNNING_MODAL;
950 void VIEW3D_OT_move(wmOperatorType *ot)
954 ot->name= "Move view";
955 ot->description = "Move the view";
956 ot->idname= "VIEW3D_OT_move";
959 ot->invoke= viewmove_invoke;
960 ot->modal= viewmove_modal;
961 ot->poll= ED_operator_view3d_active;
964 ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
967 /* ************************ viewzoom ******************************** */
969 /* called in transform_ops.c, on each regeneration of keymaps */
970 void viewzoom_modal_keymap(wmKeyConfig *keyconf)
972 static EnumPropertyItem modal_items[] = {
973 {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
975 {VIEWROT_MODAL_SWITCH_ROTATE, "SWITCH_TO_ROTATE", 0, "Switch to Rotate"},
976 {VIEWROT_MODAL_SWITCH_MOVE, "SWITCH_TO_MOVE", 0, "Switch to Move"},
978 {0, NULL, 0, NULL, NULL}};
980 wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Zoom Modal");
982 /* this function is called for each spacetype, only needs to add map once */
985 keymap= WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items);
987 /* items for modal map */
988 WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM);
989 WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, VIEW_MODAL_CONFIRM);
991 /* disabled mode switching for now, can re-implement better, later on
992 WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
993 WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, VIEWROT_MODAL_SWITCH_ROTATE);
994 WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, VIEWROT_MODAL_SWITCH_MOVE);
997 /* assign map to operators */
998 WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom");
1001 static void view_zoom_mouseloc(ARegion *ar, float dfac, int mx, int my)
1003 RegionView3D *rv3d= ar->regiondata;
1005 if(U.uiflag & USER_ZOOM_TO_MOUSEPOS) {
1010 short vb[2], mouseloc[2];
1012 mouseloc[0]= mx - ar->winrct.xmin;
1013 mouseloc[1]= my - ar->winrct.ymin;
1015 /* find the current window width and height */
1019 negate_v3_v3(tpos, rv3d->ofs);
1021 /* Project cursor position into 3D space */
1022 initgrabz(rv3d, tpos[0], tpos[1], tpos[2]);
1023 window_to_3d_delta(ar, dvec, mouseloc[0]-vb[0]/2, mouseloc[1]-vb[1]/2);
1025 /* Calculate view target position for dolly */
1026 add_v3_v3v3(tvec, tpos, dvec);
1029 /* Offset to target position and dolly */
1030 new_dist = rv3d->dist * dfac;
1032 copy_v3_v3(rv3d->ofs, tvec);
1033 rv3d->dist = new_dist;
1035 /* Calculate final offset */
1036 madd_v3_v3v3fl(rv3d->ofs, tvec, dvec, dfac);
1043 static void viewzoom_apply(ViewOpsData *vod, int x, int y, short viewzoom)
1047 if(viewzoom==USER_ZOOM_CONT) {
1048 double time= PIL_check_seconds_timer();
1049 float time_step= (float)(time - vod->timer_lastdraw);
1052 zfac = 1.0f + (((float)(vod->origx - x + vod->origy - y)/20.0) * time_step);
1053 vod->timer_lastdraw= time;
1055 else if(viewzoom==USER_ZOOM_SCALE) {
1056 int ctr[2], len1, len2;
1057 // method which zooms based on how far you move the mouse
1059 ctr[0] = (vod->ar->winrct.xmax + vod->ar->winrct.xmin)/2;
1060 ctr[1] = (vod->ar->winrct.ymax + vod->ar->winrct.ymin)/2;
1062 len1 = (int)sqrt((ctr[0] - x)*(ctr[0] - x) + (ctr[1] - y)*(ctr[1] - y)) + 5;
1063 len2 = (int)sqrt((ctr[0] - vod->origx)*(ctr[0] - vod->origx) + (ctr[1] - vod->origy)*(ctr[1] - vod->origy)) + 5;
1065 zfac = vod->dist0 * ((float)len2/len1) / vod->rv3d->dist;
1067 else { /* USER_ZOOM_DOLLY */
1070 if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
1071 len1 = (vod->ar->winrct.xmax - x) + 5;
1072 len2 = (vod->ar->winrct.xmax - vod->origx) + 5;
1075 len1 = (vod->ar->winrct.ymax - y) + 5;
1076 len2 = (vod->ar->winrct.ymax - vod->origy) + 5;
1078 if (U.uiflag & USER_ZOOM_INVERT)
1079 SWAP(float, len1, len2);
1081 zfac = vod->dist0 * (2.0*((len2/len1)-1.0) + 1.0) / vod->rv3d->dist;
1084 if(zfac != 1.0 && zfac*vod->rv3d->dist > 0.001*vod->grid &&
1085 zfac*vod->rv3d->dist < 10.0*vod->far)
1086 view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
1089 if ((U.uiflag & USER_ORBIT_ZBUF) && (viewzoom==USER_ZOOM_CONT) && (vod->rv3d->persp==RV3D_PERSP)) {
1090 float upvec[3], mat[3][3];
1092 /* Secret apricot feature, translate the view when in continues mode */
1093 upvec[0] = upvec[1] = 0.0f;
1094 upvec[2] = (vod->dist0 - vod->rv3d->dist) * vod->grid;
1095 vod->rv3d->dist = vod->dist0;
1096 copy_m3_m4(mat, vod->rv3d->viewinv);
1097 mul_m3_v3(mat, upvec);
1098 add_v3_v3(vod->rv3d->ofs, upvec);
1100 /* these limits were in old code too */
1101 if(vod->rv3d->dist<0.001*vod->grid) vod->rv3d->dist= 0.001*vod->grid;
1102 if(vod->rv3d->dist>10.0*vod->far) vod->rv3d->dist=10.0*vod->far;
1105 // XXX if(vod->rv3d->persp==RV3D_ORTHO || vod->rv3d->persp==RV3D_CAMOB) preview3d_event= 0;
1107 if(vod->rv3d->viewlock & RV3D_BOXVIEW)
1108 view3d_boxview_sync(vod->sa, vod->ar);
1110 ED_region_tag_redraw(vod->ar);
1114 static int viewzoom_modal(bContext *C, wmOperator *op, wmEvent *event)
1116 ViewOpsData *vod= op->customdata;
1117 short event_code= VIEW_PASS;
1119 /* execute the events */
1120 if (event->type == TIMER && event->customdata == vod->timer) {
1121 /* continuous zoom */
1122 event_code= VIEW_APPLY;
1124 else if(event->type==MOUSEMOVE) {
1125 event_code= VIEW_APPLY;
1127 else if(event->type==EVT_MODAL_MAP) {
1128 switch (event->val) {
1129 case VIEW_MODAL_CONFIRM:
1130 event_code= VIEW_CONFIRM;
1132 case VIEWROT_MODAL_SWITCH_MOVE:
1133 WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL);
1134 event_code= VIEW_CONFIRM;
1136 case VIEWROT_MODAL_SWITCH_ROTATE:
1137 WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL);
1138 event_code= VIEW_CONFIRM;
1142 else if(event->type==vod->origkey && event->val==KM_RELEASE) {
1143 event_code= VIEW_CONFIRM;
1146 if(event_code==VIEW_APPLY) {
1147 viewzoom_apply(vod, event->x, event->y, U.viewzoom);
1149 else if (event_code==VIEW_CONFIRM) {
1150 request_depth_update(CTX_wm_region_view3d(C));
1151 viewops_data_free(C, op);
1153 return OPERATOR_FINISHED;
1156 return OPERATOR_RUNNING_MODAL;
1159 static int viewzoom_exec(bContext *C, wmOperator *op)
1161 View3D *v3d = CTX_wm_view3d(C);
1162 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1163 int delta= RNA_int_get(op->ptr, "delta");
1164 int mx = RNA_int_get(op->ptr, "mx");
1165 int my = RNA_int_get(op->ptr, "my");
1168 /* this min and max is also in viewmove() */
1169 if(rv3d->persp==RV3D_CAMOB) {
1171 if(rv3d->camzoom<-30) rv3d->camzoom= -30;
1173 else if(rv3d->dist<10.0*v3d->far) {
1174 view_zoom_mouseloc(CTX_wm_region(C), 1.2f, mx, my);
1178 if(rv3d->persp==RV3D_CAMOB) {
1180 if(rv3d->camzoom>600) rv3d->camzoom= 600;
1182 else if(rv3d->dist> 0.001*v3d->grid) {
1183 view_zoom_mouseloc(CTX_wm_region(C), .83333f, mx, my);
1187 if(rv3d->viewlock & RV3D_BOXVIEW)
1188 view3d_boxview_sync(CTX_wm_area(C), CTX_wm_region(C));
1190 request_depth_update(CTX_wm_region_view3d(C));
1191 ED_region_tag_redraw(CTX_wm_region(C));
1193 viewops_data_free(C, op);
1195 return OPERATOR_FINISHED;
1198 static int viewzoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
1200 int delta= RNA_int_get(op->ptr, "delta");
1202 /* if one or the other zoom position aren't set, set from event */
1203 if (!RNA_property_is_set(op->ptr, "mx") || !RNA_property_is_set(op->ptr, "my"))
1205 RNA_int_set(op->ptr, "mx", event->x);
1206 RNA_int_set(op->ptr, "my", event->y);
1210 /* makes op->customdata */
1211 viewops_data_create(C, op, event);
1212 viewzoom_exec(C, op);
1217 /* makes op->customdata */
1218 viewops_data_create(C, op, event);
1220 vod= op->customdata;
1222 if (event->type == MOUSEZOOM) {
1223 if (U.uiflag & USER_ZOOM_INVERT) /* Bypass Zoom invert flag */
1224 SWAP(int, event->x, event->prevx);
1226 if (U.uiflag & USER_ZOOM_DOLLY_HORIZ) {
1227 vod->origx = vod->oldx = event->x;
1228 viewzoom_apply(vod, event->prevx, event->prevy, USER_ZOOM_DOLLY);
1232 /* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
1233 vod->origy = vod->oldy = vod->origy + event->x - event->prevx;
1234 viewzoom_apply(vod, event->prevx, event->prevy, USER_ZOOM_DOLLY);
1236 request_depth_update(CTX_wm_region_view3d(C));
1238 viewops_data_free(C, op);
1239 return OPERATOR_FINISHED;
1242 if(U.viewzoom == USER_ZOOM_CONT) {
1243 /* needs a timer to continue redrawing */
1244 vod->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
1245 vod->timer_lastdraw= PIL_check_seconds_timer();
1248 /* add temp handler */
1249 WM_event_add_modal_handler(C, op);
1251 return OPERATOR_RUNNING_MODAL;
1254 return OPERATOR_FINISHED;
1258 void VIEW3D_OT_zoom(wmOperatorType *ot)
1261 ot->name= "Zoom view";
1262 ot->description = "Zoom in/out in the view";
1263 ot->idname= "VIEW3D_OT_zoom";
1266 ot->invoke= viewzoom_invoke;
1267 ot->exec= viewzoom_exec;
1268 ot->modal= viewzoom_modal;
1269 ot->poll= ED_operator_view3d_active;
1272 ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
1274 RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1275 RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
1276 RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
1279 static int viewhome_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1281 ARegion *ar= CTX_wm_region(C);
1282 View3D *v3d = CTX_wm_view3d(C);
1283 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1284 Scene *scene= CTX_data_scene(C);
1288 int center= RNA_boolean_get(op->ptr, "center");
1290 float size, min[3], max[3], afm[3];
1291 int ok= 1, onedone=0;
1294 min[0]= min[1]= min[2]= 0.0f;
1295 max[0]= max[1]= max[2]= 0.0f;
1297 /* in 2.4x this also move the cursor to (0, 0, 0) (with shift+c). */
1298 curs= give_cursor(scene, v3d);
1299 curs[0]= curs[1]= curs[2]= 0.0;
1302 INIT_MINMAX(min, max);
1305 for(base= scene->base.first; base; base= base->next) {
1306 if(base->lay & v3d->lay) {
1308 minmax_object(base->object, min, max);
1312 ED_region_tag_redraw(ar);
1313 /* TODO - should this be cancel?
1314 * I think no, because we always move the cursor, with or without
1315 * object, but in this case there is no change in the scene,
1316 * only the cursor so I choice a ED_region_tag like
1317 * smooth_view do for the center_cursor.
1320 return OPERATOR_FINISHED;
1323 afm[0]= (max[0]-min[0]);
1324 afm[1]= (max[1]-min[1]);
1325 afm[2]= (max[2]-min[2]);
1326 size= 0.7f*MAX3(afm[0], afm[1], afm[2]);
1327 if(size==0.0) ok= 0;
1334 new_ofs[0]= -(min[0]+max[0])/2.0f;
1335 new_ofs[1]= -(min[1]+max[1])/2.0f;
1336 new_ofs[2]= -(min[2]+max[2])/2.0f;
1338 // correction for window aspect ratio
1339 if(ar->winy>2 && ar->winx>2) {
1340 size= (float)ar->winx/(float)ar->winy;
1341 if(size<1.0) size= 1.0f/size;
1345 if (rv3d->persp==RV3D_CAMOB) {
1346 rv3d->persp= RV3D_PERSP;
1347 smooth_view(C, NULL, v3d->camera, new_ofs, NULL, &new_dist, NULL);
1350 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1353 // XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1355 if(rv3d->viewlock & RV3D_BOXVIEW)
1356 view3d_boxview_copy(CTX_wm_area(C), ar);
1358 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
1360 return OPERATOR_FINISHED;
1363 static int viewhome_poll(bContext *C)
1365 if(ED_operator_view3d_active(C)) {
1366 RegionView3D *rv3d= CTX_wm_region_view3d(C); //XXX, when accessed from a header menu this doesnt work!
1367 if(rv3d && rv3d->persp!=RV3D_CAMOB) {
1375 void VIEW3D_OT_view_all(wmOperatorType *ot)
1378 ot->name= "View All";
1379 ot->description = "View all objects in scene";
1380 ot->idname= "VIEW3D_OT_view_all";
1383 ot->exec= viewhome_exec;
1384 ot->poll= viewhome_poll;
1389 RNA_def_boolean(ot->srna, "center", 0, "Center", "");
1393 static int viewselected_exec(bContext *C, wmOperator *op) /* like a localview without local!, was centerview() in 2.4x */
1395 ARegion *ar= CTX_wm_region(C);
1396 View3D *v3d = CTX_wm_view3d(C);
1397 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1398 Scene *scene= CTX_data_scene(C);
1400 Object *obedit= CTX_data_edit_object(C);
1401 float size, min[3], max[3], afm[3];
1402 int ok=0, ok_dist=1;
1408 INIT_MINMAX(min, max);
1410 if (ob && ob->mode & OB_MODE_WEIGHT_PAINT) {
1411 /* hardcoded exception, we look for the one selected armature */
1412 /* this is weak code this way, we should make a generic active/selection callback interface once... */
1414 for(base=scene->base.first; base; base= base->next) {
1415 if(TESTBASELIB(v3d, base)) {
1416 if(base->object->type==OB_ARMATURE)
1417 if(base->object->mode & OB_MODE_POSE)
1427 ok = minmax_verts(obedit, min, max); /* only selected */
1429 else if(ob && (ob->mode & OB_MODE_POSE)) {
1431 bArmature *arm= ob->data;
1432 bPoseChannel *pchan;
1435 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1436 if(pchan->bone->flag & BONE_SELECTED) {
1437 if(pchan->bone->layer & arm->layer) {
1438 bPoseChannel *pchan_tx= pchan->custom_tx ? pchan->custom_tx : pchan;
1440 mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_head);
1441 DO_MINMAX(vec, min, max);
1442 mul_v3_m4v3(vec, ob->obmat, pchan_tx->pose_tail);
1443 DO_MINMAX(vec, min, max);
1449 else if (paint_facesel_test(ob)) {
1450 ok= minmax_tface(ob, min, max);
1452 else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) {
1453 ok= PE_minmax(scene, min, max);
1456 Base *base= FIRSTBASE;
1458 if(TESTBASE(v3d, base)) {
1460 /* account for duplis */
1461 if (minmax_object_duplis(scene, base->object, min, max)==0)
1462 minmax_object(base->object, min, max); /* use if duplis not found */
1470 if(ok==0) return OPERATOR_FINISHED;
1472 sub_v3_v3v3(afm, max, min);
1473 size= MAX3(afm[0], afm[1], afm[2]);
1475 if(rv3d->persp==RV3D_ORTHO) {
1476 if(size < 0.0001f) { /* if its a sinble point. dont even re-scale */
1480 /* perspective should be a bit farther away to look nice */
1485 if(size <= v3d->near*1.5f) {
1486 size= v3d->near*1.5f;
1490 add_v3_v3v3(new_ofs, min, max);
1491 mul_v3_fl(new_ofs, -0.5f);
1495 /* correction for window aspect ratio */
1496 if(ar->winy>2 && ar->winx>2) {
1497 size= (float)ar->winx/(float)ar->winy;
1498 if(size<1.0f) size= 1.0f/size;
1502 if (rv3d->persp==RV3D_CAMOB) {
1503 rv3d->persp= RV3D_PERSP;
1504 smooth_view(C, v3d->camera, NULL, new_ofs, NULL, &new_dist, NULL);
1507 smooth_view(C, NULL, NULL, new_ofs, NULL, ok_dist ? &new_dist : NULL, NULL);
1510 // XXX BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1511 if(rv3d->viewlock & RV3D_BOXVIEW)
1512 view3d_boxview_copy(CTX_wm_area(C), ar);
1514 return OPERATOR_FINISHED;
1517 void VIEW3D_OT_view_selected(wmOperatorType *ot)
1521 ot->name= "View Selected";
1522 ot->description = "Move the view to the selection center";
1523 ot->idname= "VIEW3D_OT_view_selected";
1526 ot->exec= viewselected_exec;
1527 ot->poll= ED_operator_view3d_active;
1533 static int viewcenter_cursor_exec(bContext *C, wmOperator *op)
1535 View3D *v3d = CTX_wm_view3d(C);
1536 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1537 Scene *scene= CTX_data_scene(C);
1540 /* non camera center */
1542 negate_v3_v3(new_ofs, give_cursor(scene, v3d));
1543 smooth_view(C, NULL, NULL, new_ofs, NULL, NULL, NULL);
1545 if (rv3d->viewlock & RV3D_BOXVIEW)
1546 view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
1549 return OPERATOR_FINISHED;
1552 void VIEW3D_OT_view_center_cursor(wmOperatorType *ot)
1555 ot->name= "Center View to Cursor";
1556 ot->description= "Centers the view so that the cursor is in the middle of the view";
1557 ot->idname= "VIEW3D_OT_view_center_cursor";
1560 ot->exec= viewcenter_cursor_exec;
1561 ot->poll= ED_operator_view3d_active;
1567 static int view3d_center_camera_exec(bContext *C, wmOperator *op) /* was view3d_home() in 2.4x */
1569 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1571 rv3d->camdx= rv3d->camdy= 0.0f;
1573 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, CTX_wm_view3d(C));
1575 return OPERATOR_FINISHED;
1578 void VIEW3D_OT_view_center_camera(wmOperatorType *ot)
1581 ot->name= "View Camera Center";
1582 ot->description = "Center the camera view";
1583 ot->idname= "VIEW3D_OT_view_center_camera";
1586 ot->exec= view3d_center_camera_exec;
1587 ot->poll= view3d_camera_active_poll;
1593 /* ********************* Set render border operator ****************** */
1595 static int render_border_exec(bContext *C, wmOperator *op)
1597 View3D *v3d = CTX_wm_view3d(C);
1598 ARegion *ar= CTX_wm_region(C);
1599 RegionView3D *rv3d= ED_view3d_context_rv3d(C);
1600 Scene *scene= CTX_data_scene(C);
1605 /* get border select values using rna */
1606 rect.xmin= RNA_int_get(op->ptr, "xmin");
1607 rect.ymin= RNA_int_get(op->ptr, "ymin");
1608 rect.xmax= RNA_int_get(op->ptr, "xmax");
1609 rect.ymax= RNA_int_get(op->ptr, "ymax");
1611 /* calculate range */
1612 calc_viewborder(scene, ar, rv3d, v3d, &vb);
1614 scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1615 scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1616 scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1617 scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1619 /* actually set border */
1620 CLAMP(scene->r.border.xmin, 0.0, 1.0);
1621 CLAMP(scene->r.border.ymin, 0.0, 1.0);
1622 CLAMP(scene->r.border.xmax, 0.0, 1.0);
1623 CLAMP(scene->r.border.ymax, 0.0, 1.0);
1625 /* drawing a border surrounding the entire camera view switches off border rendering
1626 * or the border covers no pixels */
1627 if ((scene->r.border.xmin <= 0.0 && scene->r.border.xmax >= 1.0 &&
1628 scene->r.border.ymin <= 0.0 && scene->r.border.ymax >= 1.0) ||
1629 (scene->r.border.xmin == scene->r.border.xmax ||
1630 scene->r.border.ymin == scene->r.border.ymax ))
1632 scene->r.mode &= ~R_BORDER;
1634 scene->r.mode |= R_BORDER;
1637 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS, NULL);
1639 return OPERATOR_FINISHED;
1643 void VIEW3D_OT_render_border(wmOperatorType *ot)
1646 ot->name= "Set Render Border";
1647 ot->description = "Set the boundries of the border render and enables border render ";
1648 ot->idname= "VIEW3D_OT_render_border";
1651 ot->invoke= WM_border_select_invoke;
1652 ot->exec= render_border_exec;
1653 ot->modal= WM_border_select_modal;
1655 ot->poll= view3d_camera_active_poll;
1658 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1661 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1662 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1663 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1664 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1667 /* ********************* Border Zoom operator ****************** */
1669 static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
1671 ARegion *ar= CTX_wm_region(C);
1672 View3D *v3d = CTX_wm_view3d(C);
1673 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1674 Scene *scene= CTX_data_scene(C);
1676 /* Zooms in on a border drawn by the user */
1678 float dvec[3], vb[2], xscale, yscale, scale;
1684 /* ZBuffer depth vars */
1686 float depth, depth_close= FLT_MAX;
1688 double cent[2], p[3];
1691 /* note; otherwise opengl won't work */
1692 view3d_operator_needs_opengl(C);
1694 /* get border select values using rna */
1695 rect.xmin= RNA_int_get(op->ptr, "xmin");
1696 rect.ymin= RNA_int_get(op->ptr, "ymin");
1697 rect.xmax= RNA_int_get(op->ptr, "xmax");
1698 rect.ymax= RNA_int_get(op->ptr, "ymax");
1700 /* Get Z Depths, needed for perspective, nice for ortho */
1701 bgl_get_mats(&mats);
1702 draw_depth(scene, ar, v3d, NULL);
1704 /* force updating */
1707 rv3d->depths->damaged = 1;
1710 view3d_update_depths(ar, v3d);
1712 /* Constrain rect to depth bounds */
1713 if (rect.xmin < 0) rect.xmin = 0;
1714 if (rect.ymin < 0) rect.ymin = 0;
1715 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
1716 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
1718 /* Find the closest Z pixel */
1719 for (xs=rect.xmin; xs < rect.xmax; xs++) {
1720 for (ys=rect.ymin; ys < rect.ymax; ys++) {
1721 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
1722 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
1723 if (depth_close > depth) {
1724 depth_close = depth;
1731 MEM_freeN(rv3d->depths->depths);
1732 rv3d->depths->depths = NULL;
1734 rv3d->depths->damaged = 1;
1736 cent[0] = (((double)rect.xmin)+((double)rect.xmax)) / 2;
1737 cent[1] = (((double)rect.ymin)+((double)rect.ymax)) / 2;
1739 if (rv3d->persp==RV3D_PERSP) {
1742 /* no depths to use, we cant do anything! */
1743 if (depth_close==FLT_MAX){
1744 BKE_report(op->reports, RPT_ERROR, "Depth Too Large");
1745 return OPERATOR_CANCELLED;
1747 /* convert border to 3d coordinates */
1748 if (( !gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) ||
1749 ( !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])))
1750 return OPERATOR_CANCELLED;
1752 dvec[0] = p[0]-p_corner[0];
1753 dvec[1] = p[1]-p_corner[1];
1754 dvec[2] = p[2]-p_corner[2];
1756 new_dist = len_v3(dvec);
1757 if(new_dist <= v3d->near*1.5) new_dist= v3d->near*1.5;
1763 } else { /* othographic */
1764 /* find the current window width and height */
1768 new_dist = rv3d->dist;
1770 /* convert the drawn rectangle into 3d space */
1771 if (depth_close!=FLT_MAX && gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2])) {
1776 /* We cant use the depth, fallback to the old way that dosnt set the center depth */
1777 copy_v3_v3(new_ofs, rv3d->ofs);
1779 initgrabz(rv3d, -new_ofs[0], -new_ofs[1], -new_ofs[2]);
1781 window_to_3d_delta(ar, dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
1782 /* center the view to the center of the rectangle */
1783 sub_v3_v3(new_ofs, dvec);
1786 /* work out the ratios, so that everything selected fits when we zoom */
1787 xscale = ((rect.xmax-rect.xmin)/vb[0]);
1788 yscale = ((rect.ymax-rect.ymin)/vb[1]);
1789 scale = (xscale >= yscale)?xscale:yscale;
1791 /* zoom in as required, or as far as we can go */
1792 new_dist = ((new_dist*scale) >= 0.001*v3d->grid)? new_dist*scale:0.001*v3d->grid;
1795 smooth_view(C, NULL, NULL, new_ofs, NULL, &new_dist, NULL);
1797 if(rv3d->viewlock & RV3D_BOXVIEW)
1798 view3d_boxview_sync(CTX_wm_area(C), ar);
1800 return OPERATOR_FINISHED;
1803 static int view3d_zoom_border_invoke(bContext *C, wmOperator *op, wmEvent *event)
1805 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1807 /* if in camera view do not exec the operator so we do not conflict with set render border*/
1808 if (rv3d->persp != RV3D_CAMOB)
1809 return WM_border_select_invoke(C, op, event);
1811 return OPERATOR_PASS_THROUGH;
1814 void VIEW3D_OT_zoom_border(wmOperatorType *ot)
1818 ot->name= "Border Zoom";
1819 ot->description = "Zoom in the view to the nearest object contained in the border";
1820 ot->idname= "VIEW3D_OT_zoom_border";
1823 ot->invoke= view3d_zoom_border_invoke;
1824 ot->exec= view3d_zoom_border_exec;
1825 ot->modal= WM_border_select_modal;
1827 ot->poll= ED_operator_view3d_active;
1833 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1834 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1835 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1836 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1839 /* ********************* Changing view operator ****************** */
1841 static EnumPropertyItem prop_view_items[] = {
1842 {RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
1843 {RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
1844 {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
1845 {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
1846 {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
1847 {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
1848 {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the active amera"},
1849 {0, NULL, 0, NULL, NULL}};
1852 /* would like to make this a generic function - outside of transform */
1854 static void axis_set_view(bContext *C, float q1, float q2, float q3, float q4, short view, int perspo, int align_active)
1856 View3D *v3d = CTX_wm_view3d(C);
1857 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1860 new_quat[0]= q1; new_quat[1]= q2;
1861 new_quat[2]= q3; new_quat[3]= q4;
1864 /* align to active object */
1865 Object *obact= CTX_data_active_object(C);
1867 /* no active object, ignore this option */
1868 align_active= FALSE;
1871 float obact_quat[4];
1874 /* same as transform manipulator when normal is set */
1875 ED_getTransformOrientationMatrix(C, twmat, TRUE);
1877 mat3_to_quat( obact_quat,twmat);
1878 invert_qt(obact_quat);
1879 mul_qt_qtqt(new_quat, new_quat, obact_quat);
1881 rv3d->view= view= 0;
1885 if(align_active==FALSE) {
1886 /* normal operation */
1887 if(rv3d->viewlock) {
1888 /* only pass on if */
1889 if(rv3d->view==RV3D_VIEW_FRONT && view==RV3D_VIEW_BACK);
1890 else if(rv3d->view==RV3D_VIEW_BACK && view==RV3D_VIEW_FRONT);
1891 else if(rv3d->view==RV3D_VIEW_RIGHT && view==RV3D_VIEW_LEFT);
1892 else if(rv3d->view==RV3D_VIEW_LEFT && view==RV3D_VIEW_RIGHT);
1893 else if(rv3d->view==RV3D_VIEW_BOTTOM && view==RV3D_VIEW_TOP);
1894 else if(rv3d->view==RV3D_VIEW_TOP && view==RV3D_VIEW_BOTTOM);
1901 if(rv3d->viewlock) {
1902 ED_region_tag_redraw(CTX_wm_region(C));
1906 if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1908 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1909 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1911 smooth_view(C, v3d->camera, NULL, rv3d->ofs, new_quat, NULL, NULL);
1915 if (U.uiflag & USER_AUTOPERSP) rv3d->persp= RV3D_ORTHO;
1916 else if(rv3d->persp==RV3D_CAMOB) rv3d->persp= perspo;
1918 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
1923 static int viewnumpad_exec(bContext *C, wmOperator *op)
1925 View3D *v3d = CTX_wm_view3d(C);
1926 RegionView3D *rv3d= CTX_wm_region_view3d(C);
1927 Scene *scene= CTX_data_scene(C);
1928 static int perspo=RV3D_PERSP;
1929 int viewnum, align_active, nextperspo;
1931 viewnum = RNA_enum_get(op->ptr, "type");
1932 align_active = RNA_boolean_get(op->ptr, "align_active");
1935 /* Use this to test if we started out with a camera */
1937 if (rv3d->persp == RV3D_CAMOB) {
1938 nextperspo= rv3d->lpersp;
1944 case RV3D_VIEW_BOTTOM :
1945 axis_set_view(C, 0.0, -1.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1948 case RV3D_VIEW_BACK:
1949 axis_set_view(C, 0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0), viewnum, nextperspo, align_active);
1952 case RV3D_VIEW_LEFT:
1953 axis_set_view(C, 0.5, -0.5, 0.5, 0.5, viewnum, nextperspo, align_active);
1957 axis_set_view(C, 1.0, 0.0, 0.0, 0.0, viewnum, nextperspo, align_active);
1960 case RV3D_VIEW_FRONT:
1961 axis_set_view(C, (float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0, viewnum, nextperspo, align_active);
1964 case RV3D_VIEW_RIGHT:
1965 axis_set_view(C, 0.5, -0.5, -0.5, -0.5, viewnum, nextperspo, align_active);
1968 case RV3D_VIEW_CAMERA:
1969 if(rv3d->viewlock==0) {
1972 if(rv3d->persp != RV3D_CAMOB) {
1975 if (!rv3d->smooth_timer) {
1976 /* store settings of current view before allowing overwriting with camera view
1977 * only if we're not currently in a view transition */
1978 copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
1979 rv3d->lview= rv3d->view;
1980 rv3d->lpersp= rv3d->persp;
1984 if(G.qual==LR_ALTKEY) {
1985 if(oldcamera && is_an_active_object(oldcamera)) {
1986 v3d->camera= oldcamera;
1988 handle_view3d_lock();
1992 /* first get the default camera for the view lock type */
1993 if(v3d->scenelock) {
1994 /* sets the camera view if available */
1995 v3d->camera= scene->camera;
1998 /* use scene camera if one is not set (even though we're unlocked) */
1999 if(v3d->camera==NULL) {
2000 v3d->camera= scene->camera;
2004 /* if the camera isnt found, check a number of options */
2005 if(v3d->camera==NULL && ob && ob->type==OB_CAMERA)
2008 if(v3d->camera==NULL)
2009 v3d->camera= scene_find_camera(scene);
2011 /* couldnt find any useful camera, bail out */
2012 if(v3d->camera==NULL)
2013 return OPERATOR_CANCELLED;
2015 /* important these dont get out of sync for locked scenes */
2017 scene->camera= v3d->camera;
2019 /* finally do snazzy view zooming */
2020 rv3d->persp= RV3D_CAMOB;
2021 smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
2025 /* return to settings of last view */
2026 /* does smooth_view too */
2027 axis_set_view(C, rv3d->lviewquat[0], rv3d->lviewquat[1], rv3d->lviewquat[2], rv3d->lviewquat[3], rv3d->lview, rv3d->lpersp, 0);
2036 if(rv3d->persp != RV3D_CAMOB) perspo= rv3d->persp;
2038 return OPERATOR_FINISHED;
2040 void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
2043 ot->name= "View numpad";
2044 ot->description = "Set the view";
2045 ot->idname= "VIEW3D_OT_viewnumpad";
2048 ot->exec= viewnumpad_exec;
2049 ot->poll= ED_operator_view3d_active;
2054 RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
2055 RNA_def_boolean(ot->srna, "align_active", 0, "Align Active", "Align to the active objects axis");
2058 static EnumPropertyItem prop_view_orbit_items[] = {
2059 {V3D_VIEW_STEPLEFT, "ORBITLEFT", 0, "Orbit Left", "Orbit the view around to the Left"},
2060 {V3D_VIEW_STEPRIGHT, "ORBITRIGHT", 0, "Orbit Right", "Orbit the view around to the Right"},
2061 {V3D_VIEW_STEPUP, "ORBITUP", 0, "Orbit Up", "Orbit the view Up"},
2062 {V3D_VIEW_STEPDOWN, "ORBITDOWN", 0, "Orbit Down", "Orbit the view Down"},
2063 {0, NULL, 0, NULL, NULL}};
2065 static int vieworbit_exec(bContext *C, wmOperator *op)
2067 RegionView3D *rv3d= CTX_wm_region_view3d(C);
2068 float phi, q1[4], new_quat[4];
2071 orbitdir = RNA_enum_get(op->ptr, "type");
2073 if(rv3d->viewlock==0) {
2075 if(rv3d->persp != RV3D_CAMOB) {
2076 if(orbitdir == V3D_VIEW_STEPLEFT || orbitdir == V3D_VIEW_STEPRIGHT) {
2079 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
2080 if(orbitdir == V3D_VIEW_STEPRIGHT) phi= -phi;
2081 si= (float)sin(phi);
2082 q1[0]= (float)cos(phi);
2085 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
2088 else if(orbitdir == V3D_VIEW_STEPDOWN || orbitdir == V3D_VIEW_STEPUP) {
2089 /* horizontal axis */
2090 copy_v3_v3(q1+1, rv3d->viewinv[0]);
2093 phi= (float)(M_PI/360.0)*U.pad_rot_angle;
2094 if(orbitdir == V3D_VIEW_STEPDOWN) phi= -phi;
2095 q1[0]= (float)cos(phi);
2096 mul_v3_fl(q1+1, sin(phi));
2097 mul_qt_qtqt(new_quat, rv3d->viewquat, q1);
2101 smooth_view(C, NULL, NULL, NULL, new_quat, NULL, NULL);
2105 return OPERATOR_FINISHED;
2108 void VIEW3D_OT_view_orbit(wmOperatorType *ot)
2111 ot->name= "View Orbit";
2112 ot->description = "Orbit the view";
2113 ot->idname= "VIEW3D_OT_view_orbit";
2116 ot->exec= vieworbit_exec;
2117 ot->poll= view3d_rotate_poll;
2121 RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
2124 static EnumPropertyItem prop_view_pan_items[] = {
2125 {V3D_VIEW_PANLEFT, "PANLEFT", 0, "Pan Left", "Pan the view to the Left"},
2126 {V3D_VIEW_PANRIGHT, "PANRIGHT", 0, "Pan Right", "Pan the view to the Right"},
2127 {V3D_VIEW_PANUP, "PANUP", 0, "Pan Up", "Pan the view Up"},
2128 {V3D_VIEW_PANDOWN, "PANDOWN", 0, "Pan Down", "Pan the view Down"},
2129 {0, NULL, 0, NULL, NULL}};
2131 static int viewpan_exec(bContext *C, wmOperator *op)
2133 ARegion *ar= CTX_wm_region(C);
2134 RegionView3D *rv3d= CTX_wm_region_view3d(C);
2138 pandir = RNA_enum_get(op->ptr, "type");
2140 initgrabz(rv3d, 0.0, 0.0, 0.0);
2142 if(pandir == V3D_VIEW_PANRIGHT) window_to_3d_delta(ar, vec, -32, 0);
2143 else if(pandir == V3D_VIEW_PANLEFT) window_to_3d_delta(ar, vec, 32, 0);
2144 else if(pandir == V3D_VIEW_PANUP) window_to_3d_delta(ar, vec, 0, -25);
2145 else if(pandir == V3D_VIEW_PANDOWN) window_to_3d_delta(ar, vec, 0, 25);
2146 rv3d->ofs[0]+= vec[0];
2147 rv3d->ofs[1]+= vec[1];
2148 rv3d->ofs[2]+= vec[2];
2150 if(rv3d->viewlock & RV3D_BOXVIEW)
2151 view3d_boxview_sync(CTX_wm_area(C), ar);
2153 ED_region_tag_redraw(ar);
2155 return OPERATOR_FINISHED;
2158 void VIEW3D_OT_view_pan(wmOperatorType *ot)
2161 ot->name= "View Pan";
2162 ot->description = "Pan the view";
2163 ot->idname= "VIEW3D_OT_view_pan";
2166 ot->exec= viewpan_exec;
2167 ot->poll= ED_operator_view3d_active;
2171 RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
2174 static int viewpersportho_exec(bContext *C, wmOperator *op)
2176 ARegion *ar= CTX_wm_region(C);
2177 RegionView3D *rv3d= CTX_wm_region_view3d(C);
2179 if(rv3d->viewlock==0) {
2180 if(rv3d->persp!=RV3D_ORTHO)
2181 rv3d->persp=RV3D_ORTHO;
2182 else rv3d->persp=RV3D_PERSP;
2183 ED_region_tag_redraw(ar);
2186 return OPERATOR_FINISHED;
2190 void VIEW3D_OT_view_persportho(wmOperatorType *ot)
2193 ot->name= "View Persp/Ortho";
2194 ot->description = "Switch the current view from perspective/orthographic";
2195 ot->idname= "VIEW3D_OT_view_persportho";
2198 ot->exec= viewpersportho_exec;
2199 ot->poll= ED_operator_view3d_active;
2205 /* ******************** add background image operator **************** */
2207 static int add_background_image_exec(bContext *C, wmOperator *op)
2209 View3D *v3d= CTX_wm_view3d(C);
2211 BGpic *bgpic= MEM_callocN(sizeof(BGpic), "Background Image");
2214 bgpic->iuser.fie_ima= 2;
2216 bgpic->view= 0; /* 0 for all */
2218 BLI_addtail(&v3d->bgpicbase, bgpic);
2220 //ED_region_tag_redraw(v3d);
2222 return OPERATOR_FINISHED;
2225 static int add_background_image_invoke(bContext *C, wmOperator *op, wmEvent *event)
2227 return add_background_image_exec(C, op);
2230 void VIEW3D_OT_add_background_image(wmOperatorType *ot)
2233 ot->name = "Add Background Image";
2234 ot->description= "Add a new background image";
2235 ot->idname = "VIEW3D_OT_add_background_image";
2238 ot->invoke = add_background_image_invoke;
2239 ot->exec = add_background_image_exec;
2240 ot->poll = ED_operator_view3d_active;
2246 /* ***** remove image operator ******* */
2247 static int remove_background_image_exec(bContext *C, wmOperator *op)
2249 BGpic *bgpic_rem = CTX_data_pointer_get_type(C, "bgpic", &RNA_BackgroundImage).data;
2250 View3D *vd = CTX_wm_view3d(C);
2251 int index = RNA_int_get(op->ptr, "index");
2253 bgpic_rem = BLI_findlink(&vd->bgpicbase, index);
2255 BLI_remlink(&vd->bgpicbase, bgpic_rem);
2256 if(bgpic_rem->ima) bgpic_rem->ima->id.us--;
2257 MEM_freeN(bgpic_rem);
2260 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, vd);
2262 return OPERATOR_FINISHED;
2265 void VIEW3D_OT_remove_background_image(wmOperatorType *ot)
2268 ot->name = "Remove Background Image";
2269 ot->description= "Remove a background image from the 3D view";
2270 ot->idname = "VIEW3D_OT_remove_background_image";
2273 ot->exec = remove_background_image_exec;
2274 ot->poll = ED_operator_view3d_active;
2279 RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "Background image index to remove ", 0, INT_MAX);
2281 /* ********************* set clipping operator ****************** */
2283 static void calc_clipping_plane(float clip[6][4], BoundBox *clipbb)
2287 for(val=0; val<4; val++) {
2289 normal_tri_v3( clip[val],clipbb->vec[val], clipbb->vec[val==3?0:val+1], clipbb->vec[val+4]);
2292 - clip[val][0]*clipbb->vec[val][0]
2293 - clip[val][1]*clipbb->vec[val][1]
2294 - clip[val][2]*clipbb->vec[val][2];
2298 static void calc_local_clipping(float clip_local[][4], BoundBox *clipbb, float mat[][4])
2300 BoundBox clipbb_local;
2304 invert_m4_m4(imat, mat);
2306 for(i=0; i<8; i++) {
2307 mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
2310 calc_clipping_plane(clip_local, &clipbb_local);
2313 void ED_view3d_local_clipping(RegionView3D *rv3d, float mat[][4])
2315 if(rv3d->rflag & RV3D_CLIPPING)
2316 calc_local_clipping(rv3d->clip_local, rv3d->clipbb, mat);
2319 static int view3d_clipping_exec(bContext *C, wmOperator *op)
2321 RegionView3D *rv3d= CTX_wm_region_view3d(C);
2326 rect.xmin= RNA_int_get(op->ptr, "xmin");
2327 rect.ymin= RNA_int_get(op->ptr, "ymin");
2328 rect.xmax= RNA_int_get(op->ptr, "xmax");
2329 rect.ymax= RNA_int_get(op->ptr, "ymax");
2331 rv3d->rflag |= RV3D_CLIPPING;
2332 rv3d->clipbb= MEM_callocN(sizeof(BoundBox), "clipbb");
2334 /* note; otherwise opengl won't work */
2335 view3d_operator_needs_opengl(C);
2337 view3d_set_viewcontext(C, &vc);
2338 view3d_get_transformation(vc.ar, vc.rv3d, NULL, &mats); /* NULL because we don't want it in object space */
2339 view3d_calculate_clipping(rv3d->clipbb, rv3d->clip, &mats, &rect);
2341 return OPERATOR_FINISHED;
2344 static int view3d_clipping_invoke(bContext *C, wmOperator *op, wmEvent *event)
2346 RegionView3D *rv3d= CTX_wm_region_view3d(C);
2347 ARegion *ar= CTX_wm_region(C);
2349 if(rv3d->rflag & RV3D_CLIPPING) {
2350 rv3d->rflag &= ~RV3D_CLIPPING;
2351 ED_region_tag_redraw(ar);
2352 if(rv3d->clipbb) MEM_freeN(rv3d->clipbb);
2354 return OPERATOR_FINISHED;
2357 return WM_border_select_invoke(C, op, event);
2362 void VIEW3D_OT_clip_border(wmOperatorType *ot)
2366 ot->name= "Clipping Border";
2367 ot->description = "Set the view clipping border";
2368 ot->idname= "VIEW3D_OT_clip_border";
2371 ot->invoke= view3d_clipping_invoke;
2372 ot->exec= view3d_clipping_exec;
2373 ot->modal= WM_border_select_modal;
2375 ot->poll= ED_operator_view3d_active;
2381 RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2382 RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2383 RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2384 RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2387 /* ***************** 3d cursor cursor op ******************* */
2389 /* mx my in region coords */
2390 static int set_3dcursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
2392 Scene *scene= CTX_data_scene(C);
2393 ARegion *ar= CTX_wm_region(C);
2394 View3D *v3d = CTX_wm_view3d(C);
2395 RegionView3D *rv3d= CTX_wm_region_view3d(C);
2396 float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
2397 short mx, my, mval[2];
2398 // short ctrl= 0; // XXX
2400 fp= give_cursor(scene, v3d);
2402 // if(obedit && ctrl) lr_click= 1;
2403 copy_v3_v3(oldcurs, fp);
2405 mx= event->x - ar->winrct.xmin;
2406 my= event->y - ar->winrct.ymin;
2408 project_short_noclip(ar, fp, mval);
2409 flip= initgrabz(rv3d, fp[0], fp[1], fp[2]);
2411 /* reset the depth based on the view offset */
2413 negate_v3_v3(fp, rv3d->ofs);
2416 project_short_noclip(ar, fp, mval);
2417 flip= initgrabz(rv3d, fp[0], fp[1], fp[2]);
2420 if(mval[0]!=IS_CLIPPED) {
2421 short depth_used = 0;
2423 if (U.uiflag & USER_ORBIT_ZBUF) { /* maybe this should be accessed some other way */
2424 short mval_depth[2] = {mx, my};
2425 view3d_operator_needs_opengl(C);
2426 if (view_autodist(scene, ar, v3d, mval_depth, fp))
2431 window_to_3d_delta(ar, dvec, mval[0]-mx, mval[1]-my);
2432 sub_v3_v3(fp, dvec);
2437 dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
2438 dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
2440 fz= rv3d->persmat[0][3]*fp[0]+ rv3d->persmat[1][3]*fp[1]+ rv3d->persmat[2][3]*fp[2]+ rv3d->persmat[3][3];
2443 fp[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
2444 fp[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
2445 fp[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
2448 if(v3d && v3d->localvd)
2449 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2451 WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene);
2453 return OPERATOR_FINISHED;
2456 void VIEW3D_OT_cursor3d(wmOperatorType *ot)
2460 ot->name= "Set 3D Cursor";
2461 ot->description = "Set the location of the 3D cursor";
2462 ot->idname= "VIEW3D_OT_cursor3d";
2465 ot->invoke= set_3dcursor_invoke;
2467 ot->poll= ED_operator_view3d_active;
2470 // ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2476 /* ***************** manipulator op ******************* */
2479 static int manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2481 View3D *v3d = CTX_wm_view3d(C);
2483 if(!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2484 if(!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH;
2486 /* only no modifier or shift */
2487 if(event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH;
2489 /* note; otherwise opengl won't work */
2490 view3d_operator_needs_opengl(C);
2492 if(0==BIF_do_manipulator(C, event, op))
2493 return OPERATOR_PASS_THROUGH;
2495 return OPERATOR_FINISHED;
2498 void VIEW3D_OT_manipulator(wmOperatorType *ot)
2502 ot->name= "3D Manipulator";
2503 ot->description = "Manipulate selected item by axis";
2504 ot->idname= "VIEW3D_OT_manipulator";
2507 ot->invoke= manipulator_invoke;
2509 ot->poll= ED_operator_view3d_active;
2511 /* properties to pass to transform */
2512 Transform_Properties(ot, P_CONSTRAINT);
2515 static int enable_manipulator_invoke(bContext *C, wmOperator *op, wmEvent *event)
2517 View3D *v3d = CTX_wm_view3d(C);
2521 if (RNA_boolean_get(op->ptr, "translate"))
2522 v3d->twtype |= V3D_MANIP_TRANSLATE;
2523 if (RNA_boolean_get(op->ptr, "rotate"))
2524 v3d->twtype |= V3D_MANIP_ROTATE;
2525 if (RNA_boolean_get(op->ptr, "scale"))
2526 v3d->twtype |= V3D_MANIP_SCALE;
2528 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
2530 return OPERATOR_FINISHED;
2533 void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
2536 ot->name= "Enable 3D Manipulator";
2537 ot->description = "Enable the transform manipulator for use";
2538 ot->idname= "VIEW3D_OT_enable_manipulator";
2541 ot->invoke= enable_manipulator_invoke;
2542 ot->poll= ED_operator_view3d_active;
2545 RNA_def_boolean(ot->srna, "translate", 0, "Translate", "Enable the translate manipulator");
2546 RNA_def_boolean(ot->srna, "rotate", 0, "Rotate", "Enable the rotate manipulator");
2547 RNA_def_boolean(ot->srna, "scale", 0, "Scale", "Enable the scale manipulator");
2550 /* ************************* below the line! *********************** */
2553 static float view_autodist_depth_margin(ARegion *ar, short *mval, int margin)
2555 RegionView3D *rv3d= ar->regiondata;
2556 float depth= FLT_MAX;
2559 if (mval[0] < 0) return 0;
2560 if (mval[1] < 0) return 0;
2561 if (mval[0] >= rv3d->depths->w) return 0;
2562 if (mval[1] >= rv3d->depths->h) return 0;
2564 /* Get Z Depths, needed for perspective, nice for ortho */
2565 depth= rv3d->depths->depths[mval[1]*rv3d->depths->w+mval[0]];
2566 if(depth >= rv3d->depths->depth_range[1] || depth <= rv3d->depths->depth_range[0]) {
2572 float depth_close= FLT_MAX;
2575 rect.xmax = mval[0] + margin;
2576 rect.ymax = mval[1] + margin;
2578 rect.xmin = mval[0] - margin;
2579 rect.ymin = mval[1] - margin;
2581 /* Constrain rect to depth bounds */
2582 if (rect.xmin < 0) rect.xmin = 0;
2583 if (rect.ymin < 0) rect.ymin = 0;
2584 if (rect.xmax >= rv3d->depths->w) rect.xmax = rv3d->depths->w-1;
2585 if (rect.ymax >= rv3d->depths->h) rect.ymax = rv3d->depths->h-1;
2587 /* Find the closest Z pixel */
2588 for (xs=rect.xmin; xs < rect.xmax; xs++) {
2589 for (ys=rect.ymin; ys < rect.ymax; ys++) {
2590 depth= rv3d->depths->depths[ys*rv3d->depths->w+xs];
2591 if(depth < rv3d->depths->depth_range[1] && depth > rv3d->depths->depth_range[0]) {
2592 if (depth_close > depth) {
2593 depth_close = depth;
2605 /* XXX todo Zooms in on a border drawn by the user */
2606 int view_autodist(Scene *scene, ARegion *ar, View3D *v3d, short *mval, float mouse_worldloc[3] ) //, float *autodist )
2608 RegionView3D *rv3d= ar->regiondata;
2609 bglMats mats; /* ZBuffer depth vars */
2610 float depth_close= FLT_MAX;
2612 double cent[2], p[3];
2614 /* Get Z Depths, needed for perspective, nice for ortho */
2615 bgl_get_mats(&mats);
2616 draw_depth(scene, ar, v3d, NULL);
2618 /* force updating */
2621 rv3d->depths->damaged = 1;
2624 view3d_update_depths(ar, v3d);
2626 depth_close= view_autodist_depth_margin(ar, mval, 4);
2628 if (depth_close==FLT_MAX)
2632 MEM_freeN(rv3d->depths->depths);
2633 rv3d->depths->depths = NULL;
2635 rv3d->depths->damaged = 1;
2637 cent[0] = (double)mval[0];
2638 cent[1] = (double)mval[1];
2640 if (!gluUnProject(cent[0], cent[1], depth_close, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2643 mouse_worldloc[0] = (float)p[0];
2644 mouse_worldloc[1] = (float)p[1];
2645 mouse_worldloc[2] = (float)p[2];
2649 int view_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode) //, float *autodist )
2651 RegionView3D *rv3d= ar->regiondata;
2653 /* Get Z Depths, needed for perspective, nice for ortho */
2656 draw_depth(scene, ar, v3d, NULL);
2659 draw_depth_gpencil(scene, ar, v3d);
2663 /* force updating */
2665 rv3d->depths->damaged = 1;
2668 view3d_update_depths(ar, v3d);
2672 // no 4x4 sampling, run view_autodist_init first
2673 int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3], int margin, float *force_depth) //, float *autodist )
2675 bglMats mats; /* ZBuffer depth vars, could cache? */
2677 double cent[2], p[3];
2679 /* Get Z Depths, needed for perspective, nice for ortho */
2681 depth= *force_depth;
2683 depth= view_autodist_depth_margin(ar, mval, margin);
2688 cent[0] = (double)mval[0];
2689 cent[1] = (double)mval[1];
2691 bgl_get_mats(&mats);
2692 if (!gluUnProject(cent[0], cent[1], depth, mats.modelview, mats.projection, (GLint *)mats.viewport, &p[0], &p[1], &p[2]))
2695 mouse_worldloc[0] = (float)p[0];
2696 mouse_worldloc[1] = (float)p[1];
2697 mouse_worldloc[2] = (float)p[2];
2701 int view_autodist_depth(struct ARegion *ar, short *mval, int margin, float *depth)
2703 *depth= view_autodist_depth_margin(ar, mval, margin);
2705 return (*depth==FLT_MAX) ? 0:1;
2709 /* ********************* NDOF ************************ */
2710 /* note: this code is confusing and unclear... (ton) */
2711 /* **************************************************** */
2713 // ndof scaling will be moved to user setting.
2714 // In the mean time this is just a place holder.
2716 // Note: scaling in the plugin and ghostwinlay.c
2717 // should be removed. With driver default setting,
2718 // each axis returns approx. +-200 max deflection.
2720 // The values I selected are based on the older
2721 // polling i/f. With event i/f, the sensistivity
2722 // can be increased for improved response from
2723 // small deflections of the device input.
2726 // lukep notes : i disagree on the range.
2727 // the normal 3Dconnection driver give +/-400
2728 // on defaut range in other applications
2729 // and up to +/- 1000 if set to maximum
2730 // because i remove the scaling by delta,
2731 // which was a bad idea as it depend of the system
2732 // speed and os, i changed the scaling values, but
2733 // those are still not ok
2736 float ndof_axis_scale[6] = {
2745 void filterNDOFvalues(float *sbval)
2751 if (fabs(sbval[i]) > max)
2752 max = fabs(sbval[i]);
2754 if (fabs(sbval[i]) != max )
2758 // statics for controlling rv3d->dist corrections.
2759 // viewmoveNDOF zeros and adjusts rv3d->ofs.
2760 // viewmove restores based on dz_flag state.
2765 void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int mode)
2767 RegionView3D *rv3d= ar->regiondata;
2771 // static fval[6] for low pass filter; device input vector is dval[6]
2772 static float fval[6];
2773 float tvec[3],rvec[3];
2779 /*----------------------------------------------------
2780 * sometimes this routine is called from headerbuttons
2781 * viewmove needs to refresh the screen
2783 // XXX areawinset(ar->win);
2786 // fetch the current state of the ndof device
2787 // XXX getndof(dval);
2789 if (v3d->ndoffilter)
2790 filterNDOFvalues(fval);
2792 // Scale input values
2794 // if(dval[6] == 0) return; // guard against divide by zero
2799 dval[i] = dval[i] * ndof_axis_scale[i];
2803 // low pass filter with zero crossing reset
2806 if((dval[i] * fval[i]) >= 0)
2807 dval[i] = (fval[i] * 15 + dval[i]) / 16;
2813 // force perspective mode. This is a hack and is
2814 // incomplete. It doesn't actually effect the view
2815 // until the first draw and doesn't update the menu
2816 // to reflect persp mode.
2818 rv3d->persp = RV3D_PERSP;
2821 // Correct the distance jump if rv3d->dist != 0
2823 // This is due to a side effect of the original
2824 // mouse view rotation code. The rotation point is
2825 // set a distance in front of the viewport to
2826 // make rotating with the mouse look better.
2827 // The distance effect is written at a low level
2828 // in the view management instead of the mouse
2829 // view function. This means that all other view
2830 // movement devices must subtract this from their
2831 // view transformations.
2833 if(rv3d->dist != 0.0) {
2835 m_dist = rv3d->dist;
2836 upvec[0] = upvec[1] = 0;
2837 upvec[2] = rv3d->dist;
2838 copy_m3_m4(mat, rv3d->viewinv);
2839 mul_m3_v3(mat, upvec);
2840 sub_v3_v3(rv3d->ofs, upvec);
2846 // Rotations feel relatively faster than translations only in fly mode, so
2847 // we have no choice but to fix that here (not in the plugins)
2848 rvec[0] = -0.5 * dval[3];
2849 rvec[1] = -0.5 * dval[4];
2850 rvec[2] = -0.5 * dval[5];
2852 // rotate device x and y by view z
2854 copy_m3_m4(mat, rv3d->viewinv);
2856 mul_m3_v3(mat, rvec);
2860 phi = normalize_v3(rvec);
2862 axis_angle_to_quat(q1,rvec,phi);
2863 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
2867 // Apply translation
2873 // the next three lines rotate the x and y translation coordinates
2874 // by the current z axis angle
2876 copy_m3_m4(mat, rv3d->viewinv);
2878 mul_m3_v3(mat, tvec);
2880 // translate the view
2882 sub_v3_v3(rv3d->ofs, tvec);
2885 /*----------------------------------------------------
2886 * refresh the screen XXX
2889 // update render preview window
2891 // XXX BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
2894 void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int mode)
2896 RegionView3D *rv3d= ar->regiondata;
2899 float sbadjust = 1.0f;
2905 float xvec[3] = {1,0,0};
2906 float yvec[3] = {0,-1,0};
2907 float zvec[3] = {0,0,1};
2913 float d, curareaX, curareaY;
2917 /* Sensitivity will control how fast the view rotates. The value was
2918 * obtained experimentally by tweaking until the author didn't get dizzy watching.
2919 * Perhaps this should be a configurable user parameter.
2921 float psens = 0.005f * (float) U.ndof_pan; /* pan sensitivity */
2922 float rsens = 0.005f * (float) U.ndof_rotate; /* rotate sensitivity */
2923 float zsens = 0.3f; /* zoom sensitivity */
2925 const float minZoom = -30.0f;
2926 const float maxZoom = 300.0f;
2930 //printf("passing here \n");
2932 if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
2936 if((dz_flag)||rv3d->dist==0) {
2938 rv3d->dist = m_dist;
2939 upvec[0] = upvec[1] = 0;
2940 upvec[2] = rv3d->dist;
2941 copy_m3_m4(mat, rv3d->viewinv);
2942 mul_m3_v3(mat, upvec);
2943 add_v3_v3(rv3d->ofs, upvec);
2946 /*----------------------------------------------------
2947 * sometimes this routine is called from headerbuttons
2948 * viewmove needs to refresh the screen
2950 // XXX areawinset(curarea->win);
2952 /*----------------------------------------------------
2953 * record how much time has passed. clamp at 10 Hz
2954 * pretend the previous frame occurred at the clamped time
2956 // now = PIL_check_seconds_timer();
2957 // frametime = (now - prevTime);
2958 // if (frametime > 0.1f){ /* if more than 1/10s */
2959 // frametime = 1.0f/60.0; /* clamp at 1/60s so no jumps when starting to move */
2962 // sbadjust *= 60 * frametime; /* normalize ndof device adjustments to 100Hz for framerate independence */
2964 /* fetch the current state of the ndof device & enforce dominant mode if selected */
2965 // XXX getndof(fval);
2966 if (v3d->ndoffilter)
2967 filterNDOFvalues(fval);
2970 // put scaling back here, was previously in ghostwinlay
2971 fval[0] = fval[0] * (1.0f/600.0f);
2972 fval[1] = fval[1] * (1.0f/600.0f);
2973 fval[2] = fval[2] * (1.0f/1100.0f);
2974 fval[3] = fval[3] * 0.00005f;
2975 fval[4] =-fval[4] * 0.00005f;
2976 fval[5] = fval[5] * 0.00005f;
2977 fval[6] = fval[6] / 1000000.0f;
2979 // scale more if not in perspective mode
2980 if (rv3d->persp == RV3D_ORTHO) {
2981 fval[0] = fval[0] * 0.05f;
2982 fval[1] = fval[1] * 0.05f;
2983 fval[2] = fval[2] * 0.05f;
2984 fval[3] = fval[3] * 0.9f;
2985 fval[4] = fval[4] * 0.9f;
2986 fval[5] = fval[5] * 0.9f;
2990 /* set object offset */
2992 obofs[0] = -ob->obmat[3][0];
2993 obofs[1] = -ob->obmat[3][1];
2994 obofs[2] = -ob->obmat[3][2];
2997 copy_v3_v3(obofs, rv3d->ofs);
3000 /* calc an adjustment based on distance from camera
3001 disabled per patch 14402 */
3005 sub_v3_v3v3(diff, obofs, rv3d->ofs);
3010 reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
3012 /*----------------------------------------------------
3016 curareaX = sbadjust * psens * fval[0];
3017 curareaY = sbadjust * psens * fval[1];
3018 dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
3019 dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
3020 dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
3021 add_v3_v3(rv3d->ofs, dvec);
3023 /*----------------------------------------------------
3026 len = zsens * sbadjust * fval[2];
3028 if (rv3d->persp==RV3D_CAMOB) {
3029 if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
3030 rv3d->camzoom+= 10.0f * -len;
3032 if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
3033 else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
3035 else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
3036 rv3d->dist*=(1.0 + len);
3040 /*----------------------------------------------------
3041 * ndof device turntable
3042 * derived from the turntable code in viewmove
3045 /* Get the 3x3 matrix and its inverse from the quaternion */
3046 quat_to_mat3( m,rv3d->viewquat);
3047 invert_m3_m3(m_inv,m);
3049 /* Determine the direction of the x vector (for rotating up and down) */
3050 /* This can likely be compuated directly from the quaternion. */
3051 mul_m3_v3(m_inv,xvec);
3052 mul_m3_v3(m_inv,yvec);
3053 mul_m3_v3(m_inv,zvec);
3055 /* Perform the up/down rotation */
3056 phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
3058 mul_v3_v3fl(q1+1, xvec, sin(phi));
3059 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
3062 conjugate_qt(q1); /* conj == inv for unit quat */
3063 sub_v3_v3(rv3d->ofs, obofs);
3064 mul_qt_v3(q1, rv3d->ofs);
3065 add_v3_v3(rv3d->ofs, obofs);
3068 /* Perform the orbital rotation */
3069 /* Perform the orbital rotation
3070 If the seen Up axis is parallel to the zoom axis, rotation should be
3071 achieved with a pure Roll motion (no Spin) on the device. When you start
3072 to tilt, moving from Top to Side view, Spinning will increasingly become
3073 more relevant while the Roll component will decrease. When a full
3074 Side view is reached, rotations around the world's Up axis are achieved
3075 with a pure Spin-only motion. In other words the control of the spinning
3076 around the world's Up axis should move from the device's Spin axis to the
3077 device's Roll axis depending on the orientation of the world's Up axis
3078 relative to the screen. */
3079 //phi = sbadjust * rsens * reverse * fval[4]; /* spin the knob, y axis */
3080 phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
3082 q1[1] = q1[2] = 0.0;
3084 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
3088 sub_v3_v3(rv3d->ofs, obofs);
3089 mul_qt_v3(q1, rv3d->ofs);
3090 add_v3_v3(rv3d->ofs, obofs);
3093 /*----------------------------------------------------
3094 * refresh the screen
3096 // XXX scrarea_do_windraw(curarea);