forked from bartvdbraak/blender
more consistent and modal-friendly ndof events, fly mode v1
This commit is contained in:
parent
44d2e6eb10
commit
cc1ba4569c
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,74 +1102,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
#if 0 // not ready
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
if (shouldRotate)
|
||||
{
|
||||
const float turn_sensitivity = 1.f;
|
||||
|
||||
float rot[4];
|
||||
ndof_to_quat(ndof, rot);
|
||||
|
||||
rv3d->view = RV3D_VIEW_USER;
|
||||
}
|
||||
|
||||
if (shouldMove)
|
||||
{
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
// BEGIN old fly code
|
||||
// derived from blender 2.4
|
||||
|
||||
static void getndof(wmNDOFMotionData* indof, float* outdof)
|
||||
{
|
||||
// Rotations feel relatively faster than translations only in fly mode, so
|
||||
// we have no choice but to fix that here (not in the plugins)
|
||||
const float turn_sensitivity = 0.8f;
|
||||
|
||||
const float forward_sensitivity = 2.5f;
|
||||
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
|
||||
|
||||
outdof[0] = lateral_sensitivity * dt * indof->tx;
|
||||
outdof[1] = vertical_sensitivity * dt * indof->ty;
|
||||
outdof[2] = forward_sensitivity * dt * indof->tz;
|
||||
|
||||
outdof[3] = turn_sensitivity * dt * indof->rx;
|
||||
outdof[4] = turn_sensitivity * dt * indof->ry;
|
||||
outdof[5] = turn_sensitivity * dt * indof->rz;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// statics for controlling rv3d->dist corrections.
|
||||
// viewmoveNDOF zeros and adjusts rv3d->ofs.
|
||||
// viewmove restores based on dz_flag state.
|
||||
@ -1200,6 +1149,94 @@ static void mouse_rotation_workaround_pop(RegionView3D* rv3d)
|
||||
}
|
||||
}
|
||||
|
||||
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 = 1, shouldTranslate = 0;
|
||||
|
||||
const float dt = ndof->dt;
|
||||
|
||||
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 (shouldTranslate)
|
||||
{
|
||||
const float forward_sensitivity = 1.f;
|
||||
const float vertical_sensitivity = 1.f;
|
||||
const float lateral_sensitivity = 1.f;
|
||||
|
||||
float trans[3] = {
|
||||
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));
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
// BEGIN old fly code
|
||||
// derived from blender 2.4
|
||||
|
||||
static void getndof(wmNDOFMotionData* indof, float* outdof)
|
||||
{
|
||||
// Rotations feel relatively faster than translations only in fly mode, so
|
||||
// we have no choice but to fix that here (not in the plugins)
|
||||
const float turn_sensitivity = 0.8f;
|
||||
|
||||
const float forward_sensitivity = 2.5f;
|
||||
const float vertical_sensitivity = 1.6f;
|
||||
const float lateral_sensitivity = 2.5f;
|
||||
|
||||
const float dt = indof->dt;
|
||||
|
||||
outdof[0] = lateral_sensitivity * dt * indof->tx;
|
||||
outdof[1] = vertical_sensitivity * dt * indof->ty;
|
||||
outdof[2] = forward_sensitivity * dt * indof->tz;
|
||||
|
||||
outdof[3] = turn_sensitivity * dt * indof->rx;
|
||||
outdof[4] = turn_sensitivity * dt * indof->ry;
|
||||
outdof[5] = turn_sensitivity * dt * indof->rz;
|
||||
}
|
||||
|
||||
|
||||
static int ndof_oldfly_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
{
|
||||
RegionView3D* rv3d = CTX_wm_region_view3d(C);
|
||||
@ -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 */
|
||||
|
@ -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*/
|
||||
@ -339,7 +354,6 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
|
||||
/*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;
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user