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 flyApply(bContext *C, FlyInfo *fly) { #define FLY_ROTATE_FAC 2.5f /* 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 */ /* fly mode - Shift+F * a fly loop where the user can move move the view as if they are flying */ RegionView3D *rv3d = fly->rv3d; ARegion *ar = fly->ar; 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 thast added to the view offset per redraw */ /* Camera Uprighting variables */ float upvec[3] = {0, 0, 0}; /* stores the view's up vector */ float moffset[2]; /* mouse offset from the views center */ float tmp_quat[4]; /* used for rotating the view */ // int cent_orig[2], /* view center */ //XXX- can avoid using // cent[2], /* view center modified */ 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 = ar->winx / 20.0f; ymargin = ar->winy / 20.0f; // UNUSED // cent_orig[0] = ar->winrct.xmin + ar->winx / 2; // cent_orig[1] = ar->winrct.ymin + ar->winy / 2; { /* mouse offset from the center */ moffset[0] = fly->mval[0] - ar->winx / 2; moffset[1] = fly->mval[1] - ar->winy / 2; /* 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] /= ar->winx - (xmargin * 2); moffset[0] *= fabsf(moffset[0]); } if (moffset[1]) { moffset[1] /= ar->winy - (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 */ dvec_tmp[0] = -moffset[0]; dvec_tmp[1] = -moffset[1]; dvec_tmp[2] = 0; 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]) { upvec[0] = 1; upvec[1] = 0; upvec[2] = 0; mul_m3_v3(mat, upvec); /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, (float)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]) { /* if we're upside down invert the moffset */ upvec[0] = 0.0f; upvec[1] = 1.0f; upvec[2] = 0.0f; mul_m3_v3(mat, upvec); if (upvec[2] < 0.0f) moffset[0] = -moffset[0]; /* make the lock vectors */ if (fly->zlock) { upvec[0] = 0.0f; upvec[1] = 0.0f; upvec[2] = 1.0f; } else { upvec[0] = 0.0f; upvec[1] = 1.0f; upvec[2] = 0.0f; mul_m3_v3(mat, upvec); } /* Rotate about the relative up vec */ axis_angle_to_quat(tmp_quat, upvec, (float)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) { upvec[0] = 1.0f; upvec[1] = 0.0f; upvec[2] = 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; upvec[0] = 0.0f; /* rotate the view about this axis */ upvec[1] = 0.0f; upvec[2] = 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) { upvec[0] = 0; upvec[1] = 0; upvec[2] = 1; mul_m3_v3(mat, upvec); /* make sure we have some z rolling */ if (fabsf(upvec[2]) > 0.00001f) { roll = upvec[2] * -5.0f; upvec[0] = 1.0f; /* rotate the view about this axis */ upvec[1] = 0.0f; upvec[2] = 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 * 5.0f)))); if (rv3d->persp == RV3D_CAMOB) { Object *lock_ob = fly->root_parent ? fly->root_parent : fly->v3d->camera; 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, rv3d, 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; }
static int flyApply_ndof(bContext *C, FlyInfo *fly) { /* shorthand for oft-used variables */ wmNDOFMotionData *ndof = fly->ndof; const float dt = ndof->dt; RegionView3D *rv3d = fly->rv3d; const int flag = U.ndof_flag; #if 0 bool do_rotate = (flag & NDOF_SHOULD_ROTATE) && (fly->pan_view == false); bool do_translate = (flag & (NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM)); #endif bool do_rotate = (fly->pan_view == false); 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 (fly->use_precision) 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 = fly->root_parent ? fly->root_parent : fly->v3d->camera; 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 (fly->use_precision) 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_FLY_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) { fly->redraw = true; if (rv3d->persp == RV3D_CAMOB) { flyMoveCamera(C, rv3d, fly, do_rotate, do_translate); } } return OPERATOR_FINISHED; }