Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/ghost/GHOST_Types.h24
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp96
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.h9
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c182
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c149
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h3
-rw-r--r--source/blender/windowmanager/WM_types.h27
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c2
8 files changed, 361 insertions, 131 deletions
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index bc731a43ae7..85f73a25b47 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -434,14 +434,24 @@ typedef struct {
GHOST_TUns8 **strings;
} GHOST_TStringArray;
+typedef enum {
+ GHOST_kNotStarted,
+ GHOST_kStarting,
+ GHOST_kInProgress,
+ GHOST_kFinishing,
+ GHOST_kFinished
+ } GHOST_TProgress;
+
typedef struct {
- /** N-degree of freedom device data v3 [GSoC 2010]*/
- /* Each component normally ranges from -1 to +1, but can exceed that. */
- float tx, ty, tz; /* translation: -x left, +y forward, -z up */
- float rx, ry, rz; /* rotation:
- axis = (rx,ry,rz).normalized
- amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg] */
- float dt; // time since previous NDOF Motion event (or zero if this is the first)
+ /** N-degree of freedom device data v3 [GSoC 2010] */
+ // Each component normally ranges from -1 to +1, but can exceed that.
+ // These use blender standard view coordinates, with positive rotations being CCW about the axis.
+ float tx, ty, tz; // translation
+ float rx, ry, rz; // rotation:
+ // axis = (rx,ry,rz).normalized
+ // amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg]
+ float dt; // time since previous NDOF Motion event
+ GHOST_TProgress progress; // Starting, InProgress or Finishing (for modal handlers)
} GHOST_TEventNDOFMotionData;
typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction;
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index 4d2f06f8191..e001540aa95 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -29,6 +29,12 @@
#include <stdio.h> // for error/info reporting
#include <math.h>
+#ifdef DEBUG_NDOF_MOTION
+// printable version of each GHOST_TProgress value
+static const char* progress_string[] =
+ {"not started","starting","in progress","finishing","finished"};
+#endif
+
#ifdef DEBUG_NDOF_BUTTONS
static const char* ndof_button_names[] = {
// used internally, never sent
@@ -139,9 +145,10 @@ GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System& sys)
, m_buttonCount(0)
, m_buttonMask(0)
, m_buttons(0)
- , m_motionTime(1000) // one full second (operators should filter out such large time deltas)
+ , m_motionTime(0)
, m_prevMotionTime(0)
- , m_atRest(true)
+ , m_motionState(GHOST_kNotStarted)
+ , m_motionEventPending(false)
{
// to avoid the rare situation where one triple is updated and
// the other is not, initialize them both here:
@@ -179,10 +186,16 @@ void GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
break;
// -- older devices --
- case 0xC623: puts("ndof: SpaceTraveler not supported, please file a bug report"); break;
- // no buttons?
- case 0xC625: puts("ndof: SpacePilot not supported, please file a bug report"); break;
- // 21 buttons
+ // keep unknown device type so rogue button events will get discarded
+ // "mystery device" owners can help build another HID_map for their hardware
+ case 0xC623:
+ puts("ndof: SpaceTraveler not supported, please file a bug report");
+ m_buttonCount = 8;
+ break;
+ case 0xC625:
+ puts("ndof: SpacePilot not supported, please file a bug report");
+ m_buttonCount = 21;
+ break;
default: printf("ndof: unknown Logitech product %04hx\n", product_id);
}
@@ -198,18 +211,41 @@ void GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short produ
#endif
}
+void GHOST_NDOFManager::updateMotionState()
+ {
+ if (m_motionEventPending)
+ return;
+
+ switch (m_motionState)
+ {
+ case GHOST_kFinished:
+ case GHOST_kNotStarted:
+ m_motionState = GHOST_kStarting;
+ break;
+ case GHOST_kStarting:
+ m_motionState = GHOST_kInProgress;
+ break;
+ default:
+ // InProgress remains InProgress
+ // should never be Finishing
+ break;
+ }
+
+ m_motionEventPending = true;
+ }
+
void GHOST_NDOFManager::updateTranslation(short t[3], GHOST_TUns64 time)
{
memcpy(m_translation, t, sizeof(m_translation));
m_motionTime = time;
- m_atRest = false;
+ updateMotionState();
}
void GHOST_NDOFManager::updateRotation(short r[3], GHOST_TUns64 time)
{
memcpy(m_rotation, r, sizeof(m_rotation));
m_motionTime = time;
- m_atRest = false;
+ updateMotionState();
}
void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, bool press, GHOST_TUns64 time, GHOST_IWindow* window)
@@ -290,7 +326,7 @@ void GHOST_NDOFManager::updateButtons(int button_bits, GHOST_TUns64 time)
int diff = m_buttons ^ button_bits;
- for (int button_number = 0; button_number <= 31; ++button_number)
+ for (int button_number = 0; button_number < m_buttonCount; ++button_number)
{
int mask = 1 << button_number;
@@ -302,15 +338,21 @@ void GHOST_NDOFManager::updateButtons(int button_bits, GHOST_TUns64 time)
}
}
-static bool atHomePosition(GHOST_TEventNDOFMotionData* ndof, float threshold)
+static bool atHomePosition(GHOST_TEventNDOFMotionData* ndof)
{
- #define HOME(foo) (fabsf(ndof->foo) < threshold)
+ #define HOME(foo) (ndof->foo == 0)
return HOME(tx) && HOME(ty) && HOME(tz) && HOME(rx) && HOME(ry) && HOME(rz);
}
+static bool nearHomePosition(GHOST_TEventNDOFMotionData* ndof, float threshold)
+ {
+ #define HOME1(foo) (fabsf(ndof->foo) < threshold)
+ return HOME1(tx) && HOME1(ty) && HOME1(tz) && HOME1(rx) && HOME1(ry) && HOME1(rz);
+ }
+
bool GHOST_NDOFManager::sendMotionEvent()
{
- if (m_atRest)
+ if (m_motionState == GHOST_kFinished || m_motionState == GHOST_kNotStarted)
return false;
GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow();
@@ -320,7 +362,7 @@ bool GHOST_NDOFManager::sendMotionEvent()
const float scale = 1.f / 350.f; // 3Dconnexion devices send +/- 350 usually
- // possible future enhancement
+ // probable future enhancement
// scale *= m_sensitivity;
data->tx = scale * m_translation[0];
@@ -331,19 +373,35 @@ bool GHOST_NDOFManager::sendMotionEvent()
data->ry = scale * m_rotation[1];
data->rz = scale * m_rotation[2];
- data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds
+ if (m_motionState == GHOST_kStarting)
+ // prev motion time will be ancient, so just make up something reasonable
+ data->dt = 0.0125f;
+ else
+ data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds
m_prevMotionTime = m_motionTime;
+ // 'at rest' test goes at the end so that the first 'rest' event gets sent
+ if (atHomePosition(data))
+// if (nearHomePosition(data, 0.05f)) // Linux & Windows have trouble w/ calibration
+ {
+ data->progress = GHOST_kFinishing;
+ // for internal state, skip Finishing & jump to Finished
+ m_motionState = GHOST_kFinished;
+ }
+ else
+ data->progress = m_motionState; // Starting or InProgress
+
#ifdef DEBUG_NDOF_MOTION
- printf("ndof: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f\n",
- data->tx, data->ty, data->tz, data->rx, data->ry, data->rz, data->dt);
+ printf("ndof %s: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f\n",
+ progress_string[data->progress],
+ data->tx, data->ty, data->tz,
+ data->rx, data->ry, data->rz,
+ data->dt);
#endif
m_system.pushEvent(event);
-
- // 'at rest' test goes at the end so that the first 'rest' event gets sent
- m_atRest = atHomePosition(data, 0.05f);
+ m_motionEventPending = false;
return true;
}
diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h
index 155510d6d7f..cabff22fca7 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.h
+++ b/intern/ghost/intern/GHOST_NDOFManager.h
@@ -27,9 +27,7 @@
#include "GHOST_System.h"
-// --- the following type definitions will find a home somewhere else once finished ---
-
-//#define DEBUG_NDOF_MOTION
+#define DEBUG_NDOF_MOTION
#define DEBUG_NDOF_BUTTONS
typedef enum { NDOF_UnknownDevice, NDOF_SpaceNavigator, NDOF_SpaceExplorer, NDOF_SpacePilotPro } NDOF_DeviceT;
@@ -120,7 +118,7 @@ protected:
private:
void sendButtonEvent(NDOF_ButtonT, bool press, GHOST_TUns64 time, GHOST_IWindow*);
void sendKeyEvent(GHOST_TKey, bool press, GHOST_TUns64 time, GHOST_IWindow*);
-
+ void updateMotionState();
NDOF_DeviceT m_deviceType;
int m_buttonCount;
@@ -132,7 +130,8 @@ private:
GHOST_TUns64 m_motionTime; // in milliseconds
GHOST_TUns64 m_prevMotionTime; // time of most recent Motion event sent
- bool m_atRest;
+ GHOST_TProgress m_motionState;
+ bool m_motionEventPending;
};
#endif
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index fc84944da02..bfbff8a4906 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -929,10 +929,30 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
}
-#if 0 // NDOF utility functions
+// NDOF utility functions
+// (should these functions live in this file?)
+float ndof_to_angle_axis(struct wmNDOFMotionData* ndof, float axis[3])
+ {
+ const float x = ndof->rx;
+ const float y = ndof->ry;
+ const float z = ndof->rz;
+
+ float angular_velocity = sqrtf(x*x + y*y + z*z);
+ float angle = ndof->dt * angular_velocity;
+
+ float scale = 1.f / angular_velocity;
+
+ // normalize
+ axis[0] = scale * x;
+ axis[1] = scale * y;
+ axis[2] = scale * z;
+
+ return angle;
+ }
+
+#if 0 // unused utility functions
// returns angular velocity (0..1), fills axis of rotation
-// (shouldn't live in this file!)
-static float ndof_to_angle_axis(const float ndof[3], float axis[3])
+float ndof_to_angle_axis(const float ndof[3], float axis[3])
{
const float x = ndof[0];
const float y = ndof[1];
@@ -960,7 +980,7 @@ static float ndof_to_angular_velocity(wmNDOFMotionData* ndof)
}
#endif
-static void ndof_to_quat(wmNDOFMotionData* ndof, float q[4])
+void ndof_to_quat(struct wmNDOFMotionData* ndof, float q[4])
{
const float x = ndof->rx;
const float y = ndof->ry;
@@ -988,6 +1008,8 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
RegionView3D* rv3d = CTX_wm_region_view3d(C);
wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
+ const float dt = ndof->dt;
+
// tune these until everything feels right
const float rot_sensitivity = 1.f;
const float zoom_sensitivity = 1.f;
@@ -996,12 +1018,6 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
// rather have bool, but...
int has_rotation = rv3d->viewlock != RV3D_LOCKED && (ndof->rx || ndof->ry || ndof->rz);
- float dt = ndof->dt;
- if (dt > 0.25f)
- /* this is probably the first event for this motion, so set dt to something reasonable */
- /* TODO: replace such guesswork with a flag or field from the NDOF manager */
- ndof->dt = dt = 0.0125f;
-
//#define DEBUG_NDOF_MOTION
#ifdef DEBUG_NDOF_MOTION
printf("ndof: T=(%.2f,%.2f,%.2f) R=(%.2f,%.2f,%.2f) dt=%.3f delivered to 3D view\n",
@@ -1086,41 +1102,109 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_FINISHED;
}
-#if 0 // not ready
+#if 0
+// statics for controlling rv3d->dist corrections.
+// viewmoveNDOF zeros and adjusts rv3d->ofs.
+// viewmove restores based on dz_flag state.
+
+static int dz_flag = 0;
+static float m_dist;
+
+static void mouse_rotation_workaround_push(RegionView3D* rv3d)
+{
+ // This is due to a side effect of the original
+ // mouse view rotation code. The rotation point is
+ // set a distance in front of the viewport to
+ // make rotating with the mouse look better.
+ // The distance effect is written at a low level
+ // in the view management instead of the mouse
+ // view function. This means that all other view
+ // movement devices must subtract this from their
+ // view transformations.
+
+ float mat[3][3];
+ float upvec[3];
+
+ if(rv3d->dist != 0.0) {
+ dz_flag = 1;
+ m_dist = rv3d->dist;
+ upvec[0] = upvec[1] = 0;
+ upvec[2] = rv3d->dist;
+ copy_m3_m4(mat, rv3d->viewinv);
+ mul_m3_v3(mat, upvec);
+ sub_v3_v3(rv3d->ofs, upvec);
+ rv3d->dist = 0.0;
+ }
+
+ // this is still needed in version 2.5 [mce]
+ // warning! current viewmove does not look at dz_flag or m_dist
+ // don't expect 2D mouse to work properly right after using 3D mouse
+}
+
+static void mouse_rotation_workaround_pop(RegionView3D* rv3d)
+{
+ if (dz_flag) {
+ dz_flag = 0;
+ rv3d->dist = m_dist;
+ }
+}
+
static int ndof_fly_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
RegionView3D* rv3d = CTX_wm_region_view3d(C);
wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
- const int shouldRotate = 0, shouldMove = 1;
+ const int shouldRotate = 1, shouldTranslate = 0;
+
+ const float dt = ndof->dt;
- float dt = ndof->dt;
- if (dt > 0.25f)
- /* this is probably the first event for this motion, so set dt to something reasonable */
- /* TODO: replace such guesswork with a flag or field from the NDOF manager */
- ndof->dt = dt = 0.0125f;
+ float view_inv[4];
+ invert_qt_qt(view_inv, rv3d->viewquat);
if (shouldRotate)
{
const float turn_sensitivity = 1.f;
float rot[4];
+ float view_inv_conj[4];
+ mouse_rotation_workaround_push(rv3d);
+
ndof_to_quat(ndof, rot);
+ copy_qt_qt(view_inv_conj, view_inv);
+ conjugate_qt(view_inv_conj);
+
+ // transform rotation from view to world coordinates
+ mul_qt_qtqt(rot, view_inv, rot);
+ mul_qt_qtqt(rot, rot, view_inv_conj);
+
+ // apply rotation to view offset (focal point)
+ mul_qt_v3(rot, rv3d->ofs);
+// mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
+
rv3d->view = RV3D_VIEW_USER;
}
- if (shouldMove)
+ if (shouldTranslate)
{
const float forward_sensitivity = 1.f;
const float vertical_sensitivity = 1.f;
const float lateral_sensitivity = 1.f;
-
+
float trans[3] = {
- lateral_sensitivity * dt * ndof->tx,
- vertical_sensitivity * dt * ndof->ty,
- forward_sensitivity * rv3d->dist * dt * ndof->tz
+ lateral_sensitivity * ndof->tx,
+ vertical_sensitivity * ndof->ty,
+ forward_sensitivity * ndof->tz
};
+
+// mul_v3_fl(trans, rv3d->dist * dt);
+ mul_v3_fl(trans, dt);
+
+ /* transform motion from view to world coordinates */
+ mul_qt_v3(view_inv, trans);
+
+ /* move center of view opposite of hand motion (this is camera mode, not object mode) */
+ sub_v3_v3(rv3d->ofs, trans);
}
ED_region_tag_redraw(CTX_wm_region(C));
@@ -1141,9 +1225,7 @@ static void getndof(wmNDOFMotionData* indof, float* outdof)
const float vertical_sensitivity = 1.6f;
const float lateral_sensitivity = 2.5f;
- const float dt = (indof->dt < 0.25f) ? indof->dt : 0.0125f;
- // this is probably the first event for this motion, so set dt to something reasonable
- // TODO: replace such guesswork with a flag or field from the NDOF manager
+ const float dt = indof->dt;
outdof[0] = lateral_sensitivity * dt * indof->tx;
outdof[1] = vertical_sensitivity * dt * indof->ty;
@@ -1154,51 +1236,6 @@ static void getndof(wmNDOFMotionData* indof, float* outdof)
outdof[5] = turn_sensitivity * dt * indof->rz;
}
-// statics for controlling rv3d->dist corrections.
-// viewmoveNDOF zeros and adjusts rv3d->ofs.
-// viewmove restores based on dz_flag state.
-
-static int dz_flag = 0;
-static float m_dist;
-
-static void mouse_rotation_workaround_push(RegionView3D* rv3d)
-{
- // This is due to a side effect of the original
- // mouse view rotation code. The rotation point is
- // set a distance in front of the viewport to
- // make rotating with the mouse look better.
- // The distance effect is written at a low level
- // in the view management instead of the mouse
- // view function. This means that all other view
- // movement devices must subtract this from their
- // view transformations.
-
- float mat[3][3];
- float upvec[3];
-
- if(rv3d->dist != 0.0) {
- dz_flag = 1;
- m_dist = rv3d->dist;
- upvec[0] = upvec[1] = 0;
- upvec[2] = rv3d->dist;
- copy_m3_m4(mat, rv3d->viewinv);
- mul_m3_v3(mat, upvec);
- sub_v3_v3(rv3d->ofs, upvec);
- rv3d->dist = 0.0;
- }
-
- // this is still needed in version 2.5 [mce]
- // warning! current viewmove does not look at dz_flag or m_dist
- // don't expect 2D mouse to work properly right after using 3D mouse
-}
-
-static void mouse_rotation_workaround_pop(RegionView3D* rv3d)
-{
- if (dz_flag) {
- dz_flag = 0;
- rv3d->dist = m_dist;
- }
-}
static int ndof_oldfly_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
@@ -1254,7 +1291,7 @@ static int ndof_oldfly_invoke(bContext *C, wmOperator *op, wmEvent *event)
// translate the view
sub_v3_v3(rv3d->ofs, tvec);
- mouse_rotation_workaround_pop(rv3d);
+// mouse_rotation_workaround_pop(rv3d);
// back to 2.5 land!
ED_region_tag_redraw(CTX_wm_region(C));
@@ -1272,8 +1309,9 @@ void VIEW3D_OT_ndof(struct wmOperatorType *ot)
ot->idname = "VIEW3D_OT_ndof";
/* api callbacks */
-// ot->invoke = ndof_oldfly_invoke;
ot->invoke = ndof_orbit_invoke;
+// ot->invoke = ndof_fly_invoke;
+// ot->invoke = ndof_oldfly_invoke;
ot->poll = ED_operator_view3d_active;
/* flags */
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index ed1ed5b3881..00adfa13e28 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -158,7 +158,9 @@ typedef struct FlyInfo {
short state;
short use_precision;
short redraw;
- int mval[2];
+
+ int mval[2]; /* latest 2D mouse values */
+ wmNDOFMotionData* ndof; /* latest 3D mouse values */
/* fly state state */
float speed; /* the speed the view is moving per redraw */
@@ -257,6 +259,8 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
fly->ar = CTX_wm_region(C);
fly->scene= CTX_data_scene(C);
+ puts("\n-- fly begin --");
+
if(fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->id.lib) {
BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library");
return FALSE;
@@ -282,12 +286,14 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
fly->zlock_momentum=0.0f;
fly->grid= 1.0f;
fly->use_precision= 0;
+ fly->redraw= 1;
fly->dvec_prev[0]= fly->dvec_prev[1]= fly->dvec_prev[2]= 0.0f;
fly->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
VECCOPY2D(fly->mval, event->mval)
+ fly->ndof = NULL;
fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer();
@@ -329,8 +335,17 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
/* perspective or ortho */
if (fly->rv3d->persp==RV3D_ORTHO)
fly->rv3d->persp= RV3D_PERSP; /*if ortho projection, make perspective */
+
copy_qt_qt(fly->rot_backup, fly->rv3d->viewquat);
copy_v3_v3(fly->ofs_backup, fly->rv3d->ofs);
+
+ /* the dist defines a vector that is infront of the offset
+ to rotate the view about.
+ this is no good for fly mode because we
+ want to rotate about the viewers center.
+ but to correct the dist removal we must
+ alter offset so the view doesn't jump. */
+
fly->rv3d->dist= 0.0f;
upvec[2]= fly->dist_backup; /*x and y are 0*/
@@ -338,7 +353,6 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
sub_v3_v3(fly->rv3d->ofs, upvec);
/*Done with correcting for the dist*/
}
-
/* center the mouse, probably the UI mafia are against this but without its quite annoying */
WM_cursor_warp(CTX_wm_window(C), fly->ar->winrct.xmin + fly->ar->winx/2, fly->ar->winrct.ymin + fly->ar->winy/2);
@@ -356,6 +370,8 @@ static int flyEnd(bContext *C, FlyInfo *fly)
if(fly->state == FLY_RUNNING)
return OPERATOR_RUNNING_MODAL;
+ puts("\n-- fly end --");
+
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), fly->timer);
ED_region_draw_cb_exit(fly->ar->type, fly->draw_handle_pixel);
@@ -401,6 +417,9 @@ static int flyEnd(bContext *C, FlyInfo *fly)
if(fly->obtfm)
MEM_freeN(fly->obtfm);
+ if(fly->ndof)
+ MEM_freeN(fly->ndof);
+
if(fly->state == FLY_CONFIRM) {
MEM_freeN(fly);
return OPERATOR_FINISHED;
@@ -412,12 +431,46 @@ static int flyEnd(bContext *C, FlyInfo *fly)
static void flyEvent(FlyInfo *fly, wmEvent *event)
{
- if (event->type == TIMER && event->customdata == fly->timer) {
- fly->redraw = 1;
- }
- else if (event->type == MOUSEMOVE) {
+ if (event->type == MOUSEMOVE) {
VECCOPY2D(fly->mval, event->mval);
- } /* handle modal keymap first */
+ }
+ else if (event->type == NDOF_MOTION) {
+ // do these automagically get delivered? yes.
+ // puts("ndof motion detected in fly mode!");
+ // static const char* tag_name = "3D mouse position";
+
+ wmNDOFMotionData* incoming_ndof = (wmNDOFMotionData*) event->customdata;
+ switch (incoming_ndof->progress)
+ {
+ case P_STARTING:
+ // start keeping track of 3D mouse position
+ puts("start keeping track of 3D mouse position");
+ // fall through...
+ case P_IN_PROGRESS:
+ // update 3D mouse position
+ putchar('.'); fflush(stdout);
+ if (fly->ndof == NULL)
+ // fly->ndof = MEM_mallocN(sizeof(wmNDOFMotionData), tag_name);
+ fly->ndof = MEM_dupallocN(incoming_ndof);
+ // fly->ndof = malloc(sizeof(wmNDOFMotionData));
+ else
+ memcpy(fly->ndof, incoming_ndof, sizeof(wmNDOFMotionData));
+ break;
+ case P_FINISHING:
+ // stop keeping track of 3D mouse position
+ puts("stop keeping track of 3D mouse position");
+ if (fly->ndof)
+ {
+ MEM_freeN(fly->ndof);
+ // free(fly->ndof);
+ fly->ndof = NULL;
+ }
+ break;
+ default:
+ ; // should always be one of the above 3
+ }
+ }
+ /* handle modal keymap first */
else if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case FLY_MODAL_CANCEL:
@@ -528,7 +581,6 @@ static void flyEvent(FlyInfo *fly, wmEvent *event)
case FLY_MODAL_PRECISION_DISABLE:
fly->use_precision= FALSE;
break;
-
}
}
}
@@ -567,16 +619,12 @@ static int flyApply(bContext *C, FlyInfo *fly)
unsigned char
apply_rotation= 1; /* if the user presses shift they can look about without movinf the direction there looking*/
+ static unsigned int iteration = 1;
+ printf("fly timer %d\n", iteration++);
+
if(fly->root_parent)
ED_view3d_to_m4(prev_view_mat, fly->rv3d->ofs, fly->rv3d->viewquat, fly->rv3d->dist);
- /* the dist defines a vector that is infront of the offset
- to rotate the view about.
- this is no good for fly mode because we
- want to rotate about the viewers center.
- but to correct the dist removal we must
- alter offset so the view doesn't jump. */
-
xmargin= ar->winx/20.0f;
ymargin= ar->winy/20.0f;
@@ -622,6 +670,8 @@ static int flyApply(bContext *C, FlyInfo *fly)
float time_redraw;
float time_redraw_clamped;
+ fly->redraw= 1;
+
time_current= PIL_check_seconds_timer();
time_redraw= (float)(time_current - fly->time_lastdraw);
time_redraw_clamped= MIN2(0.05f, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */
@@ -854,11 +904,69 @@ static int flyApply(bContext *C, FlyInfo *fly)
copy_v3_v3(fly->dvec_prev, dvec);
}
-/* moved to flyEnd() */
-
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 shouldRotate = 1, shouldTranslate = 1;
+
+ float view_inv[4];
+ invert_qt_qt(view_inv, rv3d->viewquat);
+
+ if (shouldRotate)
+ {
+ const float turn_sensitivity = 1.f;
+
+ float rotation[4];
+ float axis[3];
+ float angle = turn_sensitivity * ndof_to_angle_axis(ndof, axis);
+
+ // 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);
+
+ rv3d->view = RV3D_VIEW_USER;
+
+ fly->redraw = 1;
+ }
+
+ if (shouldTranslate)
+ {
+ const float forward_sensitivity = 1.f;
+ const float vertical_sensitivity = 0.4f;
+ const float lateral_sensitivity = 0.6f;
+
+ float speed = 10.f; // blender units per second
+ // ^^ this is ok for default cube scene, but should scale with.. something
+
+ float trans[3] = {
+ lateral_sensitivity * ndof->tx,
+ vertical_sensitivity * ndof->ty,
+ forward_sensitivity * ndof->tz
+ };
+
+ mul_v3_fl(trans, speed * dt);
+
+ // transform motion from view to world coordinates
+ mul_qt_v3(view_inv, trans);
+
+ // move center of view opposite of hand motion (this is camera mode, not object mode)
+ sub_v3_v3(rv3d->ofs, trans);
+
+ fly->redraw = 1;
+ }
+
+ return OPERATOR_FINISHED;
+}
static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event)
@@ -908,7 +1016,12 @@ static int fly_modal(bContext *C, wmOperator *op, wmEvent *event)
flyEvent(fly, event);
- if(event->type==TIMER && event->customdata == fly->timer)
+ if (fly->ndof) // 3D mouse overrules [2D mouse + timer]
+ {
+ if (event->type==NDOF_MOTION)
+ flyApply_ndof(C, fly);
+ }
+ else if (event->type==TIMER && event->customdata == fly->timer)
flyApply(C, fly);
do_draw |= fly->redraw;
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 1a148481031..3658a481bdf 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -51,6 +51,7 @@ struct ARegionType;
struct bPoseChannel;
struct bAnimVizSettings;
struct bMotionPath;
+struct wmNDOFMotionData;
#define BL_NEAR_CLIP 0.001
@@ -92,6 +93,8 @@ void VIEW3D_OT_zoom_border(struct wmOperatorType *ot);
void VIEW3D_OT_drawtype(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
+void ndof_to_quat(struct wmNDOFMotionData* ndof, float q[4]);
+float ndof_to_angle_axis(struct wmNDOFMotionData* ndof, float axis[3]);
/* view3d_fly.c */
void view3d_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 26c394a2ad3..7476410ec19 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -377,17 +377,24 @@ typedef struct wmTabletData {
float Ytilt; /* as above */
} wmTabletData;
-typedef struct {
+typedef enum { // motion progress, for modal handlers
+ P_NOT_STARTED,
+ P_STARTING, // <--
+ P_IN_PROGRESS, // <-- only these are sent for NDOF motion
+ P_FINISHING, // <--
+ P_FINISHED
+ } wmProgress;
+
+typedef struct wmNDOFMotionData {
/* awfully similar to GHOST_TEventNDOFMotionData... */
-
- /* Each component normally ranges from -1 to +1, but can exceed that. */
-
- float tx, ty, tz; /* translation: -x left, +y forward, -z up */
- float rx, ry, rz; /* rotation:
- axis = (rx,ry,rz).normalized
- amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg] */
-
- float dt; // time since previous NDOF Motion event (or zero if this is the first)
+ // Each component normally ranges from -1 to +1, but can exceed that.
+ // These use blender standard view coordinates, with positive rotations being CCW about the axis.
+ float tx, ty, tz; // translation
+ float rx, ry, rz; // rotation:
+ // axis = (rx,ry,rz).normalized
+ // amount = (rx,ry,rz).magnitude [in revolutions, 1.0 = 360 deg]
+ float dt; // time since previous NDOF Motion event
+ wmProgress progress; // is this the first event, the last, or one of many in between?
} wmNDOFMotionData;
typedef struct wmTimer {
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index b41eebc5298..c2df53c9e91 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2324,6 +2324,8 @@ static void attach_ndof_data(wmEvent* event, const GHOST_TEventNDOFMotionData* g
data->dt = ghost->dt;
+ data->progress = (wmProgress) ghost->progress;
+
event->custom = EVT_DATA_NDOF_MOTION;
event->customdata = data;
event->customdatafree = 1;