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
path: root/source
diff options
context:
space:
mode:
authorMike Erwin <significant.bit@gmail.com>2011-07-15 01:20:45 +0400
committerMike Erwin <significant.bit@gmail.com>2011-07-15 01:20:45 +0400
commitcc1ba4569ccdb77a9371140def316caecac71da5 (patch)
treecc1329237f33e5c586177f60e46000943ebc99f6 /source
parent44d2e6eb109889f49fb9935d05ef201127d15805 (diff)
more consistent and modal-friendly ndof events, fly mode v1
Diffstat (limited to 'source')
-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
5 files changed, 263 insertions, 100 deletions
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;