static void drawWalkPixel(const struct bContext *UNUSED(C), ARegion *ar, void *arg) { /* draws an aim/cross in the center */ WalkInfo *walk = arg; const int outter_length = 24; const int inner_length = 14; int xoff, yoff; rctf viewborder; if (ED_view3d_cameracontrol_object_get(walk->v3d_camera_control)) { ED_view3d_calc_camera_border( walk->scene, walk->depsgraph, ar, walk->v3d, walk->rv3d, &viewborder, false); xoff = viewborder.xmin + BLI_rctf_size_x(&viewborder) * 0.5f; yoff = viewborder.ymin + BLI_rctf_size_y(&viewborder) * 0.5f; } else { xoff = walk->ar->winx / 2; yoff = walk->ar->winy / 2; } GPUVertFormat *format = immVertexFormat(); uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); immUniformThemeColor(TH_VIEW_OVERLAY); immBegin(GPU_PRIM_LINES, 8); /* North */ immVertex2i(pos, xoff, yoff + inner_length); immVertex2i(pos, xoff, yoff + outter_length); /* East */ immVertex2i(pos, xoff + inner_length, yoff); immVertex2i(pos, xoff + outter_length, yoff); /* South */ immVertex2i(pos, xoff, yoff - inner_length); immVertex2i(pos, xoff, yoff - outter_length); /* West */ immVertex2i(pos, xoff - inner_length, yoff); immVertex2i(pos, xoff - outter_length, yoff); immEnd(); immUnbindProgram(); }
static int fly_modal(bContext *C, wmOperator *op, const wmEvent *event) { int exit_code; bool do_draw = false; FlyInfo *fly = op->customdata; RegionView3D *rv3d = fly->rv3d; Object *fly_object = ED_view3d_cameracontrol_object_get(fly->v3d_camera_control); fly->redraw = 0; flyEvent(C, op, fly, event); #ifdef WITH_INPUT_NDOF if (fly->ndof) { /* 3D mouse overrules [2D mouse + timer] */ if (event->type == NDOF_MOTION) { flyApply_ndof(C, fly); } } else #endif /* WITH_INPUT_NDOF */ if (event->type == TIMER && event->customdata == fly->timer) { flyApply(C, fly); } do_draw |= fly->redraw; exit_code = flyEnd(C, fly); if (exit_code != OPERATOR_RUNNING_MODAL) do_draw = true; if (do_draw) { if (rv3d->persp == RV3D_CAMOB) { WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, fly_object); } // puts("redraw!"); // too frequent, commented with NDOF_FLY_DRAW_TOOMUCH for now ED_region_tag_redraw(CTX_wm_region(C)); } if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) ED_area_headerprint(CTX_wm_area(C), NULL); return exit_code; }
static void walkApply_ndof(bContext *C, WalkInfo *walk) { Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control); bool has_translate, has_rotate; view3d_ndof_fly(walk->ndof, walk->v3d, walk->rv3d, walk->is_slow, lock_ob ? lock_ob->protectflag : 0, &has_translate, &has_rotate); if (has_translate || has_rotate) { walk->redraw = true; if (walk->rv3d->persp == RV3D_CAMOB) { walkMoveCamera(C, walk, has_rotate, has_translate); } } }
static void flyApply_ndof(bContext *C, FlyInfo *fly) { Object *lock_ob = ED_view3d_cameracontrol_object_get(fly->v3d_camera_control); bool has_translate, has_rotate; view3d_ndof_fly(fly->ndof, fly->v3d, fly->rv3d, fly->use_precision, lock_ob ? lock_ob->protectflag : 0, &has_translate, &has_rotate); if (has_translate || has_rotate) { fly->redraw = true; if (fly->rv3d->persp == RV3D_CAMOB) { flyMoveCamera(C, fly, has_rotate, has_translate); } } }
static int walk_modal(bContext *C, wmOperator *op, const wmEvent *event) { int exit_code; bool do_draw = false; WalkInfo *walk = op->customdata; RegionView3D *rv3d = walk->rv3d; Object *walk_object = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control); walk->redraw = false; walkEvent(C, op, walk, event); if (walk->ndof) { /* 3D mouse overrules [2D mouse + timer] */ if (event->type == NDOF_MOTION) { walkApply_ndof(C, walk); } } else if (event->type == TIMER && event->customdata == walk->timer) { walkApply(C, op, walk); } do_draw |= walk->redraw; exit_code = walkEnd(C, walk); if (exit_code != OPERATOR_RUNNING_MODAL) do_draw = true; if (do_draw) { if (rv3d->persp == RV3D_CAMOB) { WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, walk_object); } // puts("redraw!"); // too frequent, commented with NDOF_WALK_DRAW_TOOMUCH for now ED_region_tag_redraw(CTX_wm_region(C)); } if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) ED_area_headerprint(CTX_wm_area(C), NULL); return exit_code; }
static int walkApply(bContext *C, wmOperator *op, WalkInfo *walk) { #define WALK_ROTATE_FAC 2.2f /* more is faster */ #define WALK_TOP_LIMIT DEG2RADF(85.0f) #define WALK_BOTTOM_LIMIT DEG2RADF(-80.0f) #define WALK_MOVE_SPEED base_speed #define WALK_BOOST_FACTOR ((void)0, walk->speed_factor) /* walk mode - Ctrl+Shift+F * a walk loop where the user can move move the view as if they are in a walk game */ RegionView3D *rv3d = walk->rv3d; ARegion *ar = walk->ar; float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */ float dvec[3] = {0.0f, 0.0f, 0.0f}; /* this is the direction that's added to the view offset per redraw */ /* Camera Uprighting variables */ float upvec[3] = {0.0f, 0.0f, 0.0f}; /* stores the view's up vector */ int moffset[2]; /* mouse offset from the views center */ float tmp_quat[4]; /* used for rotating the view */ #ifdef NDOF_WALK_DEBUG { static unsigned int iteration = 1; printf("walk timer %d\n", iteration++); } #endif { /* mouse offset from the center */ copy_v2_v2_int(moffset, walk->moffset); /* apply moffset so we can re-accumulate */ walk->moffset[0] = 0; walk->moffset[1] = 0; /* revert mouse */ if (walk->is_reversed) { moffset[1] = -moffset[1]; } /* Should we redraw? */ if ((walk->active_directions) || moffset[0] || moffset[1] || walk->teleport.state == WALK_TELEPORT_STATE_ON || walk->gravity_state != WALK_GRAVITY_STATE_OFF) { float dvec_tmp[3]; /* time how fast it takes for us to redraw, * this is so simple scenes don't walk too fast */ double time_current; float time_redraw; #ifdef NDOF_WALK_DRAW_TOOMUCH walk->redraw = 1; #endif time_current = PIL_check_seconds_timer(); time_redraw = (float)(time_current - walk->time_lastdraw); walk->time_lastdraw = time_current; /* base speed in m/s */ walk->speed = WALK_MOVE_SPEED; if (walk->is_fast) { walk->speed *= WALK_BOOST_FACTOR; } else if (walk->is_slow) { walk->speed *= 1.0f / WALK_BOOST_FACTOR; } copy_m3_m4(mat, rv3d->viewinv); { /* rotate about the X axis- look up/down */ if (moffset[1]) { float angle; float y; /* relative offset */ y = (float) moffset[1] / ar->winy; /* speed factor */ y *= WALK_ROTATE_FAC; /* user adjustement factor */ y *= walk->mouse_speed; /* clamp the angle limits */ /* it ranges from 90.0f to -90.0f */ angle = -asinf(rv3d->viewmat[2][2]); if (angle > WALK_TOP_LIMIT && y > 0.0f) y = 0.0f; else if (angle < WALK_BOTTOM_LIMIT && y < 0.0f) y = 0.0f; copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, -y); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); } /* rotate about the Y axis- look left/right */ if (moffset[0]) { float x; /* if we're upside down invert the moffset */ copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f); mul_m3_v3(mat, upvec); if (upvec[2] < 0.0f) moffset[0] = -moffset[0]; /* relative offset */ x = (float) moffset[0] / ar->winx; /* speed factor */ x *= WALK_ROTATE_FAC; /* user adjustement factor */ x *= walk->mouse_speed; copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); /* Rotate about the relative up vec */ axis_angle_normalized_to_quat(tmp_quat, upvec, x); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); } } /* WASD - 'move' translation code */ if ((walk->active_directions) && (walk->gravity_state == WALK_GRAVITY_STATE_OFF)) { short direction; zero_v3(dvec); if ((walk->active_directions & WALK_BIT_FORWARD) || (walk->active_directions & WALK_BIT_BACKWARD)) { direction = 0; if ((walk->active_directions & WALK_BIT_FORWARD)) direction += 1; if ((walk->active_directions & WALK_BIT_BACKWARD)) direction -= 1; copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction); mul_m3_v3(mat, dvec_tmp); if (walk->navigation_mode == WALK_MODE_GRAVITY) { dvec_tmp[2] = 0.0f; } normalize_v3(dvec_tmp); add_v3_v3(dvec, dvec_tmp); } if ((walk->active_directions & WALK_BIT_LEFT) || (walk->active_directions & WALK_BIT_RIGHT)) { direction = 0; if ((walk->active_directions & WALK_BIT_LEFT)) direction += 1; if ((walk->active_directions & WALK_BIT_RIGHT)) direction -= 1; dvec_tmp[0] = direction * rv3d->viewinv[0][0]; dvec_tmp[1] = direction * rv3d->viewinv[0][1]; dvec_tmp[2] = 0.0f; normalize_v3(dvec_tmp); add_v3_v3(dvec, dvec_tmp); } if ((walk->active_directions & WALK_BIT_UP) || (walk->active_directions & WALK_BIT_DOWN)) { if (walk->navigation_mode == WALK_MODE_FREE) { direction = 0; if ((walk->active_directions & WALK_BIT_UP)) direction -= 1; if ((walk->active_directions & WALK_BIT_DOWN)) direction = 1; copy_v3_fl3(dvec_tmp, 0.0f, 0.0f, direction); add_v3_v3(dvec, dvec_tmp); } } /* apply movement */ mul_v3_fl(dvec, walk->speed * time_redraw); } /* stick to the floor */ if (walk->navigation_mode == WALK_MODE_GRAVITY && ELEM(walk->gravity_state, WALK_GRAVITY_STATE_OFF, WALK_GRAVITY_STATE_START)) { bool ret; float ray_distance; float difference = -100.0f; float fall_distance; ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance); if (ret) { difference = walk->view_height - ray_distance; } /* the distance we would fall naturally smoothly enough that we * can manually drop the object without activating gravity */ fall_distance = time_redraw * walk->speed * WALK_BOOST_FACTOR; if (fabsf(difference) < fall_distance) { /* slope/stairs */ dvec[2] -= difference; /* in case we switched from FREE to GRAVITY too close to the ground */ if (walk->gravity_state == WALK_GRAVITY_STATE_START) walk->gravity_state = WALK_GRAVITY_STATE_OFF; } else { /* hijack the teleport variables */ walk->teleport.initial_time = PIL_check_seconds_timer(); walk->gravity_state = WALK_GRAVITY_STATE_ON; walk->teleport.duration = 0.0f; copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]); copy_v2_v2(walk->teleport.direction, dvec); } } /* Falling or jumping) */ if (ELEM(walk->gravity_state, WALK_GRAVITY_STATE_ON, WALK_GRAVITY_STATE_JUMP)) { float t; float z_cur, z_new; bool ret; float ray_distance, difference = -100.0f; /* delta time */ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time); /* keep moving if we were moving */ copy_v2_v2(dvec, walk->teleport.direction); z_cur = walk->rv3d->viewinv[3][2]; z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid; /* jump */ z_new += t * walk->speed_jump * walk->grid; /* duration is the jump duration */ if (t > walk->teleport.duration) { /* check to see if we are landing */ ret = walk_floor_distance_get(C, rv3d, walk, dvec, &ray_distance); if (ret) { difference = walk->view_height - ray_distance; } if (difference > 0.0f) { /* quit falling, lands at "view_height" from the floor */ dvec[2] -= difference; walk->gravity_state = WALK_GRAVITY_STATE_OFF; walk->speed_jump = 0.0f; } else { /* keep falling */ dvec[2] = z_cur - z_new; } } else { /* keep going up (jump) */ dvec[2] = z_cur - z_new; } } /* Teleport */ else if (walk->teleport.state == WALK_TELEPORT_STATE_ON) { float t; /* factor */ float new_loc[3]; float cur_loc[3]; /* linear interpolation */ t = (float)(PIL_check_seconds_timer() - walk->teleport.initial_time); t /= walk->teleport.duration; /* clamp so we don't go past our limit */ if (t >= 1.0f) { t = 1.0f; walk->teleport.state = WALK_TELEPORT_STATE_OFF; walk_navigation_mode_set(C, op, walk, walk->teleport.navigation_mode); } mul_v3_v3fl(new_loc, walk->teleport.direction, t); add_v3_v3(new_loc, walk->teleport.origin); copy_v3_v3(cur_loc, walk->rv3d->viewinv[3]); sub_v3_v3v3(dvec, cur_loc, new_loc); } if (rv3d->persp == RV3D_CAMOB) { Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control); if (lock_ob->protectflag & OB_LOCK_LOCX) dvec[0] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCY) dvec[1] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCZ) dvec[2] = 0.0f; } /* scale the movement to the scene size */ mul_v3_v3fl(dvec_tmp, dvec, walk->grid); add_v3_v3(rv3d->ofs, dvec_tmp); if (rv3d->persp == RV3D_CAMOB) { const bool do_rotate = (moffset[0] || moffset[1]); const bool do_translate = (walk->speed != 0.0f); walkMoveCamera(C, walk, do_rotate, do_translate); } } else { /* we're not redrawing but we need to update the time else the view will jump */ walk->time_lastdraw = PIL_check_seconds_timer(); } /* end drawing */ copy_v3_v3(walk->dvec_prev, dvec); } return OPERATOR_FINISHED; #undef WALK_ROTATE_FAC #undef WALK_ZUP_CORRECT_FAC #undef WALK_ZUP_CORRECT_ACCEL #undef WALK_SMOOTH_FAC #undef WALK_TOP_LIMIT #undef WALK_BOTTOM_LIMIT #undef WALK_MOVE_SPEED #undef WALK_BOOST_FACTOR }
static int walkApply_ndof(bContext *C, WalkInfo *walk) { /* shorthand for oft-used variables */ wmNDOFMotionData *ndof = walk->ndof; const float dt = ndof->dt; RegionView3D *rv3d = walk->rv3d; const int flag = U.ndof_flag; #if 0 bool do_rotate = (flag & NDOF_SHOULD_ROTATE) && (walk->pan_view == false); bool do_translate = (flag & (NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM)) != 0; #endif bool do_rotate = true; bool do_translate = true; float view_inv[4]; invert_qt_qt(view_inv, rv3d->viewquat); rv3d->rot_angle = 0.0f; /* disable onscreen rotation doo-dad */ if (do_translate) { const float forward_sensitivity = 1.0f; const float vertical_sensitivity = 0.4f; const float lateral_sensitivity = 0.6f; float speed = 10.0f; /* blender units per second */ /* ^^ this is ok for default cube scene, but should scale with.. something */ float trans[3] = {lateral_sensitivity * ndof->tvec[0], vertical_sensitivity * ndof->tvec[1], forward_sensitivity * ndof->tvec[2]}; if (walk->is_slow) speed *= 0.2f; mul_v3_fl(trans, speed * dt); /* transform motion from view to world coordinates */ mul_qt_v3(view_inv, trans); if (flag & NDOF_FLY_HELICOPTER) { /* replace world z component with device y (yes it makes sense) */ trans[2] = speed * dt * vertical_sensitivity * ndof->tvec[1]; } if (rv3d->persp == RV3D_CAMOB) { /* respect camera position locks */ Object *lock_ob = ED_view3d_cameracontrol_object_get(walk->v3d_camera_control); if (lock_ob->protectflag & OB_LOCK_LOCX) trans[0] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCY) trans[1] = 0.0f; if (lock_ob->protectflag & OB_LOCK_LOCZ) trans[2] = 0.0f; } if (!is_zero_v3(trans)) { /* move center of view opposite of hand motion (this is camera mode, not object mode) */ sub_v3_v3(rv3d->ofs, trans); do_translate = true; } else { do_translate = false; } } if (do_rotate) { const float turn_sensitivity = 1.0f; float rotation[4]; float axis[3]; float angle = turn_sensitivity * ndof_to_axis_angle(ndof, axis); if (fabsf(angle) > 0.0001f) { do_rotate = true; if (walk->is_slow) angle *= 0.2f; /* transform rotation axis from view to world coordinates */ mul_qt_v3(view_inv, axis); /* apply rotation to view */ axis_angle_to_quat(rotation, axis, angle); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); if (flag & NDOF_LOCK_HORIZON) { /* force an upright viewpoint * TODO: make this less... sudden */ float view_horizon[3] = {1.0f, 0.0f, 0.0f}; /* view +x */ float view_direction[3] = {0.0f, 0.0f, -1.0f}; /* view -z (into screen) */ /* find new inverse since viewquat has changed */ invert_qt_qt(view_inv, rv3d->viewquat); /* could apply reverse rotation to existing view_inv to save a few cycles */ /* transform view vectors to world coordinates */ mul_qt_v3(view_inv, view_horizon); mul_qt_v3(view_inv, view_direction); /* find difference between view & world horizons * true horizon lives in world xy plane, so look only at difference in z */ angle = -asinf(view_horizon[2]); #ifdef NDOF_WALK_DEBUG printf("lock horizon: adjusting %.1f degrees\n\n", RAD2DEG(angle)); #endif /* rotate view so view horizon = world horizon */ axis_angle_to_quat(rotation, view_direction, angle); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation); } rv3d->view = RV3D_VIEW_USER; } else { do_rotate = false; } } if (do_translate || do_rotate) { walk->redraw = true; if (rv3d->persp == RV3D_CAMOB) { walkMoveCamera(C, walk, do_rotate, do_translate); } } return OPERATOR_FINISHED; }
static int flyApply(bContext *C, FlyInfo *fly) { #define FLY_ROTATE_FAC 10.0f /* more is faster */ #define FLY_ZUP_CORRECT_FAC 0.1f /* amount to correct per step */ #define FLY_ZUP_CORRECT_ACCEL 0.05f /* increase upright momentum each step */ #define FLY_SMOOTH_FAC 20.0f /* higher value less lag */ /* fly mode - Shift+F * a fly loop where the user can move move the view as if they are flying */ RegionView3D *rv3d = fly->rv3d; float mat[3][3]; /* 3x3 copy of the view matrix so we can move along the view axis */ float dvec[3] = {0, 0, 0}; /* this is the direction that's added to the view offset per redraw */ /* Camera Uprighting variables */ float moffset[2]; /* mouse offset from the views center */ float tmp_quat[4]; /* used for rotating the view */ int xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */ #ifdef NDOF_FLY_DEBUG { static unsigned int iteration = 1; printf("fly timer %d\n", iteration++); } #endif xmargin = fly->width / 20.0f; ymargin = fly->height / 20.0f; { /* mouse offset from the center */ moffset[0] = fly->mval[0] - fly->center_mval[0]; moffset[1] = fly->mval[1] - fly->center_mval[1]; /* enforce a view margin */ if (moffset[0] > xmargin) moffset[0] -= xmargin; else if (moffset[0] < -xmargin) moffset[0] += xmargin; else moffset[0] = 0; if (moffset[1] > ymargin) moffset[1] -= ymargin; else if (moffset[1] < -ymargin) moffset[1] += ymargin; else moffset[1] = 0; /* scale the mouse movement by this value - scales mouse movement to the view size * moffset[0] / (ar->winx-xmargin * 2) - window size minus margin (same for y) * * the mouse moves isn't linear */ if (moffset[0]) { moffset[0] /= fly->width - (xmargin * 2); moffset[0] *= fabsf(moffset[0]); } if (moffset[1]) { moffset[1] /= fly->height - (ymargin * 2); moffset[1] *= fabsf(moffset[1]); } /* Should we redraw? */ if ((fly->speed != 0.0f) || moffset[0] || moffset[1] || (fly->zlock != FLY_AXISLOCK_STATE_OFF) || (fly->xlock != FLY_AXISLOCK_STATE_OFF) || dvec[0] || dvec[1] || dvec[2]) { float dvec_tmp[3]; /* time how fast it takes for us to redraw, * this is so simple scenes don't fly too fast */ double time_current; float time_redraw; float time_redraw_clamped; #ifdef NDOF_FLY_DRAW_TOOMUCH fly->redraw = 1; #endif time_current = PIL_check_seconds_timer(); time_redraw = (float)(time_current - fly->time_lastdraw); time_redraw_clamped = min_ff(0.05f, time_redraw); /* clamp redraw time to avoid jitter in roll correction */ fly->time_lastdraw = time_current; /* Scale the time to use shift to scale the speed down- just like * shift slows many other areas of blender down */ if (fly->use_precision) fly->speed = fly->speed * (1.0f - time_redraw_clamped); copy_m3_m4(mat, rv3d->viewinv); if (fly->pan_view == true) { /* pan only */ copy_v3_fl3(dvec_tmp, -moffset[0], -moffset[1], 0.0f); if (fly->use_precision) { dvec_tmp[0] *= 0.1f; dvec_tmp[1] *= 0.1f; } mul_m3_v3(mat, dvec_tmp); mul_v3_fl(dvec_tmp, time_redraw * 200.0f * fly->grid); } else { float roll; /* similar to the angle between the camera's up and the Z-up, * but its very rough so just roll */ /* rotate about the X axis- look up/down */ if (moffset[1]) { float upvec[3]; copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, moffset[1] * time_redraw * -FLY_ROTATE_FAC); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); if (fly->xlock != FLY_AXISLOCK_STATE_OFF) fly->xlock = FLY_AXISLOCK_STATE_ACTIVE; /* check for rotation */ if (fly->zlock != FLY_AXISLOCK_STATE_OFF) fly->zlock = FLY_AXISLOCK_STATE_ACTIVE; fly->xlock_momentum = 0.0f; } /* rotate about the Y axis- look left/right */ if (moffset[0]) { float upvec[3]; /* if we're upside down invert the moffset */ copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f); mul_m3_v3(mat, upvec); if (upvec[2] < 0.0f) moffset[0] = -moffset[0]; /* make the lock vectors */ if (fly->zlock) { copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); } else { copy_v3_fl3(upvec, 0.0f, 1.0f, 0.0f); mul_m3_v3(mat, upvec); } /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, moffset[0] * time_redraw * FLY_ROTATE_FAC); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); if (fly->xlock != FLY_AXISLOCK_STATE_OFF) fly->xlock = FLY_AXISLOCK_STATE_ACTIVE; /* check for rotation */ if (fly->zlock != FLY_AXISLOCK_STATE_OFF) fly->zlock = FLY_AXISLOCK_STATE_ACTIVE; } if (fly->zlock == FLY_AXISLOCK_STATE_ACTIVE) { float upvec[3]; copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); mul_m3_v3(mat, upvec); /* make sure we have some z rolling */ if (fabsf(upvec[2]) > 0.00001f) { roll = upvec[2] * 5.0f; /* rotate the view about this axis */ copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, roll * time_redraw_clamped * fly->zlock_momentum * FLY_ZUP_CORRECT_FAC); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); fly->zlock_momentum += FLY_ZUP_CORRECT_ACCEL; } else { fly->zlock = FLY_AXISLOCK_STATE_IDLE; /* don't check until the view rotates again */ fly->zlock_momentum = 0.0f; } } /* only apply xcorrect when mouse isn't applying x rot */ if (fly->xlock == FLY_AXISLOCK_STATE_ACTIVE && moffset[1] == 0) { float upvec[3]; copy_v3_fl3(upvec, 0.0f, 0.0f, 1.0f); mul_m3_v3(mat, upvec); /* make sure we have some z rolling */ if (fabsf(upvec[2]) > 0.00001f) { roll = upvec[2] * -5.0f; /* rotate the view about this axis */ copy_v3_fl3(upvec, 1.0f, 0.0f, 0.0f); mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, roll * time_redraw_clamped * fly->xlock_momentum * 0.1f); mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat); fly->xlock_momentum += 0.05f; } else { fly->xlock = FLY_AXISLOCK_STATE_IDLE; /* see above */ fly->xlock_momentum = 0.0f; } } if (fly->axis == -1) { /* pause */ zero_v3(dvec_tmp); } else if (!fly->use_freelook) { /* Normal operation */ /* define dvec, view direction vector */ zero_v3(dvec_tmp); /* move along the current axis */ dvec_tmp[fly->axis] = 1.0f; mul_m3_v3(mat, dvec_tmp); } else { normalize_v3_v3(dvec_tmp, fly->dvec_prev); if (fly->speed < 0.0f) { negate_v3(dvec_tmp); } } mul_v3_fl(dvec_tmp, fly->speed * time_redraw * 0.25f); } /* impose a directional lag */ interp_v3_v3v3(dvec, dvec_tmp, fly->dvec_prev, (1.0f / (1.0f + (time_redraw * FLY_SMOOTH_FAC)))); if (rv3d->persp == RV3D_CAMOB) { Object *lock_ob = ED_view3d_cameracontrol_object_get(fly->v3d_camera_control); if (lock_ob->protectflag & OB_LOCK_LOCX) dvec[0] = 0.0; if (lock_ob->protectflag & OB_LOCK_LOCY) dvec[1] = 0.0; if (lock_ob->protectflag & OB_LOCK_LOCZ) dvec[2] = 0.0; } add_v3_v3(rv3d->ofs, dvec); if (rv3d->persp == RV3D_CAMOB) { const bool do_rotate = ((fly->xlock != FLY_AXISLOCK_STATE_OFF) || (fly->zlock != FLY_AXISLOCK_STATE_OFF) || ((moffset[0] || moffset[1]) && !fly->pan_view)); const bool do_translate = (fly->speed != 0.0f || fly->pan_view); flyMoveCamera(C, fly, do_rotate, do_translate); } } else { /* we're not redrawing but we need to update the time else the view will jump */ fly->time_lastdraw = PIL_check_seconds_timer(); } /* end drawing */ copy_v3_v3(fly->dvec_prev, dvec); } return OPERATOR_FINISHED; }