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--build_files/scons/config/darwin-config.py8
-rw-r--r--intern/ghost/GHOST_C-api.h15
-rw-r--r--intern/ghost/GHOST_ISystem.h16
-rw-r--r--intern/ghost/GHOST_Types.h44
-rw-r--r--intern/ghost/SConscript2
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp17
-rw-r--r--intern/ghost/intern/GHOST_EventNDOF.h56
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.cpp204
-rw-r--r--intern/ghost/intern/GHOST_NDOFManager.h49
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.h48
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerCocoa.mm121
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerWin32.h47
-rw-r--r--intern/ghost/intern/GHOST_NDOFManagerX11.h100
-rw-r--r--intern/ghost/intern/GHOST_System.cpp31
-rw-r--r--intern/ghost/intern/GHOST_System.h19
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.h7
-rw-r--r--intern/ghost/intern/GHOST_SystemCocoa.mm10
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c251
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h1
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c5
-rw-r--r--source/blender/windowmanager/WM_types.h13
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c50
-rw-r--r--source/blender/windowmanager/wm_event_types.h23
23 files changed, 856 insertions, 281 deletions
diff --git a/build_files/scons/config/darwin-config.py b/build_files/scons/config/darwin-config.py
index 0c51476a6d0..231525993e1 100644
--- a/build_files/scons/config/darwin-config.py
+++ b/build_files/scons/config/darwin-config.py
@@ -264,7 +264,9 @@ if MACOSX_ARCHITECTURE == 'i386':
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse']
elif MACOSX_ARCHITECTURE == 'x86_64':
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-msse2']
-
+
+# SpaceNavigator and related 3D mice
+WITH_BF_SPACENAV = True
#############################################################################
################### various compile settings and flags ##################
@@ -294,6 +296,10 @@ if WITH_BF_QUICKTIME == True:
else:
PLATFORM_LINKFLAGS = PLATFORM_LINKFLAGS+['-framework','QuickTime']
+if WITH_BF_SPACENAV:
+ PLATFORM_LINKFLAGS = PLATFORM_LINKFLAGS + ['-weak_framework','3DconnexionClient']
+ CXXFLAGS = CXXFLAGS + ['-fpascal-strings'] # they use an old-skool Mac programming style
+
#note to build succesfully on 10.3.9 SDK you need to patch 10.3.9 by adding the SystemStubs.a lib from 10.4
LLIBS = ['stdc++', 'SystemStubs']
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 75837239c4a..a315dfa85e9 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -288,21 +288,6 @@ extern GHOST_TSuccess GHOST_SetProgressBar(GHOST_WindowHandle windowhandle, floa
* @param windowhandle The handle to the window
*/
extern GHOST_TSuccess GHOST_EndProgressBar(GHOST_WindowHandle windowhandle);
-
-
-/***************************************************************************************
- ** N-degree of freedom device management functionality
- ***************************************************************************************/
-
-/**
-* Open N-degree of freedom devices
- */
-extern int GHOST_OpenNDOF(GHOST_SystemHandle systemhandle,
- GHOST_WindowHandle windowhandle,
- GHOST_NDOFLibraryInit_fp setNdofLibraryInit,
- GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
- GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen
- );
/***************************************************************************************
** Cursor management functionality
diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h
index 69e10070be5..015ae780bea 100644
--- a/intern/ghost/GHOST_ISystem.h
+++ b/intern/ghost/GHOST_ISystem.h
@@ -298,22 +298,6 @@ public:
*/
virtual GHOST_TSuccess removeEventConsumer(GHOST_IEventConsumer* consumer) = 0;
- /***************************************************************************************
- ** N-degree of freedom device management functionality
- ***************************************************************************************/
-
- /**
- * Starts the N-degree of freedom device manager
- */
- virtual int openNDOF(GHOST_IWindow*,
- GHOST_NDOFLibraryInit_fp setNdofLibraryInit,
- GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
- GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen
- // original patch only
- // GHOST_NDOFEventHandler_fp setNdofEventHandler
- ) = 0;
-
-
/***************************************************************************************
** Cursor management functionality
***************************************************************************************/
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 705f4916619..7fa94b14716 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -439,37 +439,23 @@ typedef struct {
GHOST_TUns8 **strings;
} GHOST_TStringArray;
-
-/* original patch used floats, but the driver return ints and uns. We will calibrate in view, no sense on doing conversions twice */
-/* as all USB device controls are likely to use ints, this is also more future proof */
-//typedef struct {
-// /** N-degree of freedom device data */
-// float tx, ty, tz; /** -x left, +y up, +z forward */
-// float rx, ry, rz;
-// float dt;
-//} GHOST_TEventNDOFData;
+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)
+} GHOST_TEventNDOFMotionData;
+
+typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction;
+ // good for mouse or other buttons too, hmmm?
typedef struct {
- /** N-degree of freedom device data v2*/
- int changed;
- GHOST_TUns64 client;
- GHOST_TUns64 address;
- GHOST_TInt16 tx, ty, tz; /** -x left, +y up, +z forward */
- GHOST_TInt16 rx, ry, rz;
- GHOST_TInt16 buttons;
- GHOST_TUns64 time;
- GHOST_TUns64 delta;
-} GHOST_TEventNDOFData;
-
-typedef int (*GHOST_NDOFLibraryInit_fp)(void);
-typedef void (*GHOST_NDOFLibraryShutdown_fp)(void* deviceHandle);
-typedef void* (*GHOST_NDOFDeviceOpen_fp)(void* platformData);
-
-// original patch windows callback. In mac os X version the callback is internal to the plug-in and post an event to main thead.
-// not necessary faster, but better integration with other events.
-
-//typedef int (*GHOST_NDOFEventHandler_fp)(float* result7, void* deviceHandle, unsigned int message, unsigned int* wParam, unsigned long* lParam);
-//typedef void (*GHOST_NDOFCallBack_fp)(GHOST_TEventNDOFDataV2 *VolDatas);
+ GHOST_TButtonAction action;
+ short button;
+} GHOST_TEventNDOFButtonData;
typedef struct {
/** The key code. */
diff --git a/intern/ghost/SConscript b/intern/ghost/SConscript
index b67545f216a..3b144ba95cb 100644
--- a/intern/ghost/SConscript
+++ b/intern/ghost/SConscript
@@ -11,7 +11,7 @@ if window_system == 'darwin':
sources += env.Glob('intern/*.mm')
-pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_SystemPaths', 'GHOST_Window', 'GHOST_DropTarget']
+pf = ['GHOST_DisplayManager', 'GHOST_System', 'GHOST_SystemPaths', 'GHOST_Window', 'GHOST_DropTarget', 'GHOST_NDOFManager']
defs=['_USE_MATH_DEFINES']
if window_system in ('linux2', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'freebsd9', 'irix6', 'aix4', 'aix5'):
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 7ba8d7db411..6332d72a42f 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -275,23 +275,6 @@ GHOST_TSuccess GHOST_EndProgressBar(GHOST_WindowHandle windowhandle)
}
-int GHOST_OpenNDOF(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle,
- GHOST_NDOFLibraryInit_fp setNdofLibraryInit,
- GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
- GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen)
- //original patch only
- /* GHOST_NDOFEventHandler_fp setNdofEventHandler)*/
-{
- GHOST_ISystem* system = (GHOST_ISystem*) systemhandle;
-
- return system->openNDOF((GHOST_IWindow*) windowhandle,
- setNdofLibraryInit, setNdofLibraryShutdown, setNdofDeviceOpen);
-// original patch
-// setNdofLibraryInit, setNdofLibraryShutdown, setNdofDeviceOpen, setNdofEventHandler);
-}
-
-
-
GHOST_TStandardCursor GHOST_GetCursorShape(GHOST_WindowHandle windowhandle)
{
GHOST_IWindow* window = (GHOST_IWindow*) windowhandle;
diff --git a/intern/ghost/intern/GHOST_EventNDOF.h b/intern/ghost/intern/GHOST_EventNDOF.h
index 70861b08fc6..394aff0493f 100644
--- a/intern/ghost/intern/GHOST_EventNDOF.h
+++ b/intern/ghost/intern/GHOST_EventNDOF.h
@@ -19,11 +19,6 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-
-/** \file ghost/intern/GHOST_EventNDOF.h
- * \ingroup GHOST
- */
-
#ifndef _GHOST_EVENT_NDOF_H_
@@ -31,32 +26,33 @@
#include "GHOST_Event.h"
-/**
- * N-degree of freedom device event.
- */
-class GHOST_EventNDOF : public GHOST_Event
-{
-public:
- /**
- * Constructor.
- * @param msec The time this event was generated.
- * @param type The type of this event.
- * @param x The x-coordinate of the location the cursor was at at the time of the event.
- * @param y The y-coordinate of the location the cursor was at at the time of the event.
- */
- GHOST_EventNDOF(GHOST_TUns64 msec, GHOST_TEventType type, GHOST_IWindow* window,
- GHOST_TEventNDOFData data)
- : GHOST_Event(msec, type, window)
- {
- m_ndofEventData = data;
- m_data = &m_ndofEventData;
- }
-protected:
- /** translation & rotation from the device. */
- GHOST_TEventNDOFData m_ndofEventData;
-};
+class GHOST_EventNDOFMotion : public GHOST_Event
+ {
+ protected:
+ GHOST_TEventNDOFMotionData m_axisData;
+
+ public:
+ GHOST_EventNDOFMotion(GHOST_TUns64 time, GHOST_IWindow* window)
+ : GHOST_Event(time, GHOST_kEventNDOFMotion, window)
+ {
+ m_data = &m_axisData;
+ }
+ };
+
+
+class GHOST_EventNDOFButton : public GHOST_Event
+ {
+ protected:
+ GHOST_TEventNDOFButtonData m_buttonData;
+
+ public:
+ GHOST_EventNDOFButton(GHOST_TUns64 time, GHOST_IWindow* window)
+ : GHOST_Event(time, GHOST_kEventNDOFButton, window)
+ {
+ m_data = &m_buttonData;
+ }
+ };
#endif // _GHOST_EVENT_NDOF_H_
-
diff --git a/intern/ghost/intern/GHOST_NDOFManager.cpp b/intern/ghost/intern/GHOST_NDOFManager.cpp
index 7721b1708f9..1042398650e 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.cpp
+++ b/intern/ghost/intern/GHOST_NDOFManager.cpp
@@ -15,120 +15,108 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor(s): none yet.
+ * Contributor(s):
+ * Mike Erwin
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file ghost/intern/GHOST_NDOFManager.cpp
- * \ingroup GHOST
- */
+#include "GHOST_NDOFManager.h"
+#include "GHOST_EventNDOF.h"
+#include "GHOST_WindowManager.h"
+#include <string.h> // for memory functions
+#include <stdio.h> // for debug tracing
+
+GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System& sys)
+ : m_system(sys)
+ , m_buttons(0)
+ , m_motionTime(1000) // one full second (operators should filter out such large time deltas)
+ , m_prevMotionTime(0)
+ , m_atRest(true)
+ {
+ // to avoid the rare situation where one triple is updated and
+ // the other is not, initialize them both here:
+ memset(m_translation, 0, sizeof(m_translation));
+ memset(m_rotation, 0, sizeof(m_rotation));
+ }
+
+void GHOST_NDOFManager::updateTranslation(short t[3], GHOST_TUns64 time)
+ {
+ memcpy(m_translation, t, sizeof(m_translation));
+ m_motionTime = time;
+ m_atRest = false;
+ }
+
+void GHOST_NDOFManager::updateRotation(short r[3], GHOST_TUns64 time)
+ {
+ memcpy(m_rotation, r, sizeof(m_rotation));
+ m_motionTime = time;
+ m_atRest = false;
+ }
+
+void GHOST_NDOFManager::updateButtons(unsigned short buttons, GHOST_TUns64 time)
+ {
+ GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow();
+
+ unsigned short diff = m_buttons ^ buttons;
+
+ for (int i = 0; i < 16; ++i)
+ {
+ unsigned short mask = 1 << i;
+
+ if (diff & mask)
+ {
+ GHOST_EventNDOFButton* event = new GHOST_EventNDOFButton(time, window);
+ GHOST_TEventNDOFButtonData* data = (GHOST_TEventNDOFButtonData*) event->getData();
+
+ data->action = (buttons & mask) ? GHOST_kPress : GHOST_kRelease;
+ data->button = i + 1;
+ // printf("sending button %d %s\n", data->button, (data->action == GHOST_kPress) ? "pressed" : "released");
-#include <stdio.h> /* just for printf */
+ m_system.pushEvent(event);
+ }
+ }
-#include "GHOST_NDOFManager.h"
+ m_buttons = buttons;
+ }
+bool GHOST_NDOFManager::sendMotionEvent()
+ {
+ if (m_atRest)
+ return false;
-// the variable is outside the class because it must be accessed from plugin
-static volatile GHOST_TEventNDOFData currentNdofValues = {0,0,0,0,0,0,0,0,0,0,0};
-
-#if !defined(_WIN32) && !defined(__APPLE__)
-#include "GHOST_SystemX11.h"
-#endif
-
-namespace
-{
- GHOST_NDOFLibraryInit_fp ndofLibraryInit = 0;
- GHOST_NDOFLibraryShutdown_fp ndofLibraryShutdown = 0;
- GHOST_NDOFDeviceOpen_fp ndofDeviceOpen = 0;
-}
-
-GHOST_NDOFManager::GHOST_NDOFManager()
-{
- m_DeviceHandle = 0;
-
- // discover the API from the plugin
- ndofLibraryInit = 0;
- ndofLibraryShutdown = 0;
- ndofDeviceOpen = 0;
-}
-
-GHOST_NDOFManager::~GHOST_NDOFManager()
-{
- if (ndofLibraryShutdown)
- ndofLibraryShutdown(m_DeviceHandle);
-
- m_DeviceHandle = 0;
-}
-
-
-int
-GHOST_NDOFManager::deviceOpen(GHOST_IWindow* window,
- GHOST_NDOFLibraryInit_fp setNdofLibraryInit,
- GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
- GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen)
-{
- int Pid;
-
- ndofLibraryInit = setNdofLibraryInit;
- ndofLibraryShutdown = setNdofLibraryShutdown;
- ndofDeviceOpen = setNdofDeviceOpen;
-
- if (ndofLibraryInit && ndofDeviceOpen)
- {
- Pid= ndofLibraryInit();
-#if 0
- printf("%i client \n", Pid);
-#endif
- #if defined(WITH_HEADLESS)
- /* do nothing */
- #elif defined(_WIN32) || defined(__APPLE__)
- m_DeviceHandle = ndofDeviceOpen((void *)&currentNdofValues);
- #else
- GHOST_SystemX11 *sys;
- sys = static_cast<GHOST_SystemX11*>(GHOST_ISystem::getSystem());
- void *ndofInfo = sys->prepareNdofInfo(&currentNdofValues);
- m_DeviceHandle = ndofDeviceOpen(ndofInfo);
- #endif
- return (Pid > 0) ? 0 : 1;
-
- } else
- return 1;
-}
-
-
-bool
-GHOST_NDOFManager::available() const
-{
- return m_DeviceHandle != 0;
-}
-
-bool
-GHOST_NDOFManager::event_present() const
-{
- if( currentNdofValues.changed >0) {
- printf("time %llu but%u x%i y%i z%i rx%i ry%i rz%i \n" ,
- currentNdofValues.time, currentNdofValues.buttons,
- currentNdofValues.tx,currentNdofValues.ty,currentNdofValues.tz,
- currentNdofValues.rx,currentNdofValues.ry,currentNdofValues.rz);
- return true;
- }else
- return false;
-
-}
-
-void GHOST_NDOFManager::GHOST_NDOFGetDatas(GHOST_TEventNDOFData &datas) const
-{
- datas.tx = currentNdofValues.tx;
- datas.ty = currentNdofValues.ty;
- datas.tz = currentNdofValues.tz;
- datas.rx = currentNdofValues.rx;
- datas.ry = currentNdofValues.ry;
- datas.rz = currentNdofValues.rz;
- datas.buttons = currentNdofValues.buttons;
- datas.client = currentNdofValues.client;
- datas.address = currentNdofValues.address;
- datas.time = currentNdofValues.time;
- datas.delta = currentNdofValues.delta;
-}
+ GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow();
+
+ GHOST_EventNDOFMotion* event = new GHOST_EventNDOFMotion(m_motionTime, window);
+ GHOST_TEventNDOFMotionData* data = (GHOST_TEventNDOFMotionData*) event->getData();
+
+ const float scale = 1.f / 350.f; // SpaceNavigator sends +/- 350 usually
+ // 350 according to their developer's guide; others recommend 500 as comfortable
+
+ // possible future enhancement
+ // scale *= m_sensitivity;
+
+ data->tx = -scale * m_translation[0];
+ data->ty = scale * m_translation[1];
+ data->tz = scale * m_translation[2];
+
+ data->rx = scale * m_rotation[0];
+ data->ry = scale * m_rotation[1];
+ data->rz = scale * m_rotation[2];
+
+ data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds
+
+ m_prevMotionTime = m_motionTime;
+
+ // printf("sending 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);
+
+ m_system.pushEvent(event);
+
+ // 'at rest' test goes at the end so that the first 'rest' event gets sent
+ m_atRest = m_rotation[0] == 0 && m_rotation[1] == 0 && m_rotation[2] == 0 &&
+ m_translation[0] == 0 && m_translation[1] == 0 && m_translation[2] == 0;
+
+ return true;
+ }
diff --git a/intern/ghost/intern/GHOST_NDOFManager.h b/intern/ghost/intern/GHOST_NDOFManager.h
index c9e09370e09..f4adb4cab1d 100644
--- a/intern/ghost/intern/GHOST_NDOFManager.h
+++ b/intern/ghost/intern/GHOST_NDOFManager.h
@@ -19,38 +19,47 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-
-/** \file ghost/intern/GHOST_NDOFManager.h
- * \ingroup GHOST
- */
-
#ifndef _GHOST_NDOFMANAGER_H_
#define _GHOST_NDOFMANAGER_H_
#include "GHOST_System.h"
-#include "GHOST_IWindow.h"
-
class GHOST_NDOFManager
{
public:
- GHOST_NDOFManager();
- virtual ~GHOST_NDOFManager();
-
- int deviceOpen(GHOST_IWindow* window,
- GHOST_NDOFLibraryInit_fp setNdofLibraryInit,
- GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
- GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen);
-
- void GHOST_NDOFGetDatas(GHOST_TEventNDOFData &datas) const;
-
- bool available() const;
- bool event_present() const;
+ GHOST_NDOFManager(GHOST_System&);
+
+ virtual ~GHOST_NDOFManager() {};
+
+ // whether multi-axis functionality is available (via the OS or driver)
+ // does not imply that a device is plugged in or being used
+ virtual bool available() = 0;
+
+ // the latest raw data from the device
+ void updateTranslation(short t[3], GHOST_TUns64 time);
+ void updateRotation(short r[3], GHOST_TUns64 time);
+ // this one sends events immediately for changed buttons
+ void updateButtons(unsigned short b, GHOST_TUns64 time);
+
+ // processes most recent raw data into an NDOFMotion event and sends it
+ // returns whether an event was sent
+ virtual bool sendMotionEvent();
protected:
- void* m_DeviceHandle;
+ GHOST_System& m_system;
+
+ short m_translation[3];
+ short m_rotation[3];
+ unsigned short m_buttons;
+
+ GHOST_TUns64 m_motionTime;
+ GHOST_TUns64 m_prevMotionTime; // time of most recent Motion event sent
+ bool m_atRest;
+
+ void updateMotionTime(GHOST_TUns64 t);
+ void resetMotion();
};
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.h b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
new file mode 100644
index 00000000000..efe840bab4a
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.h
@@ -0,0 +1,48 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ * Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef _GHOST_NDOFMANAGERCOCOA_H_
+#define _GHOST_NDOFMANAGERCOCOA_H_
+
+#include "GHOST_NDOFManager.h"
+
+// Event capture is handled within the NDOFManager on Macintosh,
+// so there's no need for SystemCocoa to look for them.
+
+class GHOST_NDOFManagerCocoa : public GHOST_NDOFManager
+{
+public:
+ GHOST_NDOFManagerCocoa(GHOST_System&);
+
+ ~GHOST_NDOFManagerCocoa();
+
+ // whether multi-axis functionality is available (via the OS or driver)
+ // does not imply that a device is plugged in or being used
+ bool available();
+
+private:
+ unsigned short m_clientID;
+};
+
+
+#endif
diff --git a/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
new file mode 100644
index 00000000000..75a96556ff1
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
@@ -0,0 +1,121 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ * Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "GHOST_NDOFManagerCocoa.h"
+#include "GHOST_SystemCocoa.h"
+
+extern "C" {
+ #include <3DconnexionClient/ConnexionClientAPI.h>
+ #include <stdio.h>
+ }
+
+static void SpaceNavAdded(io_connect_t connection)
+ {
+ printf("SpaceNav added\n"); // change these: printf --> informational reports
+ }
+
+static void SpaceNavRemoved(io_connect_t connection)
+ {
+ printf("SpaceNav removed\n");
+ }
+
+static void SpaceNavEvent(io_connect_t connection, natural_t messageType, void* messageArgument)
+ {
+ GHOST_SystemCocoa* system = (GHOST_SystemCocoa*) GHOST_ISystem::getSystem();
+ GHOST_NDOFManager* manager = system->getNDOFManager();
+ switch (messageType)
+ {
+ case kConnexionMsgDeviceState:
+ {
+ ConnexionDeviceState* s = (ConnexionDeviceState*)messageArgument;
+
+ GHOST_TUns64 now = system->getMilliSeconds();
+
+ switch (s->command)
+ {
+ case kConnexionCmdHandleAxis:
+ manager->updateTranslation(s->axis, now);
+ manager->updateRotation(s->axis + 3, now);
+ system->notifyExternalEventProcessed();
+ break;
+
+ case kConnexionCmdHandleButtons:
+ manager->updateButtons(s->buttons, now);
+ system->notifyExternalEventProcessed();
+ break;
+
+ default:
+ printf("device state command %d\n", s->command);
+ }
+ break;
+ }
+ case kConnexionMsgPrefsChanged:
+ printf("prefs changed\n"); // this includes app switches
+ break;
+ case kConnexionMsgDoAction:
+ printf("do action\n"); // no idea what this means
+ // 'calibrate device' in System Prefs sends this
+ // 3Dx header file says to ignore these
+ break;
+ default:
+ printf("<!> mystery event\n");
+ }
+ }
+
+GHOST_NDOFManagerCocoa::GHOST_NDOFManagerCocoa(GHOST_System& sys)
+ : GHOST_NDOFManager(sys)
+ {
+ if (available())
+ {
+ OSErr error = InstallConnexionHandlers(SpaceNavEvent, SpaceNavAdded, SpaceNavRemoved);
+ if (error)
+ {
+ printf("<!> error = %d\n", error);
+ return;
+ }
+
+ // Pascal string *and* a four-letter constant. How old-skool.
+ m_clientID = RegisterConnexionClient('blnd', (UInt8*) "\pblender",
+ kConnexionClientModeTakeOver, kConnexionMaskAll);
+
+ printf("client id = %d\n", m_clientID);
+ }
+ else
+ {
+ printf("<!> SpaceNav driver not found\n");
+ // This isn't a hard error, just means the user doesn't have a SpaceNavigator.
+ }
+ }
+
+GHOST_NDOFManagerCocoa::~GHOST_NDOFManagerCocoa()
+ {
+ UnregisterConnexionClient(m_clientID);
+ CleanupConnexionHandlers();
+ }
+
+bool GHOST_NDOFManagerCocoa::available()
+ {
+// extern OSErr InstallConnexionHandlers() __attribute__((weak_import));
+// ^-- not needed since the entire framework is weak-linked
+ return InstallConnexionHandlers != NULL;
+ }
diff --git a/intern/ghost/intern/GHOST_NDOFManagerWin32.h b/intern/ghost/intern/GHOST_NDOFManagerWin32.h
new file mode 100644
index 00000000000..0570eefa951
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerWin32.h
@@ -0,0 +1,47 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s):
+ * Mike Erwin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef _GHOST_NDOFMANAGERWIN32_H_
+#define _GHOST_NDOFMANAGERWIN32_H_
+
+#include "GHOST_NDOFManager.h"
+
+
+class GHOST_NDOFManagerWin32 : public GHOST_NDOFManager
+{
+public:
+ GHOST_NDOFManagerWin32(GHOST_System& sys)
+ : GHOST_NDOFManager(sys)
+ {}
+
+ // whether multi-axis functionality is available (via the OS or driver)
+ // does not imply that a device is plugged in or being used
+ bool available()
+ {
+ // always available since RawInput is built into Windows
+ return true;
+ }
+};
+
+
+#endif
diff --git a/intern/ghost/intern/GHOST_NDOFManagerX11.h b/intern/ghost/intern/GHOST_NDOFManagerX11.h
new file mode 100644
index 00000000000..4c89bfe0ca6
--- /dev/null
+++ b/intern/ghost/intern/GHOST_NDOFManagerX11.h
@@ -0,0 +1,100 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef _GHOST_NDOFMANAGERX11_H_
+#define _GHOST_NDOFMANAGERX11_H_
+
+#include "GHOST_NDOFManager.h"
+#include "GHOST_Types.h"
+#include "GHOST_WindowX11.h"
+#include "GHOST_EventNDOF.h"
+#include <X11/Xlib.h>
+#include <stdio.h>
+
+class GHOST_NDOFManagerX11 : public GHOST_NDOFManager
+{
+GHOST_WindowX11 * m_ghost_window_x11;
+
+public:
+ GHOST_NDOFManagerX11(GHOST_System& sys)
+ : GHOST_NDOFManager(sys)
+ {}
+
+ void setGHOSTWindowX11(GHOST_WindowX11 * w){
+ if (m_ghost_window_x11 == NULL)
+ m_ghost_window_x11 = w;
+ }
+
+ GHOST_WindowX11 * getGHOSTWindowX11(){
+ return m_ghost_window_x11;
+ }
+
+ // whether multi-axis functionality is available (via the OS or driver)
+ // does not imply that a device is plugged in or being used
+ bool available()
+ {
+ // never available since I've not yet written it!
+ return true;
+ }
+
+ virtual bool sendMotionEvent()
+ {
+ if (m_atRest)
+ return false;
+
+ GHOST_EventNDOFMotion* event = new GHOST_EventNDOFMotion(m_motionTime, getGHOSTWindowX11());
+ GHOST_TEventNDOFMotionData* data = (GHOST_TEventNDOFMotionData*) event->getData();
+
+ const float scale = 1.f/350.f; // SpaceNavigator sends +/- 350 usually
+ // 350 according to their developer's guide; others recommend 500 as comfortable
+
+ // possible future enhancement
+ // scale *= m_sensitivity;
+
+ data->tx = -scale * m_translation[0];
+ data->ty = scale * m_translation[1];
+ data->tz = scale * m_translation[2];
+
+ data->rx = scale * m_rotation[0];
+ data->ry = scale * m_rotation[1];
+ data->rz = scale * m_rotation[2];
+
+ data->dt = 0.001f * (m_motionTime - m_prevMotionTime); // in seconds
+
+ m_prevMotionTime = m_motionTime;
+
+ printf("sending 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);
+
+ if (!m_system.pushEvent(event))
+ return false;
+
+ // 'at rest' test goes at the end so that the first 'rest' event gets sent
+ m_atRest = m_rotation[0] == 0 && m_rotation[1] == 0 && m_rotation[2] == 0 &&
+ m_translation[0] == 0 && m_translation[1] == 0 && m_translation[2] == 0;
+
+ return true;
+ }
+};
+
+
+#endif
diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp
index cb3e97fc574..792adba7ce3 100644
--- a/intern/ghost/intern/GHOST_System.cpp
+++ b/intern/ghost/intern/GHOST_System.cpp
@@ -194,12 +194,15 @@ bool GHOST_System::getFullScreen(void)
bool GHOST_System::dispatchEvents()
{
- bool handled;
- if (m_eventManager) {
- handled = m_eventManager->dispatchEvents();
+ bool handled = false;
+
+ // NDOF Motion event is sent only once per dispatch, so do it now:
+ if (m_ndofManager) {
+ handled |= m_ndofManager->sendMotionEvent();
}
- else {
- handled = false;
+
+ if (m_eventManager) {
+ handled |= m_eventManager->dispatchEvents();
}
m_timerManager->fireTimers(getMilliSeconds());
@@ -243,18 +246,6 @@ GHOST_TSuccess GHOST_System::pushEvent(GHOST_IEvent* event)
return success;
}
-int GHOST_System::openNDOF(GHOST_IWindow* w,
- GHOST_NDOFLibraryInit_fp setNdofLibraryInit,
- GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
- GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen)
-{
- return m_ndofManager->deviceOpen(w,
- setNdofLibraryInit,
- setNdofLibraryShutdown,
- setNdofDeviceOpen);
-}
-
-
GHOST_TSuccess GHOST_System::getModifierKeyState(GHOST_TModifierKeyMask mask, bool& isDown) const
{
GHOST_ModifierKeys keys;
@@ -285,12 +276,6 @@ GHOST_TSuccess GHOST_System::init()
m_timerManager = new GHOST_TimerManager ();
m_windowManager = new GHOST_WindowManager ();
m_eventManager = new GHOST_EventManager ();
- m_ndofManager = new GHOST_NDOFManager();
-
-#if 0
- if(m_ndofManager)
- printf("ndof manager \n");
-#endif
#ifdef GHOST_DEBUG
if (m_eventManager) {
diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h
index b5c64bfceb6..f62c0984c80 100644
--- a/intern/ghost/intern/GHOST_System.h
+++ b/intern/ghost/intern/GHOST_System.h
@@ -191,25 +191,6 @@ public:
virtual GHOST_TSuccess removeEventConsumer(GHOST_IEventConsumer* consumer);
/***************************************************************************************
- ** N-degree of freedom devcice management functionality
- ***************************************************************************************/
-
- /** Inherited from GHOST_ISystem
- * Opens the N-degree of freedom device manager
- * return 0 if device found, 1 otherwise
- */
- virtual int openNDOF(GHOST_IWindow* w,
- GHOST_NDOFLibraryInit_fp setNdofLibraryInit,
- GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
- GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen);
-
-// original patch only
-// GHOST_NDOFEventHandler_fp setNdofEventHandler);
-
-
-
-
- /***************************************************************************************
** Cursor management functionality
***************************************************************************************/
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h
index e7a8178a382..882c365cdb1 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.h
+++ b/intern/ghost/intern/GHOST_SystemCocoa.h
@@ -229,6 +229,11 @@ public:
GHOST_TSuccess handleApplicationBecomeActiveEvent();
/**
+ * External objects should call this when they send an event outside processEvents.
+ */
+ void notifyExternalEventProcessed();
+
+ /**
* @see GHOST_ISystem
*/
int toggleConsole(int action) { return 0; }
@@ -275,7 +280,7 @@ protected:
/** Start time at initialization. */
GHOST_TUns64 m_start_time;
- /** Event has been processed directly by Cocoa and has sent a ghost event to be dispatched */
+ /** Event has been processed directly by Cocoa (or NDOF manager) and has sent a ghost event to be dispatched */
bool m_outsideLoopEventProcessed;
/** Raised window is not yet known by the window manager, so delay application become active event handling */
diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm
index bf401138cf1..1cc692e7b78 100644
--- a/intern/ghost/intern/GHOST_SystemCocoa.mm
+++ b/intern/ghost/intern/GHOST_SystemCocoa.mm
@@ -52,7 +52,7 @@
#include "GHOST_TimerTask.h"
#include "GHOST_WindowManager.h"
#include "GHOST_WindowCocoa.h"
-#include "GHOST_NDOFManager.h"
+#include "GHOST_NDOFManagerCocoa.h"
#include "AssertMacros.h"
#pragma mark KeyMap, mouse converters
@@ -596,6 +596,9 @@ GHOST_TSuccess GHOST_SystemCocoa::init()
GHOST_TSuccess success = GHOST_System::init();
if (success) {
+
+ m_ndofManager = new GHOST_NDOFManagerCocoa(*this);
+
//ProcessSerialNumber psn;
//Carbon stuff to move window & menu to foreground
@@ -1027,6 +1030,11 @@ GHOST_TSuccess GHOST_SystemCocoa::handleApplicationBecomeActiveEvent()
return GHOST_kSuccess;
}
+void GHOST_SystemCocoa::notifyExternalEventProcessed()
+{
+ m_outsideLoopEventProcessed = true;
+}
+
//Note: called from NSWindow delegate
GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, GHOST_WindowCocoa* window)
{
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 9ff73767b4c..315c8b39f44 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -929,6 +929,257 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
}
+// returns angular velocity (0..1), fills axis of rotation
+// (shouldn't live in this file!)
+float ndof_to_angle_axis(const float ndof[3], float axis[3])
+ {
+ const float x = ndof[0];
+ const float y = ndof[1];
+ const float z = ndof[2];
+
+ float angular_velocity = sqrtf(x*x + y*y + z*z);
+
+ float scale = 1.f / angular_velocity;
+
+ // normalize
+ axis[0] = scale * x;
+ axis[1] = scale * y;
+ axis[2] = scale * z;
+
+ return angular_velocity;
+ }
+
+// Mike's version
+static int viewndof_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
+
+ float dt = ndof->dt;
+
+ RegionView3D* rv3d = CTX_wm_region_view3d(C);
+
+ if (dt > 0.25f)
+ /* this is probably the first event for this motion, so set dt to something reasonable */
+ dt = 0.0125f;
+
+ /* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
+ float phi, q1[4];
+ float m[3][3];
+ float m_inv[3][3];
+ float xvec[3] = {1,0,0};
+
+ const float sensitivity = 0.035;
+
+ /* Get the 3x3 matrix and its inverse from the quaternion */
+ quat_to_mat3(m,rv3d->viewquat);
+ invert_m3_m3(m_inv,m);
+
+ /* Determine the direction of the x vector (for rotating up and down) */
+ /* This can likely be computed directly from the quaternion. */
+ mul_m3_v3(m_inv,xvec);
+
+ /* Perform the up/down rotation */
+ phi = sensitivity * -ndof->rx;
+ q1[0] = cos(phi);
+ mul_v3_v3fl(q1+1, xvec, sin(phi));
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
+
+ /* Perform the orbital rotation */
+ phi = sensitivity * ndof->rz;
+ q1[0] = cos(phi);
+ q1[1] = q1[2] = 0.0;
+ q1[3] = sin(phi);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
+
+ ED_region_tag_redraw(CTX_wm_region(C));
+ return OPERATOR_FINISHED;
+ }
+
+// Tom's version
+#if 0
+static int viewndof_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
+
+ float phi, q1[4];
+ float m[3][3];
+ float m_inv[3][3];
+ float xvec[3] = {1,0,0};
+ float yvec[3] = {0,1,0};
+ float vec[3];
+ float mat[3][3];
+ const float rotaSensitivity = 0.007;
+ const float tranSensitivity = 0.120;
+
+ ARegion *ar= CTX_wm_region(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ View3D *v3d = CTX_wm_view3d(C);
+
+ float dt = ndof->dt;
+
+ if (dt > 0.25f) {
+ /* this is probably the first event for this motion, so set dt to something reasonable */
+ dt = 0.0125f;
+ }
+
+ /* Get the 3x3 matrix and its inverse from the quaternion */
+ quat_to_mat3(m,rv3d->viewquat);
+ invert_m3_m3(m_inv,m);
+
+ /* Determine the direction of the x vector (for rotating up and down) */
+ /* This can likely be computed directly from the quaternion. */
+ mul_m3_v3(m_inv,xvec);
+
+ //if(rv3d->persp=!= RV3D_PERSP) //Camera control not supported yet
+ /* Lock fixed views out of using rotation controls */
+ if(rv3d->view!=RV3D_VIEW_FRONT && rv3d->view!=RV3D_VIEW_BACK)
+ if(rv3d->view!=RV3D_VIEW_TOP && rv3d->view!=RV3D_VIEW_BOTTOM)
+ if(rv3d->view!=RV3D_VIEW_RIGHT && rv3d->view!=RV3D_VIEW_LEFT) {
+ // Perform the up/down rotation
+ phi = (rotaSensitivity+dt) * -ndof->rx;
+ q1[0] = cos(phi);
+ mul_v3_v3fl(q1+1, xvec, sin(phi));
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
+
+ // Perform the left/right rotation
+ mul_m3_v3(m_inv,yvec);
+ phi = (rotaSensitivity+dt) * ndof->ry;
+ q1[0] = cos(phi);
+ mul_v3_v3fl(q1+1, yvec, sin(phi));
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
+
+ // Perform the orbital rotation
+ phi = (rotaSensitivity+dt) * ndof->rz;
+ q1[0] = cos(phi);
+ q1[1] = q1[2] = 0.0;
+ q1[3] = sin(phi);
+ mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
+ }
+
+ // Perform Pan translation
+ vec[0]= (tranSensitivity+dt) * ndof->tx;
+ vec[1]= (tranSensitivity+dt) * ndof->tz;
+ //vec[2]= 0.0f;//tranSensitivity * ndof->ty;
+ //window_to_3d_delta(ar, vec, -ndof->tx, -ndof->tz); // experimented a little instead of above
+ copy_m3_m4(mat, rv3d->viewinv);
+ mat[2][2] = 0.0f;
+ mul_m3_v3(mat, vec);
+ // translate the view
+ add_v3_v3(rv3d->ofs, vec);
+
+ // Perform Zoom translation
+ if (ndof->ty!=0.0f){ // TODO - need to add limits to prevent flipping past gridlines
+ rv3d->dist += (tranSensitivity+dt)* ndof->ty;
+ // printf("dist %5.3f view %d grid %f\n",rv3d->dist,rv3d->view,v3d->grid);
+ }
+
+ //printf("Trans tx:%5.2f ty:%5.2f tz:%5.2f \n",ndof->tx, ndof->ty, ndof->tz);
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+#endif
+
+#if 0
+static int viewndof_invoke_1st_try(bContext *C, wmOperator *op, wmEvent *event)
+{
+ wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
+
+ float dt = ndof->dt;
+
+ RegionView3D *rv3d= CTX_wm_region_view3d(C);
+
+ if (dt > 0.25f)
+ /* this is probably the first event for this motion, so set dt to something reasonable */
+ dt = 0.0125f;
+
+ /* very simple for now, move viewpoint along world axes */
+ rv3d->ofs[0] += dt * ndof->tx;
+ rv3d->ofs[1] += dt * ndof->ty;
+ rv3d->ofs[2] += dt * ndof->tz;
+
+// request_depth_update(CTX_wm_region_view3d(C)); /* need this? */
+ ED_region_tag_redraw(CTX_wm_region(C));
+
+ return OPERATOR_FINISHED;
+}
+
+static int viewndof_invoke_2nd_try(bContext *C, wmOperator *op, wmEvent *event)
+{
+ wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
+
+ float dt = ndof->dt;
+
+ RegionView3D* rv3d = CTX_wm_region_view3d(C);
+
+ if (dt > 0.25f)
+ /* this is probably the first event for this motion, so set dt to something reasonable */
+ dt = 0.0125f;
+
+ float axis[3];
+ float angle = ndof_to_angle_axis(&(ndof->rx), axis);
+
+ float eyeball_q[4];// = {0.f};
+
+// float* eyeball_v = eyeball_q + 1;
+
+ axis_angle_to_quat(eyeball_q, axis, angle);
+
+ float eye_conj[4];
+ copy_qt_qt(eye_conj, eyeball_q);
+ conjugate_qt(eye_conj);
+
+// float mat[3][3];
+// quat_to_mat3(mat, rv3d->viewquat);
+/*
+ eyeball_v[0] = dt * ndof->tx;
+ eyeball_v[1] = dt * ndof->ty;
+ eyeball_v[2] = dt * ndof->tz;
+*/
+// mul_m3_v3(mat, eyeball_vector);
+// mul_qt_v3(rv3d->viewquat, eyeball_vector);
+
+ // doesn't this transform v?
+ // v' = (q)(v)(~q)
+
+ float view_q[4];
+ copy_qt_qt(view_q, rv3d->viewquat);
+
+// float q_conj[4];
+// copy_qt_qt(q_conj, q);
+// conjugate_qt(q_conj);
+
+ mul_qt_qtqt(view_q, eyeball_q, view_q);
+ mul_qt_qtqt(view_q, view_q, eye_conj);
+
+// mul_qt_qtqt(eyeball_q, q, eyeball_q);
+// mul_qt_qtqt(eyeball_q, eyeball_q, q_conj);
+
+// add_v3_v3(rv3d->ofs, eyeball_v);
+
+ copy_qt_qt(rv3d->viewquat, view_q);
+
+ ED_region_tag_redraw(CTX_wm_region(C));
+
+ return OPERATOR_FINISHED;
+}
+#endif
+
+void VIEW3D_OT_ndof(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Navigate view";
+ ot->description = "Navigate the view using a 3D mouse.";
+ ot->idname = "VIEW3D_OT_ndof";
+
+ /* api callbacks */
+ ot->invoke = viewndof_invoke;
+ ot->poll = ED_operator_view3d_active;
+
+ /* flags */
+ ot->flag = 0;
+}
+
/* ************************ viewmove ******************************** */
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index cd6bff1ebba..1a148481031 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -72,6 +72,7 @@ void VIEW3D_OT_dolly(struct wmOperatorType *ot);
void VIEW3D_OT_zoom_camera_1_to_1(struct wmOperatorType *ot);
void VIEW3D_OT_move(struct wmOperatorType *ot);
void VIEW3D_OT_rotate(struct wmOperatorType *ot);
+void VIEW3D_OT_ndof(struct wmOperatorType *ot);
void VIEW3D_OT_view_all(struct wmOperatorType *ot);
void VIEW3D_OT_viewnumpad(struct wmOperatorType *ot);
void VIEW3D_OT_view_selected(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 05ef79a9f29..3e99c6992d1 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -64,6 +64,7 @@ void view3d_operatortypes(void)
WM_operatortype_append(VIEW3D_OT_zoom);
WM_operatortype_append(VIEW3D_OT_zoom_camera_1_to_1);
WM_operatortype_append(VIEW3D_OT_dolly);
+ WM_operatortype_append(VIEW3D_OT_ndof);
WM_operatortype_append(VIEW3D_OT_view_all);
WM_operatortype_append(VIEW3D_OT_viewnumpad);
WM_operatortype_append(VIEW3D_OT_view_orbit);
@@ -161,6 +162,10 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", HOMEKEY, KM_PRESS, 0, 0)->ptr, "center", 0); /* only without camera view */
RNA_boolean_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_all", CKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "center", 1);
+ /* 3D mouse */
+ WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON1, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "VIEW3D_OT_ndof", NDOF_MOTION, 0, 0, 0);
+
/* numpad view hotkeys*/
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD0, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_CAMERA);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index 49bd3ede37d..26c394a2ad3 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -377,6 +377,19 @@ typedef struct wmTabletData {
float Ytilt; /* as above */
} wmTabletData;
+typedef struct {
+ /* 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)
+} wmNDOFMotionData;
+
typedef struct wmTimer {
struct wmTimer *next, *prev;
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 2613cb8f14f..96071bc442b 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -2309,6 +2309,26 @@ static void update_tablet_data(wmWindow *win, wmEvent *event)
}
}
+/* adds customdata to event */
+static void attach_ndof_data(wmEvent* event, const GHOST_TEventNDOFMotionData* ghost)
+{
+ wmNDOFMotionData* data = MEM_mallocN(sizeof(wmNDOFMotionData), "customdata NDOF");
+
+ data->tx = ghost->tx;
+ data->ty = ghost->ty;
+ data->tz = ghost->tz;
+
+ data->rx = ghost->rx;
+ data->ry = ghost->ry;
+ data->rz = ghost->rz;
+
+ data->dt = ghost->dt;
+
+ event->custom = EVT_DATA_NDOF_MOTION;
+ event->customdata = data;
+ event->customdatafree = 1;
+}
+
/* imperfect but probably usable... draw/enable drags to other windows */
static wmWindow *wm_event_cursor_other_windows(wmWindowManager *wm, wmWindow *win, wmEvent *evt)
{
@@ -2558,6 +2578,36 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
break;
}
+ case GHOST_kEventNDOFMotion: {
+ event.type = NDOF_MOTION;
+ attach_ndof_data(&event, customdata);
+ wm_event_add(win, &event);
+
+ break;
+ }
+
+ case GHOST_kEventNDOFButton: {
+ GHOST_TEventNDOFButtonData* e = customdata;
+
+ event.type = NDOF_BUTTON_NONE + e->button;
+
+ switch (e->action) {
+ case GHOST_kPress:
+ event.val = KM_PRESS;
+ break;
+ case GHOST_kRelease:
+ event.val = KM_RELEASE;
+ break;
+ }
+
+ event.custom = 0;
+ event.customdata = NULL;
+
+ wm_event_add(win, &event);
+
+ break;
+ }
+
case GHOST_kEventUnknown:
case GHOST_kNumEventTypes:
break;
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index ee080e7c0aa..748f5018e1a 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -45,6 +45,7 @@
#define EVT_DATA_GESTURE 2
#define EVT_DATA_TIMER 3
#define EVT_DATA_LISTBASE 4
+#define EVT_DATA_NDOF_MOTION 5
/* tablet active, matches GHOST_TTabletMode */
#define EVT_TABLET_NONE 0
@@ -77,6 +78,28 @@
#define WHEELOUTMOUSE 13
#define INBETWEEN_MOUSEMOVE 17
+/* NDOF (from SpaceNavigator & friends) */
+#define NDOF_MOTION 0x12
+enum {
+ NDOF_BUTTON_NONE = NDOF_MOTION, /* never sent, used internally */
+ NDOF_BUTTON1,
+ NDOF_BUTTON2/*, the following buttons will be supported soon...
+ NDOF_BUTTON3, and possibly get meaningful names
+ NDOF_BUTTON4,
+ NDOF_BUTTON5,
+ NDOF_BUTTON6,
+ NDOF_BUTTON7,
+ NDOF_BUTTON8,
+ NDOF_BUTTON9,
+ NDOF_BUTTON10,
+ NDOF_BUTTON11,
+ NDOF_BUTTON12,
+ NDOF_BUTTON13,
+ NDOF_BUTTON14,
+ NDOF_BUTTON15,
+ NDOF_BUTTON16*/
+ };
+
/* SYSTEM : 0x01xx */
#define INPUTCHANGE 0x0103 /* input connected or disconnected */