forked from bartvdbraak/blender
3D mouse support from merwin-spacenav branch
This commit is contained in:
commit
56918978b7
@ -179,6 +179,7 @@ option(WITH_LZO "Enable fast LZO compression (used for pointcache)" ON
|
||||
option(WITH_LZMA "Enable best LZMA compression, (used for pointcache)" ON)
|
||||
|
||||
# Misc
|
||||
option(WITH_NDOF "Enable NDOF input devices (SpaceNavigator and friends)" ON)
|
||||
option(WITH_RAYOPTIMIZATION "Enable use of SIMD (SSE) optimizations for the raytracer" ON)
|
||||
if(UNIX AND NOT APPLE)
|
||||
option(WITH_INSTALL_PORTABLE "Install redistributeable runtime, otherwise install into CMAKE_INSTALL_PREFIX" ON)
|
||||
@ -452,6 +453,15 @@ if(UNIX AND NOT APPLE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WITH_NDOF)
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
set(NDOF /usr)
|
||||
set(NDOF_INC ${NDOF}/include)
|
||||
set(NDOF_LIBRARY spnav)
|
||||
set(NDOF_LIBPATH ${NDOF}/lib)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# OpenSuse needs lutil, ArchLinux not, for now keep, can avoid by using --as-needed
|
||||
set(PLATFORM_LINKLIBS "-lutil -lc -lm -lpthread -lstdc++")
|
||||
|
||||
@ -1029,6 +1039,10 @@ elseif(APPLE)
|
||||
set(TIFF_LIBPATH ${TIFF}/lib)
|
||||
endif()
|
||||
|
||||
if (WITH_NDOF)
|
||||
# linker needs "-weak_framework 3DconnexionClient"
|
||||
endif()
|
||||
|
||||
set(EXETYPE MACOSX_BUNDLE)
|
||||
|
||||
set(CMAKE_C_FLAGS_DEBUG "-fno-strict-aliasing -g")
|
||||
|
@ -193,6 +193,9 @@ macro(SETUP_LIBDIRS)
|
||||
if(WITH_MEM_JEMALLOC)
|
||||
link_directories(${JEMALLOC_LIBPATH})
|
||||
endif()
|
||||
if(WITH_NDOF)
|
||||
link_directories(${NDOF_LIBPATH})
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT UNIX)
|
||||
link_directories(${PTHREADS_LIBPATH})
|
||||
@ -314,6 +317,10 @@ macro(setup_liblinks
|
||||
if(WITH_MEM_JEMALLOC)
|
||||
target_link_libraries(${target} ${JEMALLOC_LIBRARIES})
|
||||
endif()
|
||||
if(WITH_NDOF)
|
||||
target_link_libraries(${target} ${NDOF_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT UNIX)
|
||||
target_link_libraries(${target} ${PTHREADS_LIBRARIES})
|
||||
endif()
|
||||
|
@ -265,6 +265,8 @@ if MACOSX_ARCHITECTURE == 'i386':
|
||||
elif MACOSX_ARCHITECTURE == 'x86_64':
|
||||
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-msse2']
|
||||
|
||||
# SpaceNavigator and related 3D mice
|
||||
WITH_BF_3DMOUSE = True
|
||||
|
||||
#############################################################################
|
||||
################### various compile settings and flags ##################
|
||||
@ -294,6 +296,9 @@ if WITH_BF_QUICKTIME == True:
|
||||
else:
|
||||
PLATFORM_LINKFLAGS = PLATFORM_LINKFLAGS+['-framework','QuickTime']
|
||||
|
||||
if WITH_BF_3DMOUSE:
|
||||
PLATFORM_LINKFLAGS = PLATFORM_LINKFLAGS + ['-weak_framework','3DconnexionClient']
|
||||
|
||||
#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']
|
||||
|
||||
|
@ -192,6 +192,10 @@ WITH_BF_OPENMP = True
|
||||
WITH_BF_RAYOPTIMIZATION = True
|
||||
BF_RAYOPTIMIZATION_SSE_FLAGS = ['-msse','-pthread']
|
||||
|
||||
#SpaceNavigator and friends
|
||||
WITH_BF_3DMOUSE = True
|
||||
BF_3DMOUSE_LIB = 'spnav'
|
||||
|
||||
##
|
||||
CC = 'gcc'
|
||||
CXX = 'g++'
|
||||
@ -223,6 +227,8 @@ CXX_WARN = ['-Wno-invalid-offsetof', '-Wno-sign-compare']
|
||||
##FIX_STUBS_WARNINGS = -Wno-unused
|
||||
|
||||
LLIBS = ['util', 'c', 'm', 'dl', 'pthread', 'stdc++']
|
||||
if WITH_BF_3DMOUSE:
|
||||
LLIBS = LLIBS + [BF_3DMOUSE_LIB];
|
||||
##LOPTS = --dynamic
|
||||
##DYNLDFLAGS = -shared $(LDFLAGS)
|
||||
|
||||
|
@ -158,11 +158,13 @@ elseif(APPLE)
|
||||
intern/GHOST_SystemCocoa.mm
|
||||
intern/GHOST_SystemPathsCocoa.mm
|
||||
intern/GHOST_WindowCocoa.mm
|
||||
intern/GHOST_NDOFManagerCocoa.mm
|
||||
|
||||
intern/GHOST_DisplayManagerCocoa.h
|
||||
intern/GHOST_SystemCocoa.h
|
||||
intern/GHOST_SystemPathsCocoa.h
|
||||
intern/GHOST_WindowCocoa.h
|
||||
intern/GHOST_NDOFManagerCocoa.h
|
||||
)
|
||||
else()
|
||||
list(APPEND SRC
|
||||
@ -197,11 +199,13 @@ elseif(UNIX)
|
||||
intern/GHOST_SystemX11.cpp
|
||||
intern/GHOST_SystemPathsX11.cpp
|
||||
intern/GHOST_WindowX11.cpp
|
||||
intern/GHOST_NDOFManagerX11.cpp
|
||||
|
||||
intern/GHOST_DisplayManagerX11.h
|
||||
intern/GHOST_SystemX11.h
|
||||
intern/GHOST_SystemPathsX11.h
|
||||
intern/GHOST_WindowX11.h
|
||||
intern/GHOST_NDOFManagerX11.h
|
||||
)
|
||||
|
||||
if(NOT WITH_INSTALL_PORTABLE)
|
||||
@ -230,6 +234,7 @@ elseif(WIN32)
|
||||
intern/GHOST_SystemPathsWin32.cpp
|
||||
intern/GHOST_WindowWin32.cpp
|
||||
intern/GHOST_DropTargetWin32.cpp
|
||||
intern/GHOST_NDOFManagerWin32.cpp
|
||||
|
||||
intern/GHOST_DisplayManagerWin32.h
|
||||
intern/GHOST_DropTargetWin32.h
|
||||
@ -237,6 +242,7 @@ elseif(WIN32)
|
||||
intern/GHOST_SystemPathsWin32.h
|
||||
intern/GHOST_WindowWin32.h
|
||||
intern/GHOST_TaskbarWin32.h
|
||||
intern/GHOST_NDOFManagerWin32.h
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -289,21 +289,6 @@ extern GHOST_TSuccess GHOST_SetProgressBar(GHOST_WindowHandle windowhandle, floa
|
||||
*/
|
||||
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
|
||||
***************************************************************************************/
|
||||
|
@ -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
|
||||
***************************************************************************************/
|
||||
|
@ -47,11 +47,6 @@ typedef unsigned short GHOST_TUns16;
|
||||
typedef int GHOST_TInt32;
|
||||
typedef unsigned int GHOST_TUns32;
|
||||
|
||||
#ifdef WIN32
|
||||
#define WM_BLND_NDOF_AXIS WM_USER + 1
|
||||
#define WM_BLND_NDOF_BTN WM_USER + 2
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && !defined(FREE_WINDOWS)
|
||||
typedef __int64 GHOST_TInt64;
|
||||
typedef unsigned __int64 GHOST_TUns64;
|
||||
@ -440,37 +435,33 @@ 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 enum {
|
||||
GHOST_kNotStarted,
|
||||
GHOST_kStarting,
|
||||
GHOST_kInProgress,
|
||||
GHOST_kFinishing,
|
||||
GHOST_kFinished
|
||||
} GHOST_TProgress;
|
||||
|
||||
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;
|
||||
/** 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 int (*GHOST_NDOFLibraryInit_fp)(void);
|
||||
typedef void (*GHOST_NDOFLibraryShutdown_fp)(void* deviceHandle);
|
||||
typedef void* (*GHOST_NDOFDeviceOpen_fp)(void* platformData);
|
||||
typedef enum { GHOST_kPress, GHOST_kRelease } GHOST_TButtonAction;
|
||||
// good for mouse or other buttons too, hmmm?
|
||||
|
||||
// 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);
|
||||
typedef struct {
|
||||
GHOST_TButtonAction action;
|
||||
short button;
|
||||
} GHOST_TEventNDOFButtonData;
|
||||
|
||||
typedef struct {
|
||||
/** The key code. */
|
||||
|
@ -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']
|
||||
|
||||
incs = '. ../string #extern/glew/include #source/blender/imbuf #source/blender/makesdna ' + env['BF_OPENGL_INC']
|
||||
|
@ -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;
|
||||
|
@ -35,8 +35,11 @@
|
||||
#include "GHOST_DisplayManagerWin32.h"
|
||||
#include "GHOST_Debug.h"
|
||||
|
||||
// We do not support multiple monitors at the moment
|
||||
#define _WIN32_WINNT 0x501 // require Windows XP or newer
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
// We do not support multiple monitors at the moment
|
||||
#define COMPILE_MULTIMON_STUBS
|
||||
#ifndef FREE_WINDOWS
|
||||
#include <multimon.h>
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "GHOST_Debug.h"
|
||||
#include "GHOST_DropTargetWin32.h"
|
||||
#include <ShellApi.h>
|
||||
|
||||
#ifdef GHOST_DEBUG
|
||||
// utility
|
||||
|
@ -33,7 +33,6 @@
|
||||
#ifndef _GHOST_DROP_TARGET_WIN32_H_
|
||||
#define _GHOST_DROP_TARGET_WIN32_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
#include <GHOST_Types.h>
|
||||
#include "GHOST_WindowWin32.h"
|
||||
|
@ -42,7 +42,7 @@
|
||||
#include "GHOST_EventManager.h"
|
||||
#include <algorithm>
|
||||
#include "GHOST_Debug.h"
|
||||
|
||||
#include <stdio.h> // [mce] temp debug
|
||||
|
||||
GHOST_EventManager::GHOST_EventManager()
|
||||
{
|
||||
|
@ -20,43 +20,39 @@
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
/** \file ghost/intern/GHOST_EventNDOF.h
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef _GHOST_EVENT_NDOF_H_
|
||||
#define _GHOST_EVENT_NDOF_H_
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
class GHOST_EventNDOFMotion : public GHOST_Event
|
||||
{
|
||||
protected:
|
||||
/** translation & rotation from the device. */
|
||||
GHOST_TEventNDOFData m_ndofEventData;
|
||||
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_
|
||||
|
||||
|
@ -15,122 +15,471 @@
|
||||
* 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 <stdio.h> /* just for printf */
|
||||
|
||||
#include "GHOST_NDOFManager.h"
|
||||
#include "GHOST_EventNDOF.h"
|
||||
#include "GHOST_EventKey.h"
|
||||
#include "GHOST_WindowManager.h"
|
||||
#include <string.h> // for memory functions
|
||||
#include <stdio.h> // for error/info reporting
|
||||
#include <math.h>
|
||||
|
||||
|
||||
// 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"
|
||||
#ifdef DEBUG_NDOF_MOTION
|
||||
// printable version of each GHOST_TProgress value
|
||||
static const char* progress_string[] =
|
||||
{"not started","starting","in progress","finishing","finished"};
|
||||
#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);
|
||||
#ifdef DEBUG_NDOF_BUTTONS
|
||||
static const char* ndof_button_names[] = {
|
||||
// used internally, never sent
|
||||
"NDOF_BUTTON_NONE",
|
||||
// these two are available from any 3Dconnexion device
|
||||
"NDOF_BUTTON_MENU",
|
||||
"NDOF_BUTTON_FIT",
|
||||
// standard views
|
||||
"NDOF_BUTTON_TOP",
|
||||
"NDOF_BUTTON_BOTTOM",
|
||||
"NDOF_BUTTON_LEFT",
|
||||
"NDOF_BUTTON_RIGHT",
|
||||
"NDOF_BUTTON_FRONT",
|
||||
"NDOF_BUTTON_BACK",
|
||||
// more views
|
||||
"NDOF_BUTTON_ISO1",
|
||||
"NDOF_BUTTON_ISO2",
|
||||
// 90 degree rotations
|
||||
"NDOF_BUTTON_ROLL_CW",
|
||||
"NDOF_BUTTON_ROLL_CCW",
|
||||
"NDOF_BUTTON_SPIN_CW",
|
||||
"NDOF_BUTTON_SPIN_CCW",
|
||||
"NDOF_BUTTON_TILT_CW",
|
||||
"NDOF_BUTTON_TILT_CCW",
|
||||
// device control
|
||||
"NDOF_BUTTON_ROTATE",
|
||||
"NDOF_BUTTON_PANZOOM",
|
||||
"NDOF_BUTTON_DOMINANT",
|
||||
"NDOF_BUTTON_PLUS",
|
||||
"NDOF_BUTTON_MINUS",
|
||||
// general-purpose buttons
|
||||
"NDOF_BUTTON_1",
|
||||
"NDOF_BUTTON_2",
|
||||
"NDOF_BUTTON_3",
|
||||
"NDOF_BUTTON_4",
|
||||
"NDOF_BUTTON_5",
|
||||
"NDOF_BUTTON_6",
|
||||
"NDOF_BUTTON_7",
|
||||
"NDOF_BUTTON_8",
|
||||
"NDOF_BUTTON_9",
|
||||
"NDOF_BUTTON_10",
|
||||
};
|
||||
#endif
|
||||
#if defined(WITH_HEADLESS)
|
||||
/* do nothing */
|
||||
#elif defined(_WIN32) || defined(__APPLE__)
|
||||
m_DeviceHandle = ndofDeviceOpen((void *)¤tNdofValues);
|
||||
#elif defined(WITH_GHOST_SDL)
|
||||
/* do nothing */
|
||||
|
||||
static const NDOF_ButtonT SpaceNavigator_HID_map[] =
|
||||
{
|
||||
NDOF_BUTTON_MENU,
|
||||
NDOF_BUTTON_FIT
|
||||
};
|
||||
|
||||
static const NDOF_ButtonT SpaceExplorer_HID_map[] =
|
||||
{
|
||||
NDOF_BUTTON_1,
|
||||
NDOF_BUTTON_2,
|
||||
NDOF_BUTTON_TOP,
|
||||
NDOF_BUTTON_LEFT,
|
||||
NDOF_BUTTON_RIGHT,
|
||||
NDOF_BUTTON_FRONT,
|
||||
NDOF_BUTTON_NONE, // esc key
|
||||
NDOF_BUTTON_NONE, // alt key
|
||||
NDOF_BUTTON_NONE, // shift key
|
||||
NDOF_BUTTON_NONE, // ctrl key
|
||||
NDOF_BUTTON_FIT,
|
||||
NDOF_BUTTON_MENU,
|
||||
NDOF_BUTTON_PLUS,
|
||||
NDOF_BUTTON_MINUS,
|
||||
NDOF_BUTTON_ROTATE
|
||||
};
|
||||
|
||||
static const NDOF_ButtonT SpacePilotPro_HID_map[] =
|
||||
{
|
||||
NDOF_BUTTON_MENU,
|
||||
NDOF_BUTTON_FIT,
|
||||
NDOF_BUTTON_TOP,
|
||||
NDOF_BUTTON_LEFT,
|
||||
NDOF_BUTTON_RIGHT,
|
||||
NDOF_BUTTON_FRONT,
|
||||
NDOF_BUTTON_BOTTOM,
|
||||
NDOF_BUTTON_BACK,
|
||||
NDOF_BUTTON_ROLL_CW,
|
||||
NDOF_BUTTON_ROLL_CCW,
|
||||
NDOF_BUTTON_ISO1,
|
||||
NDOF_BUTTON_ISO2,
|
||||
NDOF_BUTTON_1,
|
||||
NDOF_BUTTON_2,
|
||||
NDOF_BUTTON_3,
|
||||
NDOF_BUTTON_4,
|
||||
NDOF_BUTTON_5,
|
||||
NDOF_BUTTON_6,
|
||||
NDOF_BUTTON_7,
|
||||
NDOF_BUTTON_8,
|
||||
NDOF_BUTTON_9,
|
||||
NDOF_BUTTON_10,
|
||||
NDOF_BUTTON_NONE, // esc key
|
||||
NDOF_BUTTON_NONE, // alt key
|
||||
NDOF_BUTTON_NONE, // shift key
|
||||
NDOF_BUTTON_NONE, // ctrl key
|
||||
NDOF_BUTTON_ROTATE,
|
||||
NDOF_BUTTON_PANZOOM,
|
||||
NDOF_BUTTON_DOMINANT,
|
||||
NDOF_BUTTON_PLUS,
|
||||
NDOF_BUTTON_MINUS
|
||||
};
|
||||
|
||||
static const NDOF_ButtonT SpacePilot_HID_map[] =
|
||||
// this is the older SpacePilot (sans Pro)
|
||||
// thanks to polosson for the info in this table
|
||||
{
|
||||
NDOF_BUTTON_1,
|
||||
NDOF_BUTTON_2,
|
||||
NDOF_BUTTON_3,
|
||||
NDOF_BUTTON_4,
|
||||
NDOF_BUTTON_5,
|
||||
NDOF_BUTTON_6,
|
||||
NDOF_BUTTON_TOP,
|
||||
NDOF_BUTTON_LEFT,
|
||||
NDOF_BUTTON_RIGHT,
|
||||
NDOF_BUTTON_FRONT,
|
||||
NDOF_BUTTON_NONE, // esc key
|
||||
NDOF_BUTTON_NONE, // alt key
|
||||
NDOF_BUTTON_NONE, // shift key
|
||||
NDOF_BUTTON_NONE, // ctrl key
|
||||
NDOF_BUTTON_FIT,
|
||||
NDOF_BUTTON_MENU,
|
||||
NDOF_BUTTON_PLUS,
|
||||
NDOF_BUTTON_MINUS,
|
||||
NDOF_BUTTON_DOMINANT,
|
||||
NDOF_BUTTON_ROTATE,
|
||||
NDOF_BUTTON_NONE // the CONFIG button -- what does it do?
|
||||
};
|
||||
|
||||
GHOST_NDOFManager::GHOST_NDOFManager(GHOST_System& sys)
|
||||
: m_system(sys)
|
||||
, m_deviceType(NDOF_UnknownDevice) // each platform has its own device detection code
|
||||
, m_buttonCount(0)
|
||||
, m_buttonMask(0)
|
||||
, m_buttons(0)
|
||||
, m_motionTime(0)
|
||||
, m_prevMotionTime(0)
|
||||
, m_motionState(GHOST_kNotStarted)
|
||||
, m_motionEventPending(false)
|
||||
, m_deadZone(0.f)
|
||||
{
|
||||
// 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));
|
||||
|
||||
#ifdef WITH_BF_3DMOUSE
|
||||
puts("WITH_BF_3DMOUSE is defined!");
|
||||
#else
|
||||
GHOST_SystemX11 *sys;
|
||||
sys = static_cast<GHOST_SystemX11*>(GHOST_ISystem::getSystem());
|
||||
void *ndofInfo = sys->prepareNdofInfo(¤tNdofValues);
|
||||
m_DeviceHandle = ndofDeviceOpen(ndofInfo);
|
||||
puts("WITH_BF_3DMOUSE is not defined.");
|
||||
#endif
|
||||
return (Pid > 0) ? 0 : 1;
|
||||
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GHOST_NDOFManager::available() const
|
||||
bool GHOST_NDOFManager::setDevice(unsigned short vendor_id, unsigned short product_id)
|
||||
{
|
||||
return m_DeviceHandle != 0;
|
||||
// default to NDOF_UnknownDevice so rogue button events will get discarded
|
||||
// "mystery device" owners can help build a HID_map for their hardware
|
||||
|
||||
switch (vendor_id)
|
||||
{
|
||||
case 0x046D: // Logitech (3Dconnexion)
|
||||
switch (product_id)
|
||||
{
|
||||
// -- current devices --
|
||||
case 0xC626:
|
||||
puts("ndof: using SpaceNavigator");
|
||||
m_deviceType = NDOF_SpaceNavigator;
|
||||
m_buttonCount = 2;
|
||||
break;
|
||||
case 0xC628:
|
||||
puts("ndof: using SpaceNavigator for Notebooks");
|
||||
m_deviceType = NDOF_SpaceNavigator; // for Notebooks
|
||||
m_buttonCount = 2;
|
||||
break;
|
||||
case 0xC627:
|
||||
puts("ndof: using SpaceExplorer");
|
||||
m_deviceType = NDOF_SpaceExplorer;
|
||||
m_buttonCount = 15;
|
||||
break;
|
||||
case 0xC629:
|
||||
puts("ndof: using SpacePilotPro");
|
||||
m_deviceType = NDOF_SpacePilotPro;
|
||||
m_buttonCount = 31;
|
||||
break;
|
||||
|
||||
// -- older devices --
|
||||
case 0xC625:
|
||||
puts("ndof: using SpacePilot");
|
||||
m_deviceType = NDOF_SpacePilot;
|
||||
m_buttonCount = 21;
|
||||
break;
|
||||
|
||||
case 0xC623:
|
||||
puts("ndof: SpaceTraveler not supported, please file a bug report");
|
||||
m_buttonCount = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("ndof: unknown Logitech product %04hx\n", product_id);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("ndof: unknown device %04hx:%04hx\n", vendor_id, product_id);
|
||||
}
|
||||
|
||||
bool
|
||||
GHOST_NDOFManager::event_present() const
|
||||
if (m_deviceType == NDOF_UnknownDevice)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
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);
|
||||
m_buttonMask = ~(-1 << m_buttonCount);
|
||||
|
||||
#ifdef DEBUG_NDOF_BUTTONS
|
||||
printf("ndof: %d buttons -> hex:%X\n", m_buttonCount, m_buttonMask);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}else
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_NDOFManager::updateTranslation(short t[3], GHOST_TUns64 time)
|
||||
{
|
||||
memcpy(m_translation, t, sizeof(m_translation));
|
||||
m_motionTime = time;
|
||||
m_motionEventPending = true;
|
||||
}
|
||||
|
||||
void GHOST_NDOFManager::updateRotation(short r[3], GHOST_TUns64 time)
|
||||
{
|
||||
memcpy(m_rotation, r, sizeof(m_rotation));
|
||||
m_motionTime = time;
|
||||
m_motionEventPending = true;
|
||||
}
|
||||
|
||||
void GHOST_NDOFManager::sendButtonEvent(NDOF_ButtonT button, bool press, GHOST_TUns64 time, GHOST_IWindow* window)
|
||||
{
|
||||
GHOST_EventNDOFButton* event = new GHOST_EventNDOFButton(time, window);
|
||||
GHOST_TEventNDOFButtonData* data = (GHOST_TEventNDOFButtonData*) event->getData();
|
||||
|
||||
data->action = press ? GHOST_kPress : GHOST_kRelease;
|
||||
data->button = button;
|
||||
|
||||
#ifdef DEBUG_NDOF_BUTTONS
|
||||
printf("%s %s\n", ndof_button_names[button], press ? "pressed" : "released");
|
||||
#endif
|
||||
|
||||
m_system.pushEvent(event);
|
||||
}
|
||||
|
||||
void GHOST_NDOFManager::sendKeyEvent(GHOST_TKey key, bool press, GHOST_TUns64 time, GHOST_IWindow* window)
|
||||
{
|
||||
GHOST_TEventType type = press ? GHOST_kEventKeyDown : GHOST_kEventKeyUp;
|
||||
GHOST_EventKey* event = new GHOST_EventKey(time, type, window, key);
|
||||
|
||||
#ifdef DEBUG_NDOF_BUTTONS
|
||||
printf("keyboard %s\n", press ? "down" : "up");
|
||||
#endif
|
||||
|
||||
m_system.pushEvent(event);
|
||||
}
|
||||
|
||||
void GHOST_NDOFManager::updateButton(int button_number, bool press, GHOST_TUns64 time)
|
||||
{
|
||||
GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow();
|
||||
|
||||
#ifdef DEBUG_NDOF_BUTTONS
|
||||
if (m_deviceType != NDOF_UnknownDevice)
|
||||
printf("ndof: button %d -> ", button_number);
|
||||
#endif
|
||||
|
||||
switch (m_deviceType)
|
||||
{
|
||||
case NDOF_SpaceNavigator:
|
||||
sendButtonEvent(SpaceNavigator_HID_map[button_number], press, time, window);
|
||||
break;
|
||||
case NDOF_SpaceExplorer:
|
||||
switch (button_number)
|
||||
{
|
||||
case 6: sendKeyEvent(GHOST_kKeyEsc, press, time, window); break;
|
||||
case 7: sendKeyEvent(GHOST_kKeyLeftAlt, press, time, window); break;
|
||||
case 8: sendKeyEvent(GHOST_kKeyLeftShift, press, time, window); break;
|
||||
case 9: sendKeyEvent(GHOST_kKeyLeftControl, press, time, window); break;
|
||||
default: sendButtonEvent(SpaceExplorer_HID_map[button_number], press, time, window);
|
||||
}
|
||||
break;
|
||||
case NDOF_SpacePilotPro:
|
||||
switch (button_number)
|
||||
{
|
||||
case 22: sendKeyEvent(GHOST_kKeyEsc, press, time, window); break;
|
||||
case 23: sendKeyEvent(GHOST_kKeyLeftAlt, press, time, window); break;
|
||||
case 24: sendKeyEvent(GHOST_kKeyLeftShift, press, time, window); break;
|
||||
case 25: sendKeyEvent(GHOST_kKeyLeftControl, press, time, window); break;
|
||||
default: sendButtonEvent(SpacePilotPro_HID_map[button_number], press, time, window);
|
||||
}
|
||||
break;
|
||||
case NDOF_SpacePilot:
|
||||
switch (button_number)
|
||||
{
|
||||
case 10: sendKeyEvent(GHOST_kKeyEsc, press, time, window); break;
|
||||
case 11: sendKeyEvent(GHOST_kKeyLeftAlt, press, time, window); break;
|
||||
case 12: sendKeyEvent(GHOST_kKeyLeftShift, press, time, window); break;
|
||||
case 13: sendKeyEvent(GHOST_kKeyLeftControl, press, time, window); break;
|
||||
case 20: puts("ndof: ignoring CONFIG button"); break;
|
||||
default: sendButtonEvent(SpacePilot_HID_map[button_number], press, time, window);
|
||||
}
|
||||
break;
|
||||
case NDOF_UnknownDevice:
|
||||
printf("ndof: button %d on unknown device (ignoring)\n", button_number);
|
||||
}
|
||||
|
||||
int mask = 1 << button_number;
|
||||
if (press)
|
||||
m_buttons |= mask; // set this button's bit
|
||||
else
|
||||
m_buttons &= ~mask; // clear this button's bit
|
||||
}
|
||||
|
||||
void GHOST_NDOFManager::updateButtons(int button_bits, GHOST_TUns64 time)
|
||||
{
|
||||
button_bits &= m_buttonMask; // discard any "garbage" bits
|
||||
|
||||
int diff = m_buttons ^ button_bits;
|
||||
|
||||
for (int button_number = 0; button_number < m_buttonCount; ++button_number)
|
||||
{
|
||||
int mask = 1 << button_number;
|
||||
|
||||
if (diff & mask)
|
||||
{
|
||||
bool press = button_bits & mask;
|
||||
updateButton(button_number, press, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_NDOFManager::setDeadZone(float dz)
|
||||
{
|
||||
if (dz < 0.f)
|
||||
// negative values don't make sense, so clamp at zero
|
||||
dz = 0.f;
|
||||
else if (dz > 0.5f)
|
||||
// warn the rogue user/programmer, but allow it
|
||||
printf("ndof: dead zone of %.2f is rather high...\n", dz);
|
||||
|
||||
m_deadZone = dz;
|
||||
|
||||
printf("ndof: dead zone set to %.2f\n", dz);
|
||||
}
|
||||
|
||||
static bool atHomePosition(GHOST_TEventNDOFMotionData* ndof)
|
||||
{
|
||||
#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)
|
||||
{
|
||||
if (threshold == 0.f)
|
||||
return atHomePosition(ndof);
|
||||
else
|
||||
{
|
||||
#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_motionEventPending)
|
||||
return false;
|
||||
|
||||
m_motionEventPending = false; // any pending motion is handled right now
|
||||
|
||||
GHOST_IWindow* window = m_system.getWindowManager()->getActiveWindow();
|
||||
if (window == NULL)
|
||||
return false; // delivery will fail, so don't bother sending
|
||||
|
||||
GHOST_EventNDOFMotion* event = new GHOST_EventNDOFMotion(m_motionTime, window);
|
||||
GHOST_TEventNDOFMotionData* data = (GHOST_TEventNDOFMotionData*) event->getData();
|
||||
|
||||
// scale axis values here to normalize them to around +/- 1
|
||||
// they are scaled again for overall sensitivity in the WM based on user prefs
|
||||
|
||||
const float scale = 1.f / 350.f; // 3Dconnexion devices send +/- 350 usually
|
||||
|
||||
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
|
||||
|
||||
bool handMotion = !nearHomePosition(data, m_deadZone);
|
||||
|
||||
// determine what kind of motion event to send (Starting, InProgress, Finishing)
|
||||
// and where that leaves this NDOF manager (NotStarted, InProgress, Finished)
|
||||
switch (m_motionState)
|
||||
{
|
||||
case GHOST_kNotStarted:
|
||||
case GHOST_kFinished:
|
||||
if (handMotion)
|
||||
{
|
||||
data->progress = GHOST_kStarting;
|
||||
m_motionState = GHOST_kInProgress;
|
||||
// prev motion time will be ancient, so just make up something reasonable
|
||||
data->dt = 0.0125f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// send no event and keep current state
|
||||
delete event;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case GHOST_kInProgress:
|
||||
if (handMotion)
|
||||
{
|
||||
data->progress = GHOST_kInProgress;
|
||||
// keep InProgress state
|
||||
}
|
||||
else
|
||||
{
|
||||
data->progress = GHOST_kFinishing;
|
||||
m_motionState = GHOST_kFinished;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
#ifdef DEBUG_NDOF_MOTION
|
||||
printf("ndof motion sent -- %s\n", progress_string[data->progress]);
|
||||
|
||||
// show details about this motion event
|
||||
printf(" 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);
|
||||
#endif
|
||||
|
||||
m_system.pushEvent(event);
|
||||
|
||||
m_prevMotionTime = m_motionTime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -15,43 +15,144 @@
|
||||
* 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.h
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _GHOST_NDOFMANAGER_H_
|
||||
#define _GHOST_NDOFMANAGER_H_
|
||||
|
||||
#include "GHOST_System.h"
|
||||
#include "GHOST_IWindow.h"
|
||||
|
||||
|
||||
// #define DEBUG_NDOF_MOTION
|
||||
#define DEBUG_NDOF_BUTTONS
|
||||
|
||||
typedef enum {
|
||||
NDOF_UnknownDevice, // <-- motion will work fine, buttons are ignored
|
||||
|
||||
// current devices
|
||||
NDOF_SpaceNavigator,
|
||||
NDOF_SpaceExplorer,
|
||||
NDOF_SpacePilotPro,
|
||||
|
||||
// older devices
|
||||
NDOF_SpacePilot
|
||||
|
||||
} NDOF_DeviceT;
|
||||
|
||||
// NDOF device button event types
|
||||
typedef enum {
|
||||
// used internally, never sent
|
||||
NDOF_BUTTON_NONE,
|
||||
// these two are available from any 3Dconnexion device
|
||||
NDOF_BUTTON_MENU,
|
||||
NDOF_BUTTON_FIT,
|
||||
// standard views
|
||||
NDOF_BUTTON_TOP,
|
||||
NDOF_BUTTON_BOTTOM,
|
||||
NDOF_BUTTON_LEFT,
|
||||
NDOF_BUTTON_RIGHT,
|
||||
NDOF_BUTTON_FRONT,
|
||||
NDOF_BUTTON_BACK,
|
||||
// more views
|
||||
NDOF_BUTTON_ISO1,
|
||||
NDOF_BUTTON_ISO2,
|
||||
// 90 degree rotations
|
||||
// these don't all correspond to physical buttons
|
||||
NDOF_BUTTON_ROLL_CW,
|
||||
NDOF_BUTTON_ROLL_CCW,
|
||||
NDOF_BUTTON_SPIN_CW,
|
||||
NDOF_BUTTON_SPIN_CCW,
|
||||
NDOF_BUTTON_TILT_CW,
|
||||
NDOF_BUTTON_TILT_CCW,
|
||||
// device control
|
||||
NDOF_BUTTON_ROTATE,
|
||||
NDOF_BUTTON_PANZOOM,
|
||||
NDOF_BUTTON_DOMINANT,
|
||||
NDOF_BUTTON_PLUS,
|
||||
NDOF_BUTTON_MINUS,
|
||||
// general-purpose buttons
|
||||
// users can assign functions via keymap editor
|
||||
NDOF_BUTTON_1,
|
||||
NDOF_BUTTON_2,
|
||||
NDOF_BUTTON_3,
|
||||
NDOF_BUTTON_4,
|
||||
NDOF_BUTTON_5,
|
||||
NDOF_BUTTON_6,
|
||||
NDOF_BUTTON_7,
|
||||
NDOF_BUTTON_8,
|
||||
NDOF_BUTTON_9,
|
||||
NDOF_BUTTON_10,
|
||||
|
||||
} NDOF_ButtonT;
|
||||
|
||||
class GHOST_NDOFManager
|
||||
{
|
||||
public:
|
||||
GHOST_NDOFManager();
|
||||
virtual ~GHOST_NDOFManager();
|
||||
GHOST_NDOFManager(GHOST_System&);
|
||||
|
||||
int deviceOpen(GHOST_IWindow* window,
|
||||
GHOST_NDOFLibraryInit_fp setNdofLibraryInit,
|
||||
GHOST_NDOFLibraryShutdown_fp setNdofLibraryShutdown,
|
||||
GHOST_NDOFDeviceOpen_fp setNdofDeviceOpen);
|
||||
virtual ~GHOST_NDOFManager() {};
|
||||
|
||||
void GHOST_NDOFGetDatas(GHOST_TEventNDOFData &datas) const;
|
||||
// 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;
|
||||
|
||||
bool available() const;
|
||||
bool event_present() const;
|
||||
// each platform's device detection should call this
|
||||
// use standard USB/HID identifiers
|
||||
bool setDevice(unsigned short vendor_id, unsigned short product_id);
|
||||
|
||||
// filter out small/accidental/uncalibrated motions by
|
||||
// setting up a "dead zone" around home position
|
||||
// set to 0 to disable
|
||||
// 0.1 is a safe and reasonable value
|
||||
void setDeadZone(float);
|
||||
|
||||
// the latest raw axis data from the device
|
||||
// NOTE: axis data should be in blender view coordinates
|
||||
// +X is to the right
|
||||
// +Y is up
|
||||
// +Z is out of the screen
|
||||
// for rotations, look from origin to each +axis
|
||||
// rotations are + when CCW, - when CW
|
||||
// each platform is responsible for getting axis data into this form
|
||||
// these values should not be scaled (just shuffled or flipped)
|
||||
void updateTranslation(short t[3], GHOST_TUns64 time);
|
||||
void updateRotation(short r[3], GHOST_TUns64 time);
|
||||
|
||||
// the latest raw button data from the device
|
||||
// use HID button encoding (not NDOF_ButtonT)
|
||||
void updateButton(int button_number, bool press, GHOST_TUns64 time);
|
||||
void updateButtons(int button_bits, GHOST_TUns64 time);
|
||||
// NDOFButton events are sent immediately
|
||||
|
||||
// processes and sends most recent raw data as an NDOFMotion event
|
||||
// returns whether an event was sent
|
||||
bool sendMotionEvent();
|
||||
|
||||
protected:
|
||||
void* m_DeviceHandle;
|
||||
GHOST_System& m_system;
|
||||
|
||||
private:
|
||||
void sendButtonEvent(NDOF_ButtonT, bool press, GHOST_TUns64 time, GHOST_IWindow*);
|
||||
void sendKeyEvent(GHOST_TKey, bool press, GHOST_TUns64 time, GHOST_IWindow*);
|
||||
|
||||
NDOF_DeviceT m_deviceType;
|
||||
int m_buttonCount;
|
||||
int m_buttonMask;
|
||||
|
||||
short m_translation[3];
|
||||
short m_rotation[3];
|
||||
int m_buttons; // bit field
|
||||
|
||||
GHOST_TUns64 m_motionTime; // in milliseconds
|
||||
GHOST_TUns64 m_prevMotionTime; // time of most recent Motion event sent
|
||||
|
||||
GHOST_TProgress m_motionState;
|
||||
bool m_motionEventPending;
|
||||
float m_deadZone; // discard motion with each component < this
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
48
intern/ghost/intern/GHOST_NDOFManagerCocoa.h
Normal file
48
intern/ghost/intern/GHOST_NDOFManagerCocoa.h
Normal file
@ -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 NDOF manager 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
|
172
intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
Normal file
172
intern/ghost/intern/GHOST_NDOFManagerCocoa.mm
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* ***** 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 functions need to talk to these objects:
|
||||
static GHOST_SystemCocoa* ghost_system = NULL;
|
||||
static GHOST_NDOFManager* ndof_manager = NULL;
|
||||
|
||||
// 3Dconnexion drivers before 10.x are "old"
|
||||
// not all buttons will work
|
||||
static bool has_old_driver = true;
|
||||
|
||||
static void NDOF_DeviceAdded(io_connect_t connection)
|
||||
{
|
||||
printf("ndof: device added\n"); // change these: printf --> informational reports
|
||||
|
||||
#if 0 // device preferences will be useful some day
|
||||
ConnexionDevicePrefs p;
|
||||
ConnexionGetCurrentDevicePrefs(kDevID_AnyDevice, &p);
|
||||
#endif
|
||||
|
||||
// determine exactly which device is plugged in
|
||||
SInt32 result = 0;
|
||||
ConnexionControl(kConnexionCtlGetDeviceID, 0, &result);
|
||||
unsigned short vendorID = result >> 16;
|
||||
unsigned short productID = result & 0xffff;
|
||||
|
||||
ndof_manager->setDevice(vendorID, productID);
|
||||
}
|
||||
|
||||
static void NDOF_DeviceRemoved(io_connect_t connection)
|
||||
{
|
||||
printf("ndof: device removed\n");
|
||||
}
|
||||
|
||||
static void NDOF_DeviceEvent(io_connect_t connection, natural_t messageType, void* messageArgument)
|
||||
{
|
||||
switch (messageType)
|
||||
{
|
||||
case kConnexionMsgDeviceState:
|
||||
{
|
||||
ConnexionDeviceState* s = (ConnexionDeviceState*)messageArgument;
|
||||
|
||||
GHOST_TUns64 now = ghost_system->getMilliSeconds();
|
||||
|
||||
switch (s->command)
|
||||
{
|
||||
case kConnexionCmdHandleAxis:
|
||||
{
|
||||
// convert to blender view coordinates
|
||||
short t[3] = {s->axis[0], -(s->axis[2]), s->axis[1]};
|
||||
short r[3] = {-(s->axis[3]), s->axis[5], -(s->axis[4])};
|
||||
|
||||
ndof_manager->updateTranslation(t, now);
|
||||
ndof_manager->updateRotation(r, now);
|
||||
|
||||
ghost_system->notifyExternalEventProcessed();
|
||||
break;
|
||||
}
|
||||
case kConnexionCmdHandleButtons:
|
||||
{
|
||||
int button_bits = has_old_driver ? s->buttons8 : s->buttons;
|
||||
ndof_manager->updateButtons(button_bits, now);
|
||||
ghost_system->notifyExternalEventProcessed();
|
||||
break;
|
||||
}
|
||||
case kConnexionCmdAppSpecific:
|
||||
printf("ndof: app-specific command, param = %hd, value = %d\n", s->param, s->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("ndof: mystery device command %d\n", s->command);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kConnexionMsgPrefsChanged:
|
||||
// printf("ndof: prefs changed\n"); // this includes app switches
|
||||
// TODO: look through updated prefs for things blender cares about
|
||||
break;
|
||||
case kConnexionMsgCalibrateDevice:
|
||||
printf("ndof: calibrate\n"); // but what should blender do?
|
||||
break;
|
||||
case kConnexionMsgDoMapping:
|
||||
// printf("ndof: driver did something\n");
|
||||
// sent when the driver itself consumes an NDOF event
|
||||
// and performs whatever action is set in user prefs
|
||||
// 3Dx header file says to ignore these
|
||||
break;
|
||||
default:
|
||||
printf("ndof: mystery event %d\n", messageType);
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_NDOFManagerCocoa::GHOST_NDOFManagerCocoa(GHOST_System& sys)
|
||||
: GHOST_NDOFManager(sys)
|
||||
{
|
||||
if (available())
|
||||
{
|
||||
// give static functions something to talk to:
|
||||
ghost_system = dynamic_cast<GHOST_SystemCocoa*>(&sys);
|
||||
ndof_manager = this;
|
||||
|
||||
OSErr error = InstallConnexionHandlers(NDOF_DeviceEvent, NDOF_DeviceAdded, NDOF_DeviceRemoved);
|
||||
if (error)
|
||||
{
|
||||
printf("ndof: error %d while installing handlers\n", error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pascal string *and* a four-letter constant. How old-skool.
|
||||
m_clientID = RegisterConnexionClient('blnd', (UInt8*) "\007blender",
|
||||
kConnexionClientModeTakeOver, kConnexionMaskAll);
|
||||
|
||||
// printf("ndof: client id = %d\n", m_clientID);
|
||||
|
||||
if (SetConnexionClientButtonMask != NULL)
|
||||
{
|
||||
has_old_driver = false;
|
||||
SetConnexionClientButtonMask(m_clientID, kConnexionMaskAllButtons);
|
||||
}
|
||||
else
|
||||
printf("ndof: old 3Dx driver installed, some buttons may not work\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ndof: 3Dx driver not found\n");
|
||||
// This isn't a hard error, just means the user doesn't have a 3D mouse.
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_NDOFManagerCocoa::~GHOST_NDOFManagerCocoa()
|
||||
{
|
||||
UnregisterConnexionClient(m_clientID);
|
||||
CleanupConnexionHandlers();
|
||||
ghost_system = NULL;
|
||||
ndof_manager = NULL;
|
||||
}
|
||||
|
||||
bool GHOST_NDOFManagerCocoa::available()
|
||||
{
|
||||
// extern OSErr InstallConnexionHandlers() __attribute__((weak_import));
|
||||
// ^^ not needed since the entire framework is weak-linked
|
||||
return InstallConnexionHandlers != NULL;
|
||||
// this means that the driver is installed and dynamically linked to blender
|
||||
}
|
37
intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
Normal file
37
intern/ghost/intern/GHOST_NDOFManagerWin32.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* ***** 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_NDOFManagerWin32.h"
|
||||
|
||||
|
||||
GHOST_NDOFManagerWin32::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 GHOST_NDOFManagerWin32::available()
|
||||
{
|
||||
// always available since RawInput is built into Windows
|
||||
return true;
|
||||
}
|
38
intern/ghost/intern/GHOST_NDOFManagerWin32.h
Normal file
38
intern/ghost/intern/GHOST_NDOFManagerWin32.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* ***** 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&);
|
||||
bool available();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
110
intern/ghost/intern/GHOST_NDOFManagerX11.cpp
Normal file
110
intern/ghost/intern/GHOST_NDOFManagerX11.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* ***** 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_NDOFManagerX11.h"
|
||||
#include "GHOST_SystemX11.h"
|
||||
#include <spnav.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
GHOST_NDOFManagerX11::GHOST_NDOFManagerX11(GHOST_System& sys)
|
||||
: GHOST_NDOFManager(sys)
|
||||
, m_available(false)
|
||||
{
|
||||
setDeadZone(0.1f); // how to calibrate on Linux? throw away slight motion!
|
||||
|
||||
if (spnav_open() != -1)
|
||||
{
|
||||
// determine exactly which device (if any) is plugged in
|
||||
|
||||
#define MAX_LINE_LENGTH 100
|
||||
|
||||
// look for USB devices with Logitech's vendor ID
|
||||
FILE* command_output = popen("lsusb -d 046d:","r");
|
||||
if (command_output)
|
||||
{
|
||||
char line[MAX_LINE_LENGTH] = {0};
|
||||
while (fgets(line, MAX_LINE_LENGTH, command_output))
|
||||
{
|
||||
unsigned short vendor_id = 0, product_id = 0;
|
||||
if (sscanf(line, "Bus %*d Device %*d: ID %hx:%hx", &vendor_id, &product_id) == 2)
|
||||
if (setDevice(vendor_id, product_id))
|
||||
{
|
||||
m_available = true;
|
||||
break; // stop looking once the first 3D mouse is found
|
||||
}
|
||||
}
|
||||
pclose(command_output);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ndof: spacenavd not found\n");
|
||||
// This isn't a hard error, just means the user doesn't have a 3D mouse.
|
||||
}
|
||||
}
|
||||
|
||||
GHOST_NDOFManagerX11::~GHOST_NDOFManagerX11()
|
||||
{
|
||||
if (m_available)
|
||||
spnav_close();
|
||||
}
|
||||
|
||||
bool GHOST_NDOFManagerX11::available()
|
||||
{
|
||||
return m_available;
|
||||
}
|
||||
|
||||
//bool GHOST_NDOFManagerX11::identifyDevice()
|
||||
// {
|
||||
//
|
||||
// }
|
||||
|
||||
bool GHOST_NDOFManagerX11::processEvents()
|
||||
{
|
||||
GHOST_TUns64 now = m_system.getMilliSeconds();
|
||||
|
||||
bool anyProcessed = false;
|
||||
spnav_event e;
|
||||
while (spnav_poll_event(&e))
|
||||
{
|
||||
switch (e.type)
|
||||
{
|
||||
case SPNAV_EVENT_MOTION:
|
||||
{
|
||||
// convert to blender view coords
|
||||
short t[3] = {e.motion.x, e.motion.y, -e.motion.z};
|
||||
short r[3] = {-e.motion.rx, -e.motion.ry, e.motion.rz};
|
||||
|
||||
updateTranslation(t, now);
|
||||
updateRotation(r, now);
|
||||
break;
|
||||
}
|
||||
case SPNAV_EVENT_BUTTON:
|
||||
updateButton(e.button.bnum, e.button.press, now);
|
||||
break;
|
||||
}
|
||||
anyProcessed = true;
|
||||
}
|
||||
return anyProcessed;
|
||||
}
|
47
intern/ghost/intern/GHOST_NDOFManagerX11.h
Normal file
47
intern/ghost/intern/GHOST_NDOFManagerX11.h
Normal file
@ -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_NDOFMANAGERX11_H_
|
||||
#define _GHOST_NDOFMANAGERX11_H_
|
||||
|
||||
#include "GHOST_NDOFManager.h"
|
||||
|
||||
// Event capture is handled within the NDOF manager on Linux,
|
||||
// so there's no need for SystemX11 to look for them.
|
||||
|
||||
class GHOST_NDOFManagerX11 : public GHOST_NDOFManager
|
||||
{
|
||||
public:
|
||||
GHOST_NDOFManagerX11(GHOST_System&);
|
||||
~GHOST_NDOFManagerX11();
|
||||
bool available();
|
||||
bool processEvents();
|
||||
|
||||
private:
|
||||
// bool identifyDevice();
|
||||
|
||||
bool m_available;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -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) {
|
||||
|
@ -190,25 +190,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
|
||||
***************************************************************************************/
|
||||
|
@ -220,6 +220,11 @@ public:
|
||||
*/
|
||||
GHOST_TSuccess handleApplicationBecomeActiveEvent();
|
||||
|
||||
/**
|
||||
* External objects should call this when they send an event outside processEvents.
|
||||
*/
|
||||
void notifyExternalEventProcessed();
|
||||
|
||||
/**
|
||||
* @see GHOST_ISystem
|
||||
*/
|
||||
@ -267,7 +272,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 */
|
||||
|
@ -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
|
||||
@ -1007,6 +1010,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)
|
||||
{
|
||||
|
@ -32,12 +32,9 @@
|
||||
|
||||
#include "GHOST_SystemPathsWin32.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#ifdef _WIN32_IE
|
||||
#undef _WIN32_IE
|
||||
#endif
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0501
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <shlobj.h>
|
||||
|
||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||
|
@ -38,6 +38,8 @@
|
||||
#error WIN32 only!
|
||||
#endif // WIN32
|
||||
|
||||
#define _WIN32_WINNT 0x501 // require Windows XP or newer
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include "GHOST_SystemPaths.h"
|
||||
|
@ -39,21 +39,18 @@
|
||||
* @date May 7, 2001
|
||||
*/
|
||||
|
||||
#ifdef BF_GHOST_DEBUG
|
||||
#include <iostream>
|
||||
|
||||
#ifdef FREE_WINDOWS
|
||||
# define WINVER 0x0501 /* GetConsoleWindow() for MinGW */
|
||||
#endif
|
||||
|
||||
#include <stdio.h> // [mce] temporary debug, remove soon!
|
||||
|
||||
#include "GHOST_SystemWin32.h"
|
||||
#include "GHOST_EventDragnDrop.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#ifdef _WIN32_IE
|
||||
#undef _WIN32_IE
|
||||
#ifndef _WIN32_IE
|
||||
#define _WIN32_IE 0x0501 /* shipped before XP, so doesn't impose additional requirements */
|
||||
#endif
|
||||
#define _WIN32_IE 0x0501
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
@ -65,48 +62,17 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* According to the docs the mouse wheel message is supported from windows 98
|
||||
* upwards. Leaving WINVER at default value, the WM_MOUSEWHEEL message and the
|
||||
* wheel detent value are undefined.
|
||||
*/
|
||||
#ifndef WM_MOUSEWHEEL
|
||||
#define WM_MOUSEWHEEL 0x020A
|
||||
#endif // WM_MOUSEWHEEL
|
||||
#ifndef WHEEL_DELTA
|
||||
#define WHEEL_DELTA 120 /* Value for rolling one detent, (old convention! MS changed it) */
|
||||
#endif // WHEEL_DELTA
|
||||
|
||||
/*
|
||||
* Defines for mouse buttons 4 and 5 aka xbutton1 and xbutton2.
|
||||
* MSDN: Declared in Winuser.h, include Windows.h
|
||||
* This does not seem to work with MinGW so we define our own here.
|
||||
*/
|
||||
#ifndef XBUTTON1
|
||||
#define XBUTTON1 0x0001
|
||||
#endif // XBUTTON1
|
||||
#ifndef XBUTTON2
|
||||
#define XBUTTON2 0x0002
|
||||
#endif // XBUTTON2
|
||||
#ifndef WM_XBUTTONUP
|
||||
#define WM_XBUTTONUP 524
|
||||
#endif // WM_XBUTTONUP
|
||||
#ifndef WM_XBUTTONDOWN
|
||||
#define WM_XBUTTONDOWN 523
|
||||
#endif // WM_XBUTTONDOWN
|
||||
|
||||
#include "GHOST_Debug.h"
|
||||
#include "GHOST_DisplayManagerWin32.h"
|
||||
#include "GHOST_EventButton.h"
|
||||
#include "GHOST_EventCursor.h"
|
||||
#include "GHOST_EventKey.h"
|
||||
#include "GHOST_EventWheel.h"
|
||||
#include "GHOST_EventNDOF.h"
|
||||
#include "GHOST_TimerTask.h"
|
||||
#include "GHOST_TimerManager.h"
|
||||
#include "GHOST_WindowManager.h"
|
||||
#include "GHOST_WindowWin32.h"
|
||||
#include "GHOST_NDOFManager.h"
|
||||
#include "GHOST_NDOFManagerWin32.h"
|
||||
|
||||
// Key code values not found in winuser.h
|
||||
#ifndef VK_MINUS
|
||||
@ -159,18 +125,25 @@
|
||||
#define VK_MEDIA_PLAY_PAUSE 0xB3
|
||||
#endif // VK_MEDIA_PLAY_PAUSE
|
||||
|
||||
/*
|
||||
Initiates WM_INPUT messages from keyboard
|
||||
That way GHOST can retrieve true keys
|
||||
*/
|
||||
GHOST_TInt32 GHOST_SystemWin32::initKeyboardRawInput(void)
|
||||
static void initRawInput()
|
||||
{
|
||||
RAWINPUTDEVICE device = {0};
|
||||
device.usUsagePage = 0x01; /* usUsagePage & usUsage for keyboard*/
|
||||
device.usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
|
||||
RAWINPUTDEVICE devices[2];
|
||||
memset(devices, 0, 2 * sizeof(RAWINPUTDEVICE));
|
||||
|
||||
return RegisterRawInputDevices(&device, 1, sizeof(device));
|
||||
};
|
||||
// multi-axis mouse (SpaceNavigator, etc.)
|
||||
devices[0].usUsagePage = 0x01;
|
||||
devices[0].usUsage = 0x08;
|
||||
|
||||
// Initiates WM_INPUT messages from keyboard
|
||||
// That way GHOST can retrieve true keys
|
||||
devices[1].usUsagePage = 0x01;
|
||||
devices[1].usUsage = 0x06; /* http://msdn.microsoft.com/en-us/windows/hardware/gg487473.aspx */
|
||||
|
||||
if (RegisterRawInputDevices(devices, 2, sizeof(RAWINPUTDEVICE)))
|
||||
puts("registered for RawInput (spacenav & keyboard)");
|
||||
else
|
||||
printf("could not register for RawInput: %d\n", (int)GetLastError());
|
||||
}
|
||||
|
||||
GHOST_SystemWin32::GHOST_SystemWin32()
|
||||
: m_hasPerformanceCounter(false), m_freq(0), m_start(0)
|
||||
@ -187,6 +160,8 @@ GHOST_SystemWin32::GHOST_SystemWin32()
|
||||
this->handleKeyboardChange();
|
||||
// Require COM for GHOST_DropTargetWin32 created in GHOST_WindowWin32.
|
||||
OleInitialize(0);
|
||||
|
||||
m_ndofManager = new GHOST_NDOFManagerWin32(*this);
|
||||
}
|
||||
|
||||
GHOST_SystemWin32::~GHOST_SystemWin32()
|
||||
@ -245,6 +220,7 @@ GHOST_IWindow* GHOST_SystemWin32::createWindow(
|
||||
// Store the pointer to the window
|
||||
// if (state != GHOST_kWindowStateFullScreen) {
|
||||
m_windowManager->addWindow(window);
|
||||
m_windowManager->setActiveWindow(window);
|
||||
// }
|
||||
}
|
||||
else {
|
||||
@ -385,22 +361,15 @@ GHOST_TSuccess GHOST_SystemWin32::init()
|
||||
GHOST_TSuccess success = GHOST_System::init();
|
||||
|
||||
/* Disable scaling on high DPI displays on Vista */
|
||||
HMODULE
|
||||
user32 = ::LoadLibraryA("user32.dll");
|
||||
typedef BOOL (WINAPI * LPFNSETPROCESSDPIAWARE)();
|
||||
LPFNSETPROCESSDPIAWARE SetProcessDPIAware =
|
||||
(LPFNSETPROCESSDPIAWARE)GetProcAddress(user32, "SetProcessDPIAware");
|
||||
if (SetProcessDPIAware)
|
||||
SetProcessDPIAware();
|
||||
#ifdef NEED_RAW_PROC
|
||||
pRegisterRawInputDevices = (LPFNDLLRRID)GetProcAddress(user32, "RegisterRawInputDevices");
|
||||
pGetRawInputData = (LPFNDLLGRID)GetProcAddress(user32, "GetRawInputData");
|
||||
#else
|
||||
FreeLibrary(user32);
|
||||
#endif
|
||||
|
||||
/* Initiates WM_INPUT messages from keyboard */
|
||||
initKeyboardRawInput();
|
||||
|
||||
initRawInput();
|
||||
|
||||
// Determine whether this system has a high frequency performance counter. */
|
||||
m_hasPerformanceCounter = ::QueryPerformanceFrequency((LARGE_INTEGER*)&m_freq) == TRUE;
|
||||
@ -441,41 +410,25 @@ GHOST_TSuccess GHOST_SystemWin32::init()
|
||||
|
||||
GHOST_TSuccess GHOST_SystemWin32::exit()
|
||||
{
|
||||
#ifdef NEED_RAW_PROC
|
||||
FreeLibrary(user32);
|
||||
#endif
|
||||
|
||||
return GHOST_System::exit();
|
||||
}
|
||||
|
||||
GHOST_TKey GHOST_SystemWin32::hardKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam, int * keyDown, char * vk)
|
||||
GHOST_TKey GHOST_SystemWin32::hardKey(GHOST_IWindow *window, RAWINPUT const& raw, int * keyDown, char * vk)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
char * data;
|
||||
GHOST_TKey key = GHOST_kKeyUnknown;
|
||||
|
||||
|
||||
if(!keyDown)
|
||||
return GHOST_kKeyUnknown;
|
||||
|
||||
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, 0, &size, sizeof(RAWINPUTHEADER));
|
||||
|
||||
|
||||
if((data = (char*)malloc(size)) &&
|
||||
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER)))
|
||||
{
|
||||
RAWINPUT ri;
|
||||
memcpy(&ri,data,(size < sizeof(ri)) ? size : sizeof(ri));
|
||||
|
||||
if (ri.header.dwType == RIM_TYPEKEYBOARD)
|
||||
{
|
||||
GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem();
|
||||
|
||||
GHOST_ModifierKeys modifiers;
|
||||
system->retrieveModifierKeys(modifiers);
|
||||
|
||||
*keyDown = !(ri.data.keyboard.Flags & RI_KEY_BREAK);
|
||||
key = this->convertKey(window, ri.data.keyboard.VKey, ri.data.keyboard.MakeCode, (ri.data.keyboard.Flags&(RI_KEY_E1|RI_KEY_E0)));
|
||||
*keyDown = !(raw.data.keyboard.Flags & RI_KEY_BREAK);
|
||||
key = this->convertKey(window, raw.data.keyboard.VKey, raw.data.keyboard.MakeCode, (raw.data.keyboard.Flags&(RI_KEY_E1|RI_KEY_E0)));
|
||||
|
||||
// extra handling of modifier keys: don't send repeats out from GHOST
|
||||
if(key >= GHOST_kKeyLeftShift && key <= GHOST_kKeyRightAlt)
|
||||
@ -534,11 +487,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(GHOST_IWindow *window, WPARAM wParam, LPAR
|
||||
}
|
||||
|
||||
|
||||
if(vk) *vk = ri.data.keyboard.VKey;
|
||||
};
|
||||
|
||||
};
|
||||
free(data);
|
||||
if(vk) *vk = raw.data.keyboard.VKey;
|
||||
|
||||
return key;
|
||||
}
|
||||
@ -742,12 +691,12 @@ GHOST_EventWheel* GHOST_SystemWin32::processWheelEvent(GHOST_IWindow *window, WP
|
||||
}
|
||||
|
||||
|
||||
GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam)
|
||||
GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, RAWINPUT const& raw)
|
||||
{
|
||||
int keyDown=0;
|
||||
char vk;
|
||||
GHOST_SystemWin32 * system = (GHOST_SystemWin32 *)getSystem();
|
||||
GHOST_TKey key = system->hardKey(window, wParam, lParam, &keyDown, &vk);
|
||||
GHOST_TKey key = system->hardKey(window, raw, &keyDown, &vk);
|
||||
GHOST_EventKey* event;
|
||||
if (key != GHOST_kKeyUnknown) {
|
||||
char ascii = '\0';
|
||||
@ -777,7 +726,15 @@ GHOST_EventKey* GHOST_SystemWin32::processKeyEvent(GHOST_IWindow *window, WPARAM
|
||||
|
||||
GHOST_Event* GHOST_SystemWin32::processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window)
|
||||
{
|
||||
return new GHOST_Event(getSystem()->getMilliSeconds(), type, window);
|
||||
GHOST_System* system = (GHOST_System*)getSystem();
|
||||
|
||||
if (type == GHOST_kEventWindowActivate)
|
||||
{
|
||||
puts("activating window");
|
||||
system->getWindowManager()->setActiveWindow(window);
|
||||
}
|
||||
|
||||
return new GHOST_Event(system->getMilliSeconds(), type, window);
|
||||
}
|
||||
|
||||
GHOST_TSuccess GHOST_SystemWin32::pushDragDropEvent(GHOST_TEventType eventType,
|
||||
@ -800,9 +757,101 @@ void GHOST_SystemWin32::processMinMaxInfo(MINMAXINFO * minmax)
|
||||
minmax->ptMinTrackSize.y=240;
|
||||
}
|
||||
|
||||
bool GHOST_SystemWin32::processNDOF(RAWINPUT const& raw)
|
||||
{
|
||||
bool eventSent = false;
|
||||
GHOST_TUns64 now = getMilliSeconds();
|
||||
|
||||
static bool firstEvent = true;
|
||||
if (firstEvent)
|
||||
{ // determine exactly which device is plugged in
|
||||
RID_DEVICE_INFO info;
|
||||
unsigned infoSize = sizeof(RID_DEVICE_INFO);
|
||||
info.cbSize = infoSize;
|
||||
|
||||
GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, &info, &infoSize);
|
||||
if (info.dwType == RIM_TYPEHID)
|
||||
m_ndofManager->setDevice(info.hid.dwVendorId, info.hid.dwProductId);
|
||||
else
|
||||
puts("<!> not a HID device... mouse/kb perhaps?");
|
||||
|
||||
firstEvent = false;
|
||||
}
|
||||
|
||||
// The NDOF manager sends button changes immediately, and *pretends* to
|
||||
// send motion. Mark as 'sent' so motion will always get dispatched.
|
||||
eventSent = true;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// using Microsoft compiler & header files
|
||||
// they invented the RawInput API, so this version is (probably) correct
|
||||
BYTE const* data = raw.data.hid.bRawData;
|
||||
// struct RAWHID {
|
||||
// DWORD dwSizeHid;
|
||||
// DWORD dwCount;
|
||||
// BYTE bRawData[1];
|
||||
// };
|
||||
#else
|
||||
// MinGW's definition (below) doesn't agree, so we need a slight
|
||||
// workaround until it's fixed
|
||||
BYTE const* data = &raw.data.hid.bRawData;
|
||||
// struct RAWHID {
|
||||
// DWORD dwSizeHid;
|
||||
// DWORD dwCount;
|
||||
// BYTE bRawData; // <== isn't this s'posed to be a BYTE*?
|
||||
// };
|
||||
#endif
|
||||
|
||||
BYTE packetType = data[0];
|
||||
switch (packetType)
|
||||
{
|
||||
case 1: // translation
|
||||
{
|
||||
short* axis = (short*)(data + 1);
|
||||
short t[3] = {axis[0], -axis[2], axis[1]};
|
||||
m_ndofManager->updateTranslation(t, now);
|
||||
|
||||
if (raw.data.hid.dwSizeHid == 13)
|
||||
{ // this report also includes rotation
|
||||
short r[3] = {-axis[3], axis[5], -axis[4]};
|
||||
m_ndofManager->updateRotation(r, now);
|
||||
|
||||
// I've never gotten one of these, has anyone else?
|
||||
puts("ndof: combined T + R");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: // rotation
|
||||
{
|
||||
short* axis = (short*)(data + 1);
|
||||
short r[3] = {-axis[0], axis[2], -axis[1]};
|
||||
m_ndofManager->updateRotation(r, now);
|
||||
break;
|
||||
}
|
||||
case 3: // buttons
|
||||
{
|
||||
#if 0
|
||||
// I'm getting garbage bits -- examine whole report:
|
||||
printf("ndof: HID report for buttons [");
|
||||
for (int i = 0; i < raw.data.hid.dwSizeHid; ++i)
|
||||
printf(" %02X", data[i]);
|
||||
printf(" ]\n");
|
||||
#endif
|
||||
|
||||
int button_bits;
|
||||
memcpy(&button_bits, data + 1, sizeof(button_bits));
|
||||
m_ndofManager->updateButtons(button_bits, now);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return eventSent;
|
||||
}
|
||||
|
||||
LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
GHOST_Event* event = 0;
|
||||
bool eventHandled = false;
|
||||
|
||||
LRESULT lResult = 0;
|
||||
GHOST_SystemWin32* system = ((GHOST_SystemWin32*)getSystem());
|
||||
GHOST_ASSERT(system, "GHOST_SystemWin32::s_wndProc(): system not initialized")
|
||||
@ -819,18 +868,36 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
// Keyboard events, processed
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
case WM_INPUT:
|
||||
{
|
||||
// check WM_INPUT from input sink when ghost window is not in the foreground
|
||||
if (wParam == RIM_INPUTSINK) {
|
||||
if (GetFocus() != hwnd) // WM_INPUT message not for this window
|
||||
return 0;
|
||||
} //else wPAram == RIM_INPUT
|
||||
event = processKeyEvent(window, wParam, lParam);
|
||||
} //else wParam == RIM_INPUT
|
||||
|
||||
RAWINPUT raw;
|
||||
RAWINPUT* raw_ptr = &raw;
|
||||
UINT rawSize = sizeof(RAWINPUT);
|
||||
|
||||
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw_ptr, &rawSize, sizeof(RAWINPUTHEADER));
|
||||
|
||||
switch (raw.header.dwType)
|
||||
{
|
||||
case RIM_TYPEKEYBOARD:
|
||||
event = processKeyEvent(window, raw);
|
||||
if (!event) {
|
||||
GHOST_PRINT("GHOST_SystemWin32::wndProc: key event ")
|
||||
GHOST_PRINT(msg)
|
||||
GHOST_PRINT(" key ignored\n")
|
||||
}
|
||||
break;
|
||||
case RIM_TYPEHID:
|
||||
if (system->processNDOF(raw))
|
||||
eventHandled = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Keyboard events, ignored
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@ -1128,28 +1195,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
* In GHOST, we let DefWindowProc call the timer callback.
|
||||
*/
|
||||
break;
|
||||
case WM_BLND_NDOF_AXIS:
|
||||
{
|
||||
GHOST_TEventNDOFData ndofdata;
|
||||
system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
|
||||
system->m_eventManager->
|
||||
pushEvent(new GHOST_EventNDOF(
|
||||
system->getMilliSeconds(),
|
||||
GHOST_kEventNDOFMotion,
|
||||
window, ndofdata));
|
||||
}
|
||||
break;
|
||||
case WM_BLND_NDOF_BTN:
|
||||
{
|
||||
GHOST_TEventNDOFData ndofdata;
|
||||
system->m_ndofManager->GHOST_NDOFGetDatas(ndofdata);
|
||||
system->m_eventManager->
|
||||
pushEvent(new GHOST_EventNDOF(
|
||||
system->getMilliSeconds(),
|
||||
GHOST_kEventNDOFButton,
|
||||
window, ndofdata));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -1171,10 +1216,12 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
|
||||
if (event) {
|
||||
system->pushEvent(event);
|
||||
eventHandled = true;
|
||||
}
|
||||
else {
|
||||
|
||||
if (!eventHandled)
|
||||
lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
return lResult;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,10 @@
|
||||
#error WIN32 only!
|
||||
#endif // WIN32
|
||||
|
||||
#define _WIN32_WINNT 0x501 // require Windows XP or newer
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <ole2.h> // for drag-n-drop
|
||||
|
||||
#include "GHOST_System.h"
|
||||
|
||||
@ -46,95 +49,6 @@
|
||||
# define __int64 long long
|
||||
#endif
|
||||
|
||||
#ifndef WM_INPUT
|
||||
#define WM_INPUT 0x00FF
|
||||
#endif
|
||||
#ifndef RID_INPUT
|
||||
#define RID_INPUT 0x10000003
|
||||
#endif
|
||||
#ifndef RIM_INPUTSINK
|
||||
#define RIM_INPUTSINK 0x1
|
||||
#endif
|
||||
#ifndef RI_KEY_BREAK
|
||||
#define RI_KEY_BREAK 0x1
|
||||
#endif
|
||||
#ifndef RI_KEY_E0
|
||||
#define RI_KEY_E0 0x2
|
||||
#endif
|
||||
#ifndef RI_KEY_E1
|
||||
#define RI_KEY_E1 0x4
|
||||
#endif
|
||||
#ifndef RIM_TYPEMOUSE
|
||||
#define RIM_TYPEMOUSE 0x0
|
||||
#define RIM_TYPEKEYBOARD 0x1
|
||||
#define RIM_TYPEHID 0x2
|
||||
|
||||
typedef struct tagRAWINPUTDEVICE {
|
||||
USHORT usUsagePage;
|
||||
USHORT usUsage;
|
||||
DWORD dwFlags;
|
||||
HWND hwndTarget;
|
||||
} RAWINPUTDEVICE;
|
||||
|
||||
|
||||
|
||||
typedef struct tagRAWINPUTHEADER {
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
HANDLE hDevice;
|
||||
WPARAM wParam;
|
||||
} RAWINPUTHEADER;
|
||||
|
||||
typedef struct tagRAWMOUSE {
|
||||
USHORT usFlags;
|
||||
union {
|
||||
ULONG ulButtons;
|
||||
struct {
|
||||
USHORT usButtonFlags;
|
||||
USHORT usButtonData;
|
||||
};
|
||||
};
|
||||
ULONG ulRawButtons;
|
||||
LONG lLastX;
|
||||
LONG lLastY;
|
||||
ULONG ulExtraInformation;
|
||||
} RAWMOUSE;
|
||||
|
||||
typedef struct tagRAWKEYBOARD {
|
||||
USHORT MakeCode;
|
||||
USHORT Flags;
|
||||
USHORT Reserved;
|
||||
USHORT VKey;
|
||||
UINT Message;
|
||||
ULONG ExtraInformation;
|
||||
} RAWKEYBOARD;
|
||||
|
||||
typedef struct tagRAWHID {
|
||||
DWORD dwSizeHid;
|
||||
DWORD dwCount;
|
||||
BYTE bRawData[1];
|
||||
} RAWHID;
|
||||
|
||||
typedef struct tagRAWINPUT {
|
||||
RAWINPUTHEADER header;
|
||||
union {
|
||||
RAWMOUSE mouse;
|
||||
RAWKEYBOARD keyboard;
|
||||
RAWHID hid;
|
||||
} data;
|
||||
} RAWINPUT;
|
||||
|
||||
DECLARE_HANDLE(HRAWINPUT);
|
||||
#endif
|
||||
|
||||
#ifdef FREE_WINDOWS
|
||||
#define NEED_RAW_PROC
|
||||
typedef BOOL (WINAPI * LPFNDLLRRID)(RAWINPUTDEVICE*,UINT, UINT);
|
||||
|
||||
typedef UINT (WINAPI * LPFNDLLGRID)(HRAWINPUT, UINT, LPVOID, PUINT, UINT);
|
||||
#define GetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader) ((pGetRawInputData)?pGetRawInputData(hRawInput, uiCommand, pData, pcbSize, cbSizeHeader):(UINT)-1)
|
||||
#endif
|
||||
|
||||
class GHOST_EventButton;
|
||||
class GHOST_EventCursor;
|
||||
class GHOST_EventKey;
|
||||
@ -314,14 +228,13 @@ protected:
|
||||
|
||||
/**
|
||||
* Catches raw WIN32 key codes from WM_INPUT in the wndproc.
|
||||
* @param window-> The window for this handling
|
||||
* @param wParam The wParam from the wndproc
|
||||
* @param lParam The lParam from the wndproc
|
||||
* @param window The window for this handling
|
||||
* @param raw RawInput structure with detailed info about the key event
|
||||
* @param keyDown Pointer flag that specify if a key is down
|
||||
* @param vk Pointer to virtual key
|
||||
* @return The GHOST key (GHOST_kKeyUnknown if no match).
|
||||
*/
|
||||
virtual GHOST_TKey hardKey(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam, int * keyDown, char * vk);
|
||||
virtual GHOST_TKey hardKey(GHOST_IWindow *window, RAWINPUT const& raw, int * keyDown, char * vk);
|
||||
|
||||
/**
|
||||
* Creates modifier key event(s) and updates the key data stored locally (m_modifierKeys).
|
||||
@ -362,10 +275,9 @@ protected:
|
||||
* In most cases this is a straightforward conversion of key codes.
|
||||
* For the modifier keys however, we want to distinguish left and right keys.
|
||||
* @param window The window receiving the event (the active window).
|
||||
* @param wParam The wParam from the wndproc
|
||||
* @param lParam The lParam from the wndproc
|
||||
* @param raw RawInput structure with detailed info about the key event
|
||||
*/
|
||||
static GHOST_EventKey* processKeyEvent(GHOST_IWindow *window, WPARAM wParam, LPARAM lParam);
|
||||
static GHOST_EventKey* processKeyEvent(GHOST_IWindow *window, RAWINPUT const& raw);
|
||||
|
||||
/**
|
||||
* Process special keys (VK_OEM_*), to see if current key layout
|
||||
@ -383,12 +295,22 @@ protected:
|
||||
* @return The event created.
|
||||
*/
|
||||
static GHOST_Event* processWindowEvent(GHOST_TEventType type, GHOST_IWindow* window);
|
||||
|
||||
/**
|
||||
* Handles minimum window size.
|
||||
* @param minmax The MINMAXINFO structure.
|
||||
*/
|
||||
static void processMinMaxInfo(MINMAXINFO * minmax);
|
||||
|
||||
/**
|
||||
* Handles Motion and Button events from a SpaceNavigator or related device.
|
||||
* Instead of returning an event object, this function communicates directly
|
||||
* with the GHOST_NDOFManager.
|
||||
* @param raw RawInput structure with detailed info about the NDOF event
|
||||
* @return Whether an event was generated and sent.
|
||||
*/
|
||||
bool processNDOF(RAWINPUT const& raw);
|
||||
|
||||
/**
|
||||
* Returns the local state of the modifier keys (from the message queue).
|
||||
* @param keys The state of the keys.
|
||||
@ -412,11 +334,6 @@ protected:
|
||||
*/
|
||||
static LRESULT WINAPI s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
/**
|
||||
* Initiates WM_INPUT messages from keyboard
|
||||
*/
|
||||
GHOST_TInt32 initKeyboardRawInput(void);
|
||||
|
||||
/**
|
||||
* Toggles console
|
||||
* @action 0 - Hides
|
||||
@ -445,15 +362,6 @@ protected:
|
||||
|
||||
/** Console status */
|
||||
int m_consoleStatus;
|
||||
|
||||
/** handle for user32.dll*/
|
||||
HMODULE user32;
|
||||
#ifdef NEED_RAW_PROC
|
||||
/* pointer to RegisterRawInputDevices function */
|
||||
LPFNDLLRRID pRegisterRawInputDevices;
|
||||
/* pointer to GetRawInputData function */
|
||||
LPFNDLLGRID pGetRawInputData;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline void GHOST_SystemWin32::retrieveModifierKeys(GHOST_ModifierKeys& keys) const
|
||||
@ -487,4 +395,3 @@ inline void GHOST_SystemWin32::handleKeyboardChange(void)
|
||||
}
|
||||
}
|
||||
#endif // _GHOST_SYSTEM_WIN32_H_
|
||||
|
||||
|
@ -42,8 +42,7 @@
|
||||
#include "GHOST_EventKey.h"
|
||||
#include "GHOST_EventButton.h"
|
||||
#include "GHOST_EventWheel.h"
|
||||
#include "GHOST_EventNDOF.h"
|
||||
#include "GHOST_NDOFManager.h"
|
||||
#include "GHOST_NDOFManagerX11.h"
|
||||
#include "GHOST_DisplayManagerX11.h"
|
||||
|
||||
#include "GHOST_Debug.h"
|
||||
@ -79,19 +78,6 @@
|
||||
static GHOST_TKey
|
||||
convertXKey(KeySym key);
|
||||
|
||||
typedef struct NDOFPlatformInfo {
|
||||
Display *display;
|
||||
Window window;
|
||||
volatile GHOST_TEventNDOFData *currValues;
|
||||
Atom cmdAtom;
|
||||
Atom motionAtom;
|
||||
Atom btnPressAtom;
|
||||
Atom btnRelAtom;
|
||||
} NDOFPlatformInfo;
|
||||
|
||||
static NDOFPlatformInfo sNdofInfo = {NULL, 0, NULL, 0, 0, 0, 0};
|
||||
|
||||
|
||||
//these are for copy and select copy
|
||||
static char *txt_cut_buffer= NULL;
|
||||
static char *txt_select_buffer= NULL;
|
||||
@ -181,6 +167,7 @@ init(
|
||||
GHOST_TSuccess success = GHOST_System::init();
|
||||
|
||||
if (success) {
|
||||
m_ndofManager = new GHOST_NDOFManagerX11(*this);
|
||||
m_displayManager = new GHOST_DisplayManagerX11(this);
|
||||
|
||||
if (m_displayManager) {
|
||||
@ -275,7 +262,7 @@ createWindow(
|
||||
if (window->getValid()) {
|
||||
// Store the pointer to the window
|
||||
m_windowManager->addWindow(window);
|
||||
|
||||
m_windowManager->setActiveWindow(window);
|
||||
pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window) );
|
||||
}
|
||||
else {
|
||||
@ -386,8 +373,6 @@ lastEventTime(Time default_time) {
|
||||
return data.timestamp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
GHOST_SystemX11::
|
||||
processEvents(
|
||||
@ -428,6 +413,11 @@ processEvents(
|
||||
if (generateWindowExposeEvents()) {
|
||||
anyProcessed = true;
|
||||
}
|
||||
|
||||
if (dynamic_cast<GHOST_NDOFManagerX11*>(m_ndofManager)->processEvents()) {
|
||||
anyProcessed = true;
|
||||
}
|
||||
|
||||
} while (waitForEvent && !anyProcessed);
|
||||
|
||||
return anyProcessed;
|
||||
@ -612,6 +602,9 @@ GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
{
|
||||
XFocusChangeEvent &xfe = xe->xfocus;
|
||||
|
||||
// TODO: make sure this is the correct place for activate/deactivate
|
||||
// printf("X: focus %s for window %d\n", xfe.type == FocusIn ? "in" : "out", (int) xfe.window);
|
||||
|
||||
// May have to look at the type of event and filter some
|
||||
// out.
|
||||
|
||||
@ -641,32 +634,8 @@ GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
);
|
||||
} else
|
||||
#endif
|
||||
if (sNdofInfo.currValues) {
|
||||
static GHOST_TEventNDOFData data = {0,0,0,0,0,0,0,0,0,0,0};
|
||||
if (xcme.message_type == sNdofInfo.motionAtom)
|
||||
{
|
||||
data.changed = 1;
|
||||
data.delta = xcme.data.s[8] - data.time;
|
||||
data.time = xcme.data.s[8];
|
||||
data.tx = xcme.data.s[2] >> 2;
|
||||
data.ty = xcme.data.s[3] >> 2;
|
||||
data.tz = xcme.data.s[4] >> 2;
|
||||
data.rx = xcme.data.s[5];
|
||||
data.ry = xcme.data.s[6];
|
||||
data.rz =-xcme.data.s[7];
|
||||
g_event = new GHOST_EventNDOF(getMilliSeconds(),
|
||||
GHOST_kEventNDOFMotion,
|
||||
window, data);
|
||||
} else if (xcme.message_type == sNdofInfo.btnPressAtom) {
|
||||
data.changed = 2;
|
||||
data.delta = xcme.data.s[8] - data.time;
|
||||
data.time = xcme.data.s[8];
|
||||
data.buttons = xcme.data.s[2];
|
||||
g_event = new GHOST_EventNDOF(getMilliSeconds(),
|
||||
GHOST_kEventNDOFButton,
|
||||
window, data);
|
||||
}
|
||||
} else if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
|
||||
|
||||
if (((Atom)xcme.data.l[0]) == m_wm_take_focus) {
|
||||
XWindowAttributes attr;
|
||||
Window fwin;
|
||||
int revert_to;
|
||||
@ -723,6 +692,14 @@ GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
xce.y_root
|
||||
);
|
||||
}
|
||||
|
||||
// printf("X: %s window %d\n", xce.type == EnterNotify ? "entering" : "leaving", (int) xce.window);
|
||||
|
||||
if (xce.type == EnterNotify)
|
||||
m_windowManager->setActiveWindow(window);
|
||||
else
|
||||
m_windowManager->setWindowInactive(window);
|
||||
|
||||
break;
|
||||
}
|
||||
case MapNotify:
|
||||
@ -834,6 +811,8 @@ GHOST_SystemX11::processEvent(XEvent *xe)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // obsolete SpaceNav code
|
||||
|
||||
void *
|
||||
GHOST_SystemX11::
|
||||
prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
|
||||
@ -846,6 +825,8 @@ prepareNdofInfo(volatile GHOST_TEventNDOFData *currentNdofValues)
|
||||
return (void*)&sNdofInfo;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
GHOST_TSuccess
|
||||
GHOST_SystemX11::
|
||||
getModifierKeys(
|
||||
|
@ -203,11 +203,6 @@ public:
|
||||
return m_display;
|
||||
}
|
||||
|
||||
void *
|
||||
prepareNdofInfo(
|
||||
volatile GHOST_TEventNDOFData *current_values
|
||||
);
|
||||
|
||||
/* Helped function for get data from the clipboard. */
|
||||
void getClipboard_xcout(XEvent evt, Atom sel, Atom target,
|
||||
unsigned char **txt, unsigned long *len,
|
||||
|
@ -3,20 +3,16 @@
|
||||
*/
|
||||
#ifndef GHOST_TASKBARWIN32_H_
|
||||
#define GHOST_TASKBARWIN32_H_
|
||||
|
||||
#ifndef WIN32
|
||||
#error WIN32 only!
|
||||
#endif // WIN32
|
||||
|
||||
#define _WIN32_WINNT 0x501 // require Windows XP or newer
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
/* MinGW needs it */
|
||||
#ifdef FREE_WINDOWS
|
||||
#ifdef WINVER
|
||||
#undef WINVER
|
||||
#endif
|
||||
#define WINVER 0x0501
|
||||
#endif /* FREE_WINDOWS */
|
||||
|
||||
// ITaskbarList, ITaskbarList2 and ITaskbarList3 might be missing, present here in that case.
|
||||
// Note, ITaskbarList3 is supported only since Windows 7, though. Check for that is done in
|
||||
|
@ -39,20 +39,12 @@
|
||||
#endif // WIN32
|
||||
|
||||
#include "GHOST_Window.h"
|
||||
|
||||
/* MinGW needs it */
|
||||
#ifdef FREE_WINDOWS
|
||||
#ifdef WINVER
|
||||
#undef WINVER
|
||||
#endif
|
||||
#define WINVER 0x0501
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
#include "GHOST_TaskbarWin32.h"
|
||||
|
||||
#define _WIN32_WINNT 0x501 // require Windows XP or newer
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
#include <wintab.h>
|
||||
#define PACKETDATA (PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR)
|
||||
|
@ -817,12 +817,9 @@ class USERPREF_PT_input(bpy.types.Panel, InputKeyMapPanel):
|
||||
#sub.prop(view, "wheel_scroll_lines", text="Scroll Lines")
|
||||
|
||||
col.separator()
|
||||
''' not implemented yet
|
||||
sub = col.column()
|
||||
sub.label(text="NDOF Device:")
|
||||
sub.prop(inputs, "ndof_pan_speed", text="Pan Speed")
|
||||
sub.prop(inputs, "ndof_rotate_speed", text="Orbit Speed")
|
||||
'''
|
||||
sub.prop(inputs, "ndof_sensitivity", text="NDOF Sensitivity")
|
||||
|
||||
row.separator()
|
||||
|
||||
|
@ -271,6 +271,8 @@ class InputKeyMapPanel:
|
||||
row.prop(kmi, "type", text="", full_event=True)
|
||||
elif map_type == 'MOUSE':
|
||||
row.prop(kmi, "type", text="", full_event=True)
|
||||
if map_type == 'NDOF':
|
||||
row.prop(kmi, "type", text="", full_event=True)
|
||||
elif map_type == 'TWEAK':
|
||||
subrow = row.row()
|
||||
subrow.prop(kmi, "type", text="")
|
||||
@ -306,7 +308,7 @@ class InputKeyMapPanel:
|
||||
sub = split.column()
|
||||
subrow = sub.row(align=True)
|
||||
|
||||
if map_type == 'KEYBOARD':
|
||||
if map_type in ('KEYBOARD', 'NDOF'):
|
||||
subrow.prop(kmi, "type", text="", event=True)
|
||||
subrow.prop(kmi, "value", text="")
|
||||
elif map_type == 'MOUSE':
|
||||
|
@ -349,6 +349,30 @@ class VIEW3D_MT_view_navigation(bpy.types.Menu):
|
||||
layout.operator("view3d.fly")
|
||||
|
||||
|
||||
class VIEW3D_MT_ndof_settings(bpy.types.Menu):
|
||||
bl_label = "3D Mouse Settings"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
input_prefs = context.user_preferences.inputs
|
||||
|
||||
layout.separator()
|
||||
layout.prop(input_prefs, "ndof_sensitivity")
|
||||
|
||||
if context.space_data.type == 'VIEW_3D':
|
||||
layout.separator()
|
||||
layout.prop(input_prefs, "ndof_show_guide")
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="orbit options")
|
||||
layout.prop(input_prefs, "ndof_orbit_invert_axes")
|
||||
|
||||
layout.separator()
|
||||
layout.label(text="fly options")
|
||||
layout.prop(input_prefs, "ndof_fly_helicopter", icon='NDOF_FLY')
|
||||
layout.prop(input_prefs, "ndof_lock_horizon", icon='NDOF_DOM')
|
||||
|
||||
|
||||
class VIEW3D_MT_view_align(bpy.types.Menu):
|
||||
bl_label = "Align View"
|
||||
|
||||
|
@ -92,9 +92,6 @@ typedef struct Global {
|
||||
|
||||
/* save the allowed windowstate of blender when using -W or -w */
|
||||
int windowstate;
|
||||
|
||||
/* ndof device found ? */
|
||||
int ndofdevice;
|
||||
} Global;
|
||||
|
||||
/* **************** GLOBAL ********************* */
|
||||
@ -174,5 +171,3 @@ extern Global G;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -1617,6 +1617,18 @@ static int gpencil_draw_modal (bContext *C, wmOperator *op, wmEvent *event)
|
||||
tGPsdata *p= op->customdata;
|
||||
int estate = OPERATOR_PASS_THROUGH; /* default exit state - not handled, so let others have a share of the pie */
|
||||
|
||||
// if (event->type == NDOF_MOTION)
|
||||
// return OPERATOR_PASS_THROUGH;
|
||||
// -------------------------------
|
||||
// [mce] Not quite what I was looking
|
||||
// for, but a good start! GP continues to
|
||||
// draw on the screen while the 3D mouse
|
||||
// moves the viewpoint. Problem is that
|
||||
// the stroke is converted to 3D only after
|
||||
// it is finished. This approach should work
|
||||
// better in tools that immediately apply
|
||||
// in 3D space.
|
||||
|
||||
//printf("\tGP - handle modal event...\n");
|
||||
|
||||
/* exit painting mode (and/or end current stroke) */
|
||||
|
@ -1585,6 +1585,12 @@ void init_userdef_do_versions(void)
|
||||
if (U.anisotropic_filter <= 0)
|
||||
U.anisotropic_filter = 1;
|
||||
|
||||
if (U.ndof_sensitivity == 0.0f) {
|
||||
U.ndof_sensitivity = 1.0f;
|
||||
U.ndof_flag = NDOF_SHOW_GUIDE | NDOF_LOCK_HORIZON |
|
||||
NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM | NDOF_SHOULD_ROTATE;
|
||||
}
|
||||
|
||||
/* funny name, but it is GE stuff, moves userdef stuff to engine */
|
||||
// XXX space_set_commmandline_options();
|
||||
/* this timer uses U */
|
||||
|
@ -832,6 +832,13 @@ int paint_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
|
||||
float mouse[2];
|
||||
int first= 0;
|
||||
|
||||
// let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
|
||||
// this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
|
||||
// since the 2D deltas are zero -- code in this file needs to be updated to use the
|
||||
// post-NDOF_MOTION MOUSEMOVE
|
||||
if (event->type == NDOF_MOTION)
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
|
||||
if(!stroke->stroke_started) {
|
||||
stroke->last_mouse_position[0] = event->x;
|
||||
stroke->last_mouse_position[1] = event->y;
|
||||
|
@ -73,6 +73,7 @@ void IMAGE_OT_view_zoom(struct wmOperatorType *ot);
|
||||
void IMAGE_OT_view_zoom_in(struct wmOperatorType *ot);
|
||||
void IMAGE_OT_view_zoom_out(struct wmOperatorType *ot);
|
||||
void IMAGE_OT_view_zoom_ratio(struct wmOperatorType *ot);
|
||||
void IMAGE_OT_view_ndof(struct wmOperatorType *ot);
|
||||
|
||||
void IMAGE_OT_new(struct wmOperatorType *ot);
|
||||
void IMAGE_OT_open(struct wmOperatorType *ot);
|
||||
|
@ -437,6 +437,60 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
|
||||
"Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out.", -FLT_MAX, FLT_MAX);
|
||||
}
|
||||
|
||||
/********************** NDOF operator *********************/
|
||||
|
||||
/* Combined pan/zoom from a 3D mouse device.
|
||||
* Z zooms, XY pans
|
||||
* "view" (not "paper") control -- user moves the viewpoint, not the image being viewed
|
||||
* that explains the negative signs in the code below
|
||||
*/
|
||||
|
||||
static int view_ndof_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
{
|
||||
SpaceImage *sima= CTX_wm_space_image(C);
|
||||
ARegion *ar= CTX_wm_region(C);
|
||||
|
||||
wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
|
||||
|
||||
float dt = ndof->dt > 0.25f ? 0.0125f : ndof->dt;
|
||||
/* 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
|
||||
*/
|
||||
|
||||
/* tune these until it feels right */
|
||||
const float zoom_sensitivity = 0.5f;
|
||||
const float pan_sensitivity = 300.f;
|
||||
|
||||
float pan_x = pan_sensitivity * dt * ndof->tx / sima->zoom;
|
||||
float pan_y = pan_sensitivity * dt * ndof->ty / sima->zoom;
|
||||
|
||||
/* "mouse zoom" factor = 1 + (dx + dy) / 300
|
||||
* what about "ndof zoom" factor? should behave like this:
|
||||
* at rest -> factor = 1
|
||||
* move forward -> factor > 1
|
||||
* move backward -> factor < 1
|
||||
*/
|
||||
float zoom_factor = 1.f + zoom_sensitivity * dt * -ndof->tz;
|
||||
|
||||
sima_zoom_set_factor(sima, ar, zoom_factor);
|
||||
sima->xof += pan_x;
|
||||
sima->yof += pan_y;
|
||||
|
||||
ED_region_tag_redraw(ar);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void IMAGE_OT_view_ndof(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "NDOF Pan/Zoom";
|
||||
ot->idname= "IMAGE_OT_view_ndof";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke= view_ndof_invoke;
|
||||
}
|
||||
|
||||
/********************** view all operator *********************/
|
||||
|
||||
/* Updates the fields of the View2D member of the SpaceImage struct.
|
||||
|
@ -469,6 +469,7 @@ static void image_operatortypes(void)
|
||||
WM_operatortype_append(IMAGE_OT_view_zoom_in);
|
||||
WM_operatortype_append(IMAGE_OT_view_zoom_out);
|
||||
WM_operatortype_append(IMAGE_OT_view_zoom_ratio);
|
||||
WM_operatortype_append(IMAGE_OT_view_ndof);
|
||||
|
||||
WM_operatortype_append(IMAGE_OT_new);
|
||||
WM_operatortype_append(IMAGE_OT_open);
|
||||
@ -518,6 +519,9 @@ static void image_keymap(struct wmKeyConfig *keyconf)
|
||||
WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MIDDLEMOUSE, KM_PRESS, KM_SHIFT, 0);
|
||||
WM_keymap_add_item(keymap, "IMAGE_OT_view_pan", MOUSEPAN, 0, 0, 0);
|
||||
|
||||
WM_keymap_add_item(keymap, "IMAGE_OT_view_all", NDOF_BUTTON_FIT, KM_PRESS, 0, 0); // or view selected?
|
||||
WM_keymap_add_item(keymap, "IMAGE_OT_view_ndof", NDOF_MOTION, 0, 0, 0);
|
||||
|
||||
WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_in", WHEELINMOUSE, KM_PRESS, 0, 0);
|
||||
WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_out", WHEELOUTMOUSE, KM_PRESS, 0, 0);
|
||||
WM_keymap_add_item(keymap, "IMAGE_OT_view_zoom_in", PADPLUSKEY, KM_PRESS, 0, 0);
|
||||
|
@ -675,6 +675,104 @@ static void draw_view_axis(RegionView3D *rv3d)
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
/* draw center and axis of rotation for ongoing 3D mouse navigation */
|
||||
static void draw_rotation_guide(RegionView3D *rv3d)
|
||||
{
|
||||
float o[3]; // center of rotation
|
||||
float end[3]; // endpoints for drawing
|
||||
|
||||
float color[4] = {0.f ,0.4235f, 1.f, 1.f}; // bright blue so it matches device LEDs
|
||||
|
||||
negate_v3_v3(o, rv3d->ofs);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glPointSize(5);
|
||||
glEnable(GL_POINT_SMOOTH);
|
||||
glDepthMask(0); // don't overwrite zbuf
|
||||
|
||||
if (rv3d->rot_angle != 0.f) {
|
||||
// -- draw rotation axis --
|
||||
float scaled_axis[3];
|
||||
const float scale = rv3d->dist;
|
||||
mul_v3_v3fl(scaled_axis, rv3d->rot_axis, scale);
|
||||
|
||||
glBegin(GL_LINE_STRIP);
|
||||
color[3] = 0.f; // more transparent toward the ends
|
||||
glColor4fv(color);
|
||||
add_v3_v3v3(end, o, scaled_axis);
|
||||
glVertex3fv(end);
|
||||
|
||||
// color[3] = 0.2f + fabsf(rv3d->rot_angle); // modulate opacity with angle
|
||||
// ^^ neat idea, but angle is frame-rate dependent, so it's usually close to 0.2
|
||||
|
||||
color[3] = 0.5f; // more opaque toward the center
|
||||
glColor4fv(color);
|
||||
glVertex3fv(o);
|
||||
|
||||
color[3] = 0.f;
|
||||
glColor4fv(color);
|
||||
sub_v3_v3v3(end, o, scaled_axis);
|
||||
glVertex3fv(end);
|
||||
glEnd();
|
||||
|
||||
// -- draw ring around rotation center --
|
||||
{
|
||||
#define ROT_AXIS_DETAIL 13
|
||||
const float s = 0.05f * scale;
|
||||
const float step = 2.f * M_PI / ROT_AXIS_DETAIL;
|
||||
float angle;
|
||||
int i;
|
||||
|
||||
float q[4]; // rotate ring so it's perpendicular to axis
|
||||
const int upright = fabsf(rv3d->rot_axis[2]) >= 0.95f;
|
||||
if (!upright)
|
||||
{
|
||||
const float up[3] = {0.f, 0.f, 1.f};
|
||||
float vis_angle, vis_axis[3];
|
||||
|
||||
cross_v3_v3v3(vis_axis, up, rv3d->rot_axis);
|
||||
vis_angle = acosf(dot_v3v3(up, rv3d->rot_axis));
|
||||
axis_angle_to_quat(q, vis_axis, vis_angle);
|
||||
}
|
||||
|
||||
color[3] = 0.25f; // somewhat faint
|
||||
glColor4fv(color);
|
||||
glBegin(GL_LINE_LOOP);
|
||||
for (i = 0, angle = 0.f; i < ROT_AXIS_DETAIL; ++i, angle += step)
|
||||
{
|
||||
float p[3] = { s * cosf(angle), s * sinf(angle), 0.f };
|
||||
|
||||
if (!upright)
|
||||
mul_qt_v3(q, p);
|
||||
|
||||
add_v3_v3(p, o);
|
||||
glVertex3fv(p);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
color[3] = 1.f; // solid dot
|
||||
}
|
||||
else
|
||||
color[3] = 0.5f; // see-through dot
|
||||
|
||||
// -- draw rotation center --
|
||||
glColor4fv(color);
|
||||
glBegin(GL_POINTS);
|
||||
glVertex3fv(o);
|
||||
glEnd();
|
||||
|
||||
// find screen coordinates for rotation center, then draw pretty icon
|
||||
// mul_m4_v3(rv3d->persinv, rot_center);
|
||||
// UI_icon_draw(rot_center[0], rot_center[1], ICON_NDOF_TURN);
|
||||
// ^^ just playing around, does not work
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_POINT_SMOOTH);
|
||||
glDepthMask(1);
|
||||
}
|
||||
|
||||
static void draw_view_icon(RegionView3D *rv3d)
|
||||
{
|
||||
@ -2618,6 +2716,10 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
|
||||
BDR_drawSketch(C);
|
||||
}
|
||||
|
||||
if ((U.ndof_flag & NDOF_SHOW_GUIDE) && (rv3d->viewlock != RV3D_LOCKED) && (rv3d->persp != RV3D_CAMOB))
|
||||
// TODO: draw something else (but not this) during fly mode
|
||||
draw_rotation_guide(rv3d);
|
||||
|
||||
ED_region_pixelspace(ar);
|
||||
|
||||
// retopo_paint_view_update(v3d);
|
||||
|
@ -928,6 +928,269 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
|
||||
ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void ndof_to_quat(struct wmNDOFMotionData* ndof, float q[4])
|
||||
{
|
||||
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;
|
||||
|
||||
// combined scaling factor -- normalize axis while converting to quaternion
|
||||
float scale = sin(0.5f * angle) / angular_velocity;
|
||||
|
||||
// convert axis-angle to quaternion
|
||||
q[0] = cos(0.5f * angle);
|
||||
q[1] = scale * x;
|
||||
q[2] = scale * y;
|
||||
q[3] = scale * z;
|
||||
}
|
||||
|
||||
static int ndof_orbit_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
// -- "orbit" navigation (trackball/turntable)
|
||||
// -- zooming
|
||||
// -- panning in rotationally-locked views
|
||||
{
|
||||
RegionView3D* rv3d = CTX_wm_region_view3d(C);
|
||||
wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
|
||||
|
||||
rv3d->rot_angle = 0.f; // off by default, until changed later this function
|
||||
|
||||
if (ndof->progress != P_FINISHING) {
|
||||
const float dt = ndof->dt;
|
||||
|
||||
// tune these until everything feels right
|
||||
const float rot_sensitivity = 1.f;
|
||||
const float zoom_sensitivity = 1.f;
|
||||
const float pan_sensitivity = 1.f;
|
||||
|
||||
// rather have bool, but...
|
||||
int has_rotation = rv3d->viewlock != RV3D_LOCKED && (ndof->rx || ndof->ry || ndof->rz);
|
||||
|
||||
float view_inv[4];
|
||||
invert_qt_qt(view_inv, rv3d->viewquat);
|
||||
|
||||
//#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",
|
||||
ndof->tx, ndof->ty, ndof->tz, ndof->rx, ndof->ry, ndof->rz, ndof->dt);
|
||||
#endif
|
||||
|
||||
if (ndof->tz) {
|
||||
// Zoom!
|
||||
// velocity should be proportional to the linear velocity attained by rotational motion of same strength
|
||||
// [got that?]
|
||||
// proportional to arclength = radius * angle
|
||||
|
||||
float zoom_distance = zoom_sensitivity * rv3d->dist * dt * ndof->tz;
|
||||
rv3d->dist += zoom_distance;
|
||||
}
|
||||
|
||||
if (rv3d->viewlock == RV3D_LOCKED) {
|
||||
/* rotation not allowed -- explore panning options instead */
|
||||
float pan_vec[3] = {ndof->tx, ndof->ty, 0};
|
||||
mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt);
|
||||
|
||||
/* transform motion from view to world coordinates */
|
||||
invert_qt_qt(view_inv, rv3d->viewquat);
|
||||
mul_qt_v3(view_inv, pan_vec);
|
||||
|
||||
/* move center of view opposite of hand motion (this is camera mode, not object mode) */
|
||||
sub_v3_v3(rv3d->ofs, pan_vec);
|
||||
}
|
||||
|
||||
if (has_rotation) {
|
||||
|
||||
const int invert = U.ndof_flag & NDOF_ORBIT_INVERT_AXES;
|
||||
|
||||
rv3d->view = RV3D_VIEW_USER;
|
||||
|
||||
if (U.flag & USER_TRACKBALL) {
|
||||
float rot[4];
|
||||
#if 0 // -------------------------- Mike's nifty original version
|
||||
float view_inv_conj[4];
|
||||
|
||||
ndof_to_quat(ndof, rot);
|
||||
// mul_qt_fl(rot, rot_sensitivity);
|
||||
// ^^ no apparent effect
|
||||
|
||||
if (invert)
|
||||
invert_qt(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);
|
||||
#else // ---------------------------------------- Mike's revised version
|
||||
float axis[3];
|
||||
float angle = rot_sensitivity * ndof_to_angle_axis(ndof, axis);
|
||||
|
||||
if (invert)
|
||||
angle = -angle;
|
||||
|
||||
// transform rotation axis from view to world coordinates
|
||||
mul_qt_v3(view_inv, axis);
|
||||
|
||||
// update the onscreen doo-dad
|
||||
rv3d->rot_angle = angle;
|
||||
copy_v3_v3(rv3d->rot_axis, axis);
|
||||
|
||||
axis_angle_to_quat(rot, axis, angle);
|
||||
#endif // --------------------------------------------
|
||||
// apply rotation
|
||||
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
|
||||
} else {
|
||||
/* turntable view code by John Aughey, adapted for 3D mouse by [mce] */
|
||||
float angle, rot[4];
|
||||
float xvec[3] = {1,0,0};
|
||||
|
||||
/* Determine the direction of the x vector (for rotating up and down) */
|
||||
mul_qt_v3(view_inv, xvec);
|
||||
|
||||
/* Perform the up/down rotation */
|
||||
angle = rot_sensitivity * dt * ndof->rx;
|
||||
if (invert)
|
||||
angle = -angle;
|
||||
rot[0] = cos(angle);
|
||||
mul_v3_v3fl(rot+1, xvec, sin(angle));
|
||||
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
|
||||
|
||||
/* Perform the orbital rotation */
|
||||
angle = rot_sensitivity * dt * ndof->ry;
|
||||
if (invert)
|
||||
angle = -angle;
|
||||
|
||||
// update the onscreen doo-dad
|
||||
rv3d->rot_angle = angle;
|
||||
rv3d->rot_axis[0] = 0;
|
||||
rv3d->rot_axis[1] = 0;
|
||||
rv3d->rot_axis[2] = 1;
|
||||
|
||||
rot[0] = cos(angle);
|
||||
rot[1] = rot[2] = 0.0;
|
||||
rot[3] = sin(angle);
|
||||
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void VIEW3D_OT_ndof_orbit(struct wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "NDOF Orbit View";
|
||||
ot->description = "Explore every angle of an object using the 3D mouse.";
|
||||
ot->idname = "VIEW3D_OT_ndof_orbit";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = ndof_orbit_invoke;
|
||||
ot->poll = ED_operator_view3d_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
}
|
||||
|
||||
static int ndof_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
// -- "pan" navigation
|
||||
// -- zoom or dolly?
|
||||
{
|
||||
RegionView3D* rv3d = CTX_wm_region_view3d(C);
|
||||
wmNDOFMotionData* ndof = (wmNDOFMotionData*) event->customdata;
|
||||
|
||||
rv3d->rot_angle = 0.f; // we're panning here! so erase any leftover rotation from other operators
|
||||
|
||||
if (ndof->progress != P_FINISHING) {
|
||||
const float dt = ndof->dt;
|
||||
float view_inv[4];
|
||||
#if 0 // ------------------------------------------- zoom with Z
|
||||
// tune these until everything feels right
|
||||
const float zoom_sensitivity = 1.f;
|
||||
const float pan_sensitivity = 1.f;
|
||||
|
||||
float pan_vec[3] = {
|
||||
ndof->tx, ndof->ty, 0
|
||||
};
|
||||
|
||||
// "zoom in" or "translate"? depends on zoom mode in user settings?
|
||||
if (ndof->tz) {
|
||||
float zoom_distance = zoom_sensitivity * rv3d->dist * dt * ndof->tz;
|
||||
rv3d->dist += zoom_distance;
|
||||
}
|
||||
|
||||
mul_v3_fl(pan_vec, pan_sensitivity * rv3d->dist * dt);
|
||||
#else // ------------------------------------------------------- dolly with Z
|
||||
float speed = 10.f; // blender units per second
|
||||
// ^^ this is ok for default cube scene, but should scale with.. something
|
||||
|
||||
// tune these until everything feels right
|
||||
const float forward_sensitivity = 1.f;
|
||||
const float vertical_sensitivity = 0.4f;
|
||||
const float lateral_sensitivity = 0.6f;
|
||||
|
||||
float pan_vec[3] = {
|
||||
lateral_sensitivity * ndof->tx,
|
||||
vertical_sensitivity * ndof->ty,
|
||||
forward_sensitivity * ndof->tz
|
||||
};
|
||||
|
||||
mul_v3_fl(pan_vec, speed * dt);
|
||||
#endif
|
||||
/* transform motion from view to world coordinates */
|
||||
invert_qt_qt(view_inv, rv3d->viewquat);
|
||||
mul_qt_v3(view_inv, pan_vec);
|
||||
|
||||
/* move center of view opposite of hand motion (this is camera mode, not object mode) */
|
||||
sub_v3_v3(rv3d->ofs, pan_vec);
|
||||
}
|
||||
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void VIEW3D_OT_ndof_pan(struct wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "NDOF Pan View";
|
||||
ot->description = "Position your viewpoint with the 3D mouse.";
|
||||
ot->idname = "VIEW3D_OT_ndof_pan";
|
||||
|
||||
/* api callbacks */
|
||||
ot->invoke = ndof_pan_invoke;
|
||||
ot->poll = ED_operator_view3d_active;
|
||||
|
||||
/* flags */
|
||||
ot->flag = 0;
|
||||
}
|
||||
|
||||
/* ************************ viewmove ******************************** */
|
||||
|
||||
|
||||
@ -3195,398 +3458,6 @@ int ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], cons
|
||||
return (*depth==FLT_MAX) ? 0:1;
|
||||
}
|
||||
|
||||
/* ********************* NDOF ************************ */
|
||||
/* note: this code is confusing and unclear... (ton) */
|
||||
/* **************************************************** */
|
||||
|
||||
// ndof scaling will be moved to user setting.
|
||||
// In the mean time this is just a place holder.
|
||||
|
||||
// Note: scaling in the plugin and ghostwinlay.c
|
||||
// should be removed. With driver default setting,
|
||||
// each axis returns approx. +-200 max deflection.
|
||||
|
||||
// The values I selected are based on the older
|
||||
// polling i/f. With event i/f, the sensistivity
|
||||
// can be increased for improved response from
|
||||
// small deflections of the device input.
|
||||
|
||||
|
||||
// lukep notes : i disagree on the range.
|
||||
// the normal 3Dconnection driver give +/-400
|
||||
// on defaut range in other applications
|
||||
// and up to +/- 1000 if set to maximum
|
||||
// because i remove the scaling by delta,
|
||||
// which was a bad idea as it depend of the system
|
||||
// speed and os, i changed the scaling values, but
|
||||
// those are still not ok
|
||||
|
||||
#if 0
|
||||
static float ndof_axis_scale[6] = {
|
||||
+0.01, // Tx
|
||||
+0.01, // Tz
|
||||
+0.01, // Ty
|
||||
+0.0015, // Rx
|
||||
+0.0015, // Rz
|
||||
+0.0015 // Ry
|
||||
};
|
||||
|
||||
static void filterNDOFvalues(float *sbval)
|
||||
{
|
||||
int i=0;
|
||||
float max = 0.0;
|
||||
|
||||
for (i =0; i<6;i++)
|
||||
if (fabs(sbval[i]) > max)
|
||||
max = fabs(sbval[i]);
|
||||
for (i =0; i<6;i++)
|
||||
if (fabs(sbval[i]) != max )
|
||||
sbval[i]=0.0;
|
||||
}
|
||||
|
||||
// statics for controlling rv3d->dist corrections.
|
||||
// viewmoveNDOF zeros and adjusts rv3d->ofs.
|
||||
// viewmove restores based on dz_flag state.
|
||||
|
||||
int dz_flag = 0;
|
||||
float m_dist;
|
||||
|
||||
void viewmoveNDOFfly(ARegion *ar, View3D *v3d, int UNUSED(mode))
|
||||
{
|
||||
RegionView3D *rv3d= ar->regiondata;
|
||||
int i;
|
||||
float phi;
|
||||
float dval[7];
|
||||
// static fval[6] for low pass filter; device input vector is dval[6]
|
||||
static float fval[6];
|
||||
float tvec[3],rvec[3];
|
||||
float q1[4];
|
||||
float mat[3][3];
|
||||
float upvec[3];
|
||||
|
||||
|
||||
/*----------------------------------------------------
|
||||
* sometimes this routine is called from headerbuttons
|
||||
* viewmove needs to refresh the screen
|
||||
*/
|
||||
// XXX areawinset(ar->win);
|
||||
|
||||
|
||||
// fetch the current state of the ndof device
|
||||
// XXX getndof(dval);
|
||||
|
||||
if (v3d->ndoffilter)
|
||||
filterNDOFvalues(fval);
|
||||
|
||||
// Scale input values
|
||||
|
||||
// if(dval[6] == 0) return; // guard against divide by zero
|
||||
|
||||
for(i=0;i<6;i++) {
|
||||
|
||||
// user scaling
|
||||
dval[i] = dval[i] * ndof_axis_scale[i];
|
||||
}
|
||||
|
||||
|
||||
// low pass filter with zero crossing reset
|
||||
|
||||
for(i=0;i<6;i++) {
|
||||
if((dval[i] * fval[i]) >= 0)
|
||||
dval[i] = (fval[i] * 15 + dval[i]) / 16;
|
||||
else
|
||||
fval[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
// force perspective mode. This is a hack and is
|
||||
// incomplete. It doesn't actually effect the view
|
||||
// until the first draw and doesn't update the menu
|
||||
// to reflect persp mode.
|
||||
|
||||
rv3d->persp = RV3D_PERSP;
|
||||
|
||||
|
||||
// Correct the distance jump if rv3d->dist != 0
|
||||
|
||||
// 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.
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// Apply rotation
|
||||
// Rotations feel relatively faster than translations only in fly mode, so
|
||||
// we have no choice but to fix that here (not in the plugins)
|
||||
rvec[0] = -0.5 * dval[3];
|
||||
rvec[1] = -0.5 * dval[4];
|
||||
rvec[2] = -0.5 * dval[5];
|
||||
|
||||
// rotate device x and y by view z
|
||||
|
||||
copy_m3_m4(mat, rv3d->viewinv);
|
||||
mat[2][2] = 0.0f;
|
||||
mul_m3_v3(mat, rvec);
|
||||
|
||||
// rotate the view
|
||||
|
||||
phi = normalize_v3(rvec);
|
||||
if(phi != 0) {
|
||||
axis_angle_to_quat(q1,rvec,phi);
|
||||
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
|
||||
}
|
||||
|
||||
|
||||
// Apply translation
|
||||
|
||||
tvec[0] = dval[0];
|
||||
tvec[1] = dval[1];
|
||||
tvec[2] = -dval[2];
|
||||
|
||||
// the next three lines rotate the x and y translation coordinates
|
||||
// by the current z axis angle
|
||||
|
||||
copy_m3_m4(mat, rv3d->viewinv);
|
||||
mat[2][2] = 0.0f;
|
||||
mul_m3_v3(mat, tvec);
|
||||
|
||||
// translate the view
|
||||
|
||||
sub_v3_v3(rv3d->ofs, tvec);
|
||||
|
||||
|
||||
/*----------------------------------------------------
|
||||
* refresh the screen XXX
|
||||
*/
|
||||
|
||||
// update render preview window
|
||||
|
||||
// XXX BIF_view3d_previewrender_signal(ar, PR_DBASE|PR_DISPRECT);
|
||||
}
|
||||
|
||||
void viewmoveNDOF(Scene *scene, ARegion *ar, View3D *v3d, int UNUSED(mode))
|
||||
{
|
||||
RegionView3D *rv3d= ar->regiondata;
|
||||
float fval[7];
|
||||
float dvec[3];
|
||||
float sbadjust = 1.0f;
|
||||
float len;
|
||||
short use_sel = 0;
|
||||
Object *ob = OBACT;
|
||||
float m[3][3];
|
||||
float m_inv[3][3];
|
||||
float xvec[3] = {1,0,0};
|
||||
float yvec[3] = {0,-1,0};
|
||||
float zvec[3] = {0,0,1};
|
||||
float phi;
|
||||
float q1[4];
|
||||
float obofs[3];
|
||||
float reverse;
|
||||
//float diff[4];
|
||||
float d, curareaX, curareaY;
|
||||
float mat[3][3];
|
||||
float upvec[3];
|
||||
|
||||
/* Sensitivity will control how fast the view rotates. The value was
|
||||
* obtained experimentally by tweaking until the author didn't get dizzy watching.
|
||||
* Perhaps this should be a configurable user parameter.
|
||||
*/
|
||||
float psens = 0.005f * (float) U.ndof_pan; /* pan sensitivity */
|
||||
float rsens = 0.005f * (float) U.ndof_rotate; /* rotate sensitivity */
|
||||
float zsens = 0.3f; /* zoom sensitivity */
|
||||
|
||||
const float minZoom = -30.0f;
|
||||
const float maxZoom = 300.0f;
|
||||
|
||||
//reset view type
|
||||
rv3d->view = 0;
|
||||
//printf("passing here \n");
|
||||
//
|
||||
if (scene->obedit==NULL && ob && !(ob->mode & OB_MODE_POSE)) {
|
||||
use_sel = 1;
|
||||
}
|
||||
|
||||
if((dz_flag)||rv3d->dist==0) {
|
||||
dz_flag = 0;
|
||||
rv3d->dist = m_dist;
|
||||
upvec[0] = upvec[1] = 0;
|
||||
upvec[2] = rv3d->dist;
|
||||
copy_m3_m4(mat, rv3d->viewinv);
|
||||
mul_m3_v3(mat, upvec);
|
||||
add_v3_v3(rv3d->ofs, upvec);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------
|
||||
* sometimes this routine is called from headerbuttons
|
||||
* viewmove needs to refresh the screen
|
||||
*/
|
||||
// XXX areawinset(curarea->win);
|
||||
|
||||
/*----------------------------------------------------
|
||||
* record how much time has passed. clamp at 10 Hz
|
||||
* pretend the previous frame occurred at the clamped time
|
||||
*/
|
||||
// now = PIL_check_seconds_timer();
|
||||
// frametime = (now - prevTime);
|
||||
// if (frametime > 0.1f){ /* if more than 1/10s */
|
||||
// frametime = 1.0f/60.0; /* clamp at 1/60s so no jumps when starting to move */
|
||||
// }
|
||||
// prevTime = now;
|
||||
// sbadjust *= 60 * frametime; /* normalize ndof device adjustments to 100Hz for framerate independence */
|
||||
|
||||
/* fetch the current state of the ndof device & enforce dominant mode if selected */
|
||||
// XXX getndof(fval);
|
||||
if (v3d->ndoffilter)
|
||||
filterNDOFvalues(fval);
|
||||
|
||||
|
||||
// put scaling back here, was previously in ghostwinlay
|
||||
fval[0] = fval[0] * (1.0f/600.0f);
|
||||
fval[1] = fval[1] * (1.0f/600.0f);
|
||||
fval[2] = fval[2] * (1.0f/1100.0f);
|
||||
fval[3] = fval[3] * 0.00005f;
|
||||
fval[4] =-fval[4] * 0.00005f;
|
||||
fval[5] = fval[5] * 0.00005f;
|
||||
fval[6] = fval[6] / 1000000.0f;
|
||||
|
||||
// scale more if not in perspective mode
|
||||
if (rv3d->persp == RV3D_ORTHO) {
|
||||
fval[0] = fval[0] * 0.05f;
|
||||
fval[1] = fval[1] * 0.05f;
|
||||
fval[2] = fval[2] * 0.05f;
|
||||
fval[3] = fval[3] * 0.9f;
|
||||
fval[4] = fval[4] * 0.9f;
|
||||
fval[5] = fval[5] * 0.9f;
|
||||
zsens *= 8;
|
||||
}
|
||||
|
||||
/* set object offset */
|
||||
if (ob) {
|
||||
obofs[0] = -ob->obmat[3][0];
|
||||
obofs[1] = -ob->obmat[3][1];
|
||||
obofs[2] = -ob->obmat[3][2];
|
||||
}
|
||||
else {
|
||||
copy_v3_v3(obofs, rv3d->ofs);
|
||||
}
|
||||
|
||||
/* calc an adjustment based on distance from camera
|
||||
disabled per patch 14402 */
|
||||
d = 1.0f;
|
||||
|
||||
/* if (ob) {
|
||||
sub_v3_v3v3(diff, obofs, rv3d->ofs);
|
||||
d = len_v3(diff);
|
||||
}
|
||||
*/
|
||||
|
||||
reverse = (rv3d->persmat[2][1] < 0.0f) ? -1.0f : 1.0f;
|
||||
|
||||
/*----------------------------------------------------
|
||||
* ndof device pan
|
||||
*/
|
||||
psens *= 1.0f + d;
|
||||
curareaX = sbadjust * psens * fval[0];
|
||||
curareaY = sbadjust * psens * fval[1];
|
||||
dvec[0] = curareaX * rv3d->persinv[0][0] + curareaY * rv3d->persinv[1][0];
|
||||
dvec[1] = curareaX * rv3d->persinv[0][1] + curareaY * rv3d->persinv[1][1];
|
||||
dvec[2] = curareaX * rv3d->persinv[0][2] + curareaY * rv3d->persinv[1][2];
|
||||
add_v3_v3(rv3d->ofs, dvec);
|
||||
|
||||
/*----------------------------------------------------
|
||||
* ndof device dolly
|
||||
*/
|
||||
len = zsens * sbadjust * fval[2];
|
||||
|
||||
if (rv3d->persp==RV3D_CAMOB) {
|
||||
if(rv3d->persp==RV3D_CAMOB) { /* This is stupid, please fix - TODO */
|
||||
rv3d->camzoom+= 10.0f * -len;
|
||||
}
|
||||
if (rv3d->camzoom < minZoom) rv3d->camzoom = minZoom;
|
||||
else if (rv3d->camzoom > maxZoom) rv3d->camzoom = maxZoom;
|
||||
}
|
||||
else if ((rv3d->dist> 0.001*v3d->grid) && (rv3d->dist<10.0*v3d->far)) {
|
||||
rv3d->dist*=(1.0 + len);
|
||||
}
|
||||
|
||||
|
||||
/*----------------------------------------------------
|
||||
* ndof device turntable
|
||||
* derived from the turntable code in viewmove
|
||||
*/
|
||||
|
||||
/* 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 compuated directly from the quaternion. */
|
||||
mul_m3_v3(m_inv,xvec);
|
||||
mul_m3_v3(m_inv,yvec);
|
||||
mul_m3_v3(m_inv,zvec);
|
||||
|
||||
/* Perform the up/down rotation */
|
||||
phi = sbadjust * rsens * /*0.5f * */ fval[3]; /* spin vertically half as fast as horizontally */
|
||||
q1[0] = cos(phi);
|
||||
mul_v3_v3fl(q1+1, xvec, sin(phi));
|
||||
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
|
||||
|
||||
if (use_sel) {
|
||||
conjugate_qt(q1); /* conj == inv for unit quat */
|
||||
sub_v3_v3(rv3d->ofs, obofs);
|
||||
mul_qt_v3(q1, rv3d->ofs);
|
||||
add_v3_v3(rv3d->ofs, obofs);
|
||||
}
|
||||
|
||||
/* Perform the orbital rotation */
|
||||
/* Perform the orbital rotation
|
||||
If the seen Up axis is parallel to the zoom axis, rotation should be
|
||||
achieved with a pure Roll motion (no Spin) on the device. When you start
|
||||
to tilt, moving from Top to Side view, Spinning will increasingly become
|
||||
more relevant while the Roll component will decrease. When a full
|
||||
Side view is reached, rotations around the world's Up axis are achieved
|
||||
with a pure Spin-only motion. In other words the control of the spinning
|
||||
around the world's Up axis should move from the device's Spin axis to the
|
||||
device's Roll axis depending on the orientation of the world's Up axis
|
||||
relative to the screen. */
|
||||
//phi = sbadjust * rsens * reverse * fval[4]; /* spin the knob, y axis */
|
||||
phi = sbadjust * rsens * (yvec[2] * fval[4] + zvec[2] * fval[5]);
|
||||
q1[0] = cos(phi);
|
||||
q1[1] = q1[2] = 0.0;
|
||||
q1[3] = sin(phi);
|
||||
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, q1);
|
||||
|
||||
if (use_sel) {
|
||||
conjugate_qt(q1);
|
||||
sub_v3_v3(rv3d->ofs, obofs);
|
||||
mul_qt_v3(q1, rv3d->ofs);
|
||||
add_v3_v3(rv3d->ofs, obofs);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------
|
||||
* refresh the screen
|
||||
*/
|
||||
// XXX scrarea_do_windraw(curarea);
|
||||
}
|
||||
#endif // if 0, unused NDof code
|
||||
|
||||
|
||||
/* Gets the view trasnformation from a camera
|
||||
* currently dosnt take camzoom into account
|
||||
*
|
||||
|
@ -29,6 +29,8 @@
|
||||
|
||||
/* defines VIEW3D_OT_fly modal operator */
|
||||
|
||||
//#define NDOF_FLY_DEBUG
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
@ -143,7 +145,6 @@ void fly_modal_keymap(wmKeyConfig *keyconf)
|
||||
|
||||
/* assign map to operators */
|
||||
WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly");
|
||||
|
||||
}
|
||||
|
||||
typedef struct FlyInfo {
|
||||
@ -158,7 +159,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 +260,10 @@ static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *even
|
||||
fly->ar = CTX_wm_region(C);
|
||||
fly->scene= CTX_data_scene(C);
|
||||
|
||||
#ifdef NDOF_FLY_DEBUG
|
||||
puts("\n-- fly begin --");
|
||||
#endif
|
||||
|
||||
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 +289,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 +338,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 +357,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 +373,10 @@ static int flyEnd(bContext *C, FlyInfo *fly)
|
||||
if(fly->state == FLY_RUNNING)
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
|
||||
#ifdef NDOF_FLY_DEBUG
|
||||
puts("\n-- fly end --");
|
||||
#endif
|
||||
|
||||
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 +422,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 +436,54 @@ 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
|
||||
#ifdef NDOF_FLY_DEBUG
|
||||
puts("start keeping track of 3D mouse position");
|
||||
#endif
|
||||
// fall through...
|
||||
case P_IN_PROGRESS:
|
||||
// update 3D mouse position
|
||||
#ifdef NDOF_FLY_DEBUG
|
||||
putchar('.'); fflush(stdout);
|
||||
#endif
|
||||
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
|
||||
#ifdef NDOF_FLY_DEBUG
|
||||
puts("stop keeping track of 3D mouse position");
|
||||
#endif
|
||||
if (fly->ndof)
|
||||
{
|
||||
MEM_freeN(fly->ndof);
|
||||
// free(fly->ndof);
|
||||
fly->ndof = NULL;
|
||||
}
|
||||
/* update the time else the view will jump when 2D mouse/timer resume */
|
||||
fly->time_lastdraw= PIL_check_seconds_timer();
|
||||
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,14 +594,81 @@ static void flyEvent(FlyInfo *fly, wmEvent *event)
|
||||
case FLY_MODAL_PRECISION_DISABLE:
|
||||
fly->use_precision= FALSE;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void move_camera(bContext* C, RegionView3D* rv3d, FlyInfo* fly, int orientationChanged, int positionChanged)
|
||||
{
|
||||
/* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
|
||||
|
||||
View3D* v3d = fly->v3d;
|
||||
Scene *scene= fly->scene;
|
||||
ID *id_key;
|
||||
|
||||
/* transform the parent or the camera? */
|
||||
if(fly->root_parent) {
|
||||
Object *ob_update;
|
||||
|
||||
float view_mat[4][4];
|
||||
float prev_view_mat[4][4];
|
||||
float prev_view_imat[4][4];
|
||||
float diff_mat[4][4];
|
||||
float parent_mat[4][4];
|
||||
|
||||
ED_view3d_to_m4(prev_view_mat, fly->rv3d->ofs, fly->rv3d->viewquat, fly->rv3d->dist);
|
||||
invert_m4_m4(prev_view_imat, prev_view_mat);
|
||||
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
|
||||
mul_m4_m4m4(diff_mat, prev_view_imat, view_mat);
|
||||
mul_m4_m4m4(parent_mat, fly->root_parent->obmat, diff_mat);
|
||||
object_apply_mat4(fly->root_parent, parent_mat, TRUE, FALSE);
|
||||
|
||||
// where_is_object(scene, fly->root_parent);
|
||||
|
||||
ob_update= v3d->camera->parent;
|
||||
while(ob_update) {
|
||||
DAG_id_tag_update(&ob_update->id, OB_RECALC_OB);
|
||||
ob_update= ob_update->parent;
|
||||
}
|
||||
|
||||
id_key= &fly->root_parent->id;
|
||||
}
|
||||
else {
|
||||
float view_mat[4][4];
|
||||
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
|
||||
object_apply_mat4(v3d->camera, view_mat, TRUE, FALSE);
|
||||
id_key= &v3d->camera->id;
|
||||
}
|
||||
|
||||
/* record the motion */
|
||||
if (autokeyframe_cfra_can_key(scene, id_key)) {
|
||||
ListBase dsources = {NULL, NULL};
|
||||
|
||||
/* add datasource override for the camera object */
|
||||
ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
|
||||
|
||||
/* insert keyframes
|
||||
* 1) on the first frame
|
||||
* 2) on each subsequent frame
|
||||
* TODO: need to check in future that frame changed before doing this
|
||||
*/
|
||||
if (orientationChanged) {
|
||||
KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
|
||||
}
|
||||
if (positionChanged) {
|
||||
KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
|
||||
}
|
||||
|
||||
/* free temp data */
|
||||
BLI_freelistN(&dsources);
|
||||
}
|
||||
}
|
||||
|
||||
static int flyApply(bContext *C, FlyInfo *fly)
|
||||
{
|
||||
|
||||
#define FLY_ROTATE_FAC 2.5f /* more is faster */
|
||||
#define FLY_ZUP_CORRECT_FAC 0.1f /* amount to correct per step */
|
||||
#define FLY_ZUP_CORRECT_ACCEL 0.05f /* increase upright momentum each step */
|
||||
@ -545,11 +678,7 @@ static int flyApply(bContext *C, FlyInfo *fly)
|
||||
a fly loop where the user can move move the view as if they are flying
|
||||
*/
|
||||
RegionView3D *rv3d= fly->rv3d;
|
||||
View3D *v3d = fly->v3d;
|
||||
ARegion *ar = fly->ar;
|
||||
Scene *scene= fly->scene;
|
||||
|
||||
float prev_view_mat[4][4];
|
||||
|
||||
float mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */
|
||||
dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */
|
||||
@ -567,15 +696,11 @@ 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*/
|
||||
|
||||
if(fly->root_parent)
|
||||
ED_view3d_to_m4(prev_view_mat, fly->rv3d->ofs, fly->rv3d->viewquat, fly->rv3d->dist);
|
||||
#ifdef NDOF_FLY_DEBUG
|
||||
static unsigned int iteration = 1;
|
||||
printf("fly timer %d\n", iteration++);
|
||||
#endif
|
||||
|
||||
/* 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 +747,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 */
|
||||
@ -784,69 +911,9 @@ static int flyApply(bContext *C, FlyInfo *fly)
|
||||
ED_area_headerprint(fly->ar, "FlyKeys Speed:(+/- | Wheel), Upright Axis:X off/Z off, Slow:Shift, Direction:WASDRF, Ok:LMB, Pan:MMB, Cancel:RMB");
|
||||
#endif
|
||||
|
||||
/* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
|
||||
if (rv3d->persp==RV3D_CAMOB) {
|
||||
ID *id_key;
|
||||
/* transform the parent or the camera? */
|
||||
if(fly->root_parent) {
|
||||
Object *ob_update;
|
||||
if (rv3d->persp==RV3D_CAMOB)
|
||||
move_camera(C, rv3d, fly, (fly->xlock || fly->zlock || moffset[0] || moffset[1]), fly->speed);
|
||||
|
||||
float view_mat[4][4];
|
||||
float prev_view_imat[4][4];
|
||||
float diff_mat[4][4];
|
||||
float parent_mat[4][4];
|
||||
|
||||
invert_m4_m4(prev_view_imat, prev_view_mat);
|
||||
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
|
||||
mul_m4_m4m4(diff_mat, prev_view_imat, view_mat);
|
||||
mul_m4_m4m4(parent_mat, fly->root_parent->obmat, diff_mat);
|
||||
object_apply_mat4(fly->root_parent, parent_mat, TRUE, FALSE);
|
||||
|
||||
// where_is_object(scene, fly->root_parent);
|
||||
|
||||
ob_update= v3d->camera->parent;
|
||||
while(ob_update) {
|
||||
DAG_id_tag_update(&ob_update->id, OB_RECALC_OB);
|
||||
ob_update= ob_update->parent;
|
||||
}
|
||||
|
||||
copy_m4_m4(prev_view_mat, view_mat);
|
||||
|
||||
id_key= &fly->root_parent->id;
|
||||
|
||||
}
|
||||
else {
|
||||
float view_mat[4][4];
|
||||
ED_view3d_to_m4(view_mat, rv3d->ofs, rv3d->viewquat, rv3d->dist);
|
||||
object_apply_mat4(v3d->camera, view_mat, TRUE, FALSE);
|
||||
id_key= &v3d->camera->id;
|
||||
}
|
||||
|
||||
/* record the motion */
|
||||
if (autokeyframe_cfra_can_key(scene, id_key)) {
|
||||
ListBase dsources = {NULL, NULL};
|
||||
|
||||
/* add datasource override for the camera object */
|
||||
ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
|
||||
|
||||
/* insert keyframes
|
||||
* 1) on the first frame
|
||||
* 2) on each subsequent frame
|
||||
* TODO: need to check in future that frame changed before doing this
|
||||
*/
|
||||
if (fly->xlock || fly->zlock || moffset[0] || moffset[1]) {
|
||||
KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
|
||||
}
|
||||
if (fly->speed) {
|
||||
KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
|
||||
ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
|
||||
}
|
||||
|
||||
/* free temp data */
|
||||
BLI_freelistN(&dsources);
|
||||
}
|
||||
}
|
||||
} else
|
||||
/*were not redrawing but we need to update the time else the view will jump */
|
||||
fly->time_lastdraw= PIL_check_seconds_timer();
|
||||
@ -854,11 +921,141 @@ 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 flag = U.ndof_flag;
|
||||
|
||||
// int shouldRotate = (flag & NDOF_SHOULD_ROTATE) && (fly->pan_view == FALSE),
|
||||
// shouldTranslate = (flag & (NDOF_SHOULD_PAN | NDOF_SHOULD_ZOOM));
|
||||
|
||||
int shouldRotate = (fly->pan_view == FALSE),
|
||||
shouldTranslate = TRUE;
|
||||
|
||||
float view_inv[4];
|
||||
invert_qt_qt(view_inv, rv3d->viewquat);
|
||||
|
||||
rv3d->rot_angle = 0.f; // disable onscreen rotation doo-dad
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
if (fly->use_precision)
|
||||
speed *= 0.2f;
|
||||
|
||||
mul_v3_fl(trans, speed * dt);
|
||||
|
||||
// transform motion from view to world coordinates
|
||||
mul_qt_v3(view_inv, trans);
|
||||
|
||||
if (flag & NDOF_FLY_HELICOPTER)
|
||||
{
|
||||
// replace world z component with device y (yes it makes sense)
|
||||
trans[2] = speed * dt * vertical_sensitivity * ndof->ty;
|
||||
}
|
||||
|
||||
if (rv3d->persp==RV3D_CAMOB) {
|
||||
// respect camera position locks
|
||||
Object *lock_ob= fly->root_parent ? fly->root_parent : fly->v3d->camera;
|
||||
if (lock_ob->protectflag & OB_LOCK_LOCX) trans[0] = 0.f;
|
||||
if (lock_ob->protectflag & OB_LOCK_LOCY) trans[1] = 0.f;
|
||||
if (lock_ob->protectflag & OB_LOCK_LOCZ) trans[2] = 0.f;
|
||||
}
|
||||
|
||||
if (trans[0] || trans[1] || trans[2])
|
||||
{
|
||||
// move center of view opposite of hand motion (this is camera mode, not object mode)
|
||||
sub_v3_v3(rv3d->ofs, trans);
|
||||
shouldTranslate = TRUE;
|
||||
}
|
||||
else
|
||||
shouldTranslate = FALSE;
|
||||
}
|
||||
|
||||
if (shouldRotate)
|
||||
{
|
||||
const float turn_sensitivity = 1.f;
|
||||
|
||||
float rotation[4];
|
||||
float axis[3];
|
||||
float angle = turn_sensitivity * ndof_to_angle_axis(ndof, axis);
|
||||
|
||||
if (fabsf(angle) > 0.0001f)
|
||||
{
|
||||
shouldRotate = TRUE;
|
||||
|
||||
if (fly->use_precision)
|
||||
angle *= 0.2f;
|
||||
|
||||
// transform rotation axis from view to world coordinates
|
||||
mul_qt_v3(view_inv, axis);
|
||||
|
||||
// apply rotation to view
|
||||
axis_angle_to_quat(rotation, axis, angle);
|
||||
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);
|
||||
|
||||
if (flag & NDOF_LOCK_HORIZON)
|
||||
// force an upright viewpoint
|
||||
// TODO: make this less... sudden
|
||||
{
|
||||
float view_horizon[3] = {1.f, 0.f, 0.f}; // view +x
|
||||
float view_direction[3] = {0.f, 0.f, -1.f}; // view -z (into screen)
|
||||
|
||||
// find new inverse since viewquat has changed
|
||||
invert_qt_qt(view_inv, rv3d->viewquat);
|
||||
// could apply reverse rotation to existing view_inv to save a few cycles
|
||||
|
||||
// transform view vectors to world coordinates
|
||||
mul_qt_v3(view_inv, view_horizon);
|
||||
mul_qt_v3(view_inv, view_direction);
|
||||
|
||||
// find difference between view & world horizons
|
||||
// true horizon lives in world xy plane, so look only at difference in z
|
||||
angle = -asinf(view_horizon[2]);
|
||||
|
||||
#ifdef NDOF_FLY_DEBUG
|
||||
printf("lock horizon: adjusting %.1f degrees\n\n", RAD2DEG(angle));
|
||||
#endif
|
||||
|
||||
// rotate view so view horizon = world horizon
|
||||
axis_angle_to_quat(rotation, view_direction, angle);
|
||||
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, rotation);
|
||||
}
|
||||
|
||||
rv3d->view = RV3D_VIEW_USER;
|
||||
}
|
||||
else
|
||||
shouldRotate = FALSE;
|
||||
}
|
||||
|
||||
if (shouldTranslate || shouldRotate)
|
||||
{
|
||||
fly->redraw = TRUE;
|
||||
|
||||
if (rv3d->persp==RV3D_CAMOB)
|
||||
move_camera(C, rv3d, fly, shouldRotate, shouldTranslate);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
|
||||
static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
@ -908,7 +1105,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;
|
||||
@ -923,6 +1125,7 @@ static int fly_modal(bContext *C, wmOperator *op, wmEvent *event)
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, fly_object);
|
||||
}
|
||||
|
||||
// puts("redraw!"); // too frequent, fix tomorrow.
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ struct ARegionType;
|
||||
struct bPoseChannel;
|
||||
struct bAnimVizSettings;
|
||||
struct bMotionPath;
|
||||
struct wmNDOFMotionData;
|
||||
|
||||
#define BL_NEAR_CLIP 0.001
|
||||
|
||||
@ -72,6 +73,8 @@ 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_orbit(struct wmOperatorType *ot);
|
||||
void VIEW3D_OT_ndof_pan(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);
|
||||
@ -91,6 +94,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);
|
||||
|
@ -64,6 +64,8 @@ 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_orbit);
|
||||
WM_operatortype_append(VIEW3D_OT_ndof_pan);
|
||||
WM_operatortype_append(VIEW3D_OT_view_all);
|
||||
WM_operatortype_append(VIEW3D_OT_viewnumpad);
|
||||
WM_operatortype_append(VIEW3D_OT_view_orbit);
|
||||
@ -161,6 +163,17 @@ 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_ndof_orbit", NDOF_MOTION, 0, 0, 0);
|
||||
WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_pan", NDOF_MOTION, 0, KM_SHIFT, 0);
|
||||
WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BACK, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BACK);
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_LEFT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_LEFT);
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_RIGHT);
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_TOP);
|
||||
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_BOTTOM, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_BOTTOM);
|
||||
|
||||
/* 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);
|
||||
@ -210,6 +223,17 @@ void view3d_keymap(wmKeyConfig *keyconf)
|
||||
RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_BOTTOM);
|
||||
RNA_boolean_set(kmi->ptr, "align_active", TRUE);
|
||||
|
||||
/* 3D mouse align */
|
||||
kmi= WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, KM_SHIFT, 0);
|
||||
RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_FRONT);
|
||||
RNA_boolean_set(kmi->ptr, "align_active", TRUE);
|
||||
kmi= WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_RIGHT, KM_PRESS, KM_SHIFT, 0);
|
||||
RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_RIGHT);
|
||||
RNA_boolean_set(kmi->ptr, "align_active", TRUE);
|
||||
kmi= WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_TOP, KM_PRESS, KM_SHIFT, 0);
|
||||
RNA_enum_set(kmi->ptr, "type", RV3D_VIEW_TOP);
|
||||
RNA_boolean_set(kmi->ptr, "align_active", TRUE);
|
||||
|
||||
WM_keymap_add_item(keymap, "VIEW3D_OT_localview", PADSLASHKEY, KM_PRESS, 0, 0);
|
||||
|
||||
/* layers, shift + alt are properties set in invoke() */
|
||||
|
@ -1006,9 +1006,11 @@ int transformEvent(TransInfo *t, wmEvent *event)
|
||||
else view_editmove(event->type);
|
||||
t->redraw= 1;
|
||||
break;
|
||||
// case NDOFMOTION:
|
||||
// viewmoveNDOF(1);
|
||||
// break;
|
||||
#if 0
|
||||
case NDOF_MOTION:
|
||||
// should have been caught by tranform_modal
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
#endif
|
||||
default:
|
||||
handled = 0;
|
||||
break;
|
||||
@ -1017,43 +1019,6 @@ int transformEvent(TransInfo *t, wmEvent *event)
|
||||
// Numerical input events
|
||||
t->redraw |= handleNumInput(&(t->num), event);
|
||||
|
||||
// NDof input events
|
||||
switch(handleNDofInput(&(t->ndof), event))
|
||||
{
|
||||
case NDOF_CONFIRM:
|
||||
if ((t->options & CTX_NDOF) == 0)
|
||||
{
|
||||
/* Confirm on normal transform only */
|
||||
t->state = TRANS_CONFIRM;
|
||||
}
|
||||
break;
|
||||
case NDOF_CANCEL:
|
||||
if (t->options & CTX_NDOF)
|
||||
{
|
||||
/* Cancel on pure NDOF transform */
|
||||
t->state = TRANS_CANCEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, just redraw, NDof input was cancelled */
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
}
|
||||
break;
|
||||
case NDOF_NOMOVE:
|
||||
if (t->options & CTX_NDOF)
|
||||
{
|
||||
/* Confirm on pure NDOF transform */
|
||||
t->state = TRANS_CONFIRM;
|
||||
}
|
||||
break;
|
||||
case NDOF_REFRESH:
|
||||
t->redraw |= TREDRAW_HARD;
|
||||
break;
|
||||
default:
|
||||
handled = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Snapping events
|
||||
t->redraw |= handleSnapping(t, event);
|
||||
|
||||
@ -2886,10 +2851,6 @@ void initRotation(TransInfo *t)
|
||||
setInputPostFct(&t->mouse, postInputRotation);
|
||||
initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
|
||||
|
||||
t->ndof.axis = 16;
|
||||
/* Scale down and flip input for rotation */
|
||||
t->ndof.factor[0] = -0.2f;
|
||||
|
||||
t->idx_max = 0;
|
||||
t->num.idx_max = 0;
|
||||
t->snap[0] = 0.0f;
|
||||
@ -3161,8 +3122,6 @@ int Rotation(TransInfo *t, const int UNUSED(mval[2]))
|
||||
|
||||
final = t->values[0];
|
||||
|
||||
applyNDofInput(&t->ndof, &final);
|
||||
|
||||
snapGrid(t, &final);
|
||||
|
||||
if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
|
||||
@ -3216,11 +3175,6 @@ void initTrackball(TransInfo *t)
|
||||
|
||||
initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
|
||||
|
||||
t->ndof.axis = 40;
|
||||
/* Scale down input for rotation */
|
||||
t->ndof.factor[0] = 0.2f;
|
||||
t->ndof.factor[1] = 0.2f;
|
||||
|
||||
t->idx_max = 1;
|
||||
t->num.idx_max = 1;
|
||||
t->snap[0] = 0.0f;
|
||||
@ -3276,8 +3230,6 @@ int Trackball(TransInfo *t, const int UNUSED(mval[2]))
|
||||
phi[0] = t->values[0];
|
||||
phi[1] = t->values[1];
|
||||
|
||||
applyNDofInput(&t->ndof, phi);
|
||||
|
||||
snapGrid(t, phi);
|
||||
|
||||
if (hasNumInput(&t->num)) {
|
||||
@ -3331,8 +3283,6 @@ void initTranslation(TransInfo *t)
|
||||
t->num.flag = 0;
|
||||
t->num.idx_max = t->idx_max;
|
||||
|
||||
t->ndof.axis = (t->flag & T_2D_EDIT)? 1|2: 1|2|4;
|
||||
|
||||
if(t->spacetype == SPACE_VIEW3D) {
|
||||
RegionView3D *rv3d = t->ar->regiondata;
|
||||
|
||||
@ -3507,7 +3457,6 @@ int Translation(TransInfo *t, const int UNUSED(mval[2]))
|
||||
headerTranslation(t, pvec, str);
|
||||
}
|
||||
else {
|
||||
applyNDofInput(&t->ndof, t->values);
|
||||
snapGrid(t, t->values);
|
||||
applyNumInput(&t->num, t->values);
|
||||
if (hasNumInput(&t->num)) {
|
||||
@ -3616,10 +3565,6 @@ void initTilt(TransInfo *t)
|
||||
|
||||
initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
|
||||
|
||||
t->ndof.axis = 16;
|
||||
/* Scale down and flip input for rotation */
|
||||
t->ndof.factor[0] = -0.2f;
|
||||
|
||||
t->idx_max = 0;
|
||||
t->num.idx_max = 0;
|
||||
t->snap[0] = 0.0f;
|
||||
@ -3643,8 +3588,6 @@ int Tilt(TransInfo *t, const int UNUSED(mval[2]))
|
||||
|
||||
final = t->values[0];
|
||||
|
||||
applyNDofInput(&t->ndof, &final);
|
||||
|
||||
snapGrid(t, &final);
|
||||
|
||||
if (hasNumInput(&t->num)) {
|
||||
@ -3759,10 +3702,6 @@ void initPushPull(TransInfo *t)
|
||||
|
||||
initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
|
||||
|
||||
t->ndof.axis = 4;
|
||||
/* Flip direction */
|
||||
t->ndof.factor[0] = -1.0f;
|
||||
|
||||
t->idx_max = 0;
|
||||
t->num.idx_max = 0;
|
||||
t->snap[0] = 0.0f;
|
||||
@ -3783,8 +3722,6 @@ int PushPull(TransInfo *t, const int UNUSED(mval[2]))
|
||||
|
||||
distance = t->values[0];
|
||||
|
||||
applyNDofInput(&t->ndof, &distance);
|
||||
|
||||
snapGrid(t, &distance);
|
||||
|
||||
applyNumInput(&t->num, &distance);
|
||||
@ -5309,8 +5246,6 @@ void initSeqSlide(TransInfo *t)
|
||||
t->num.flag = 0;
|
||||
t->num.idx_max = t->idx_max;
|
||||
|
||||
t->ndof.axis = 1|2;
|
||||
|
||||
t->snap[0] = 0.0f;
|
||||
t->snap[1] = floor(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
|
||||
t->snap[2] = 10.0f;
|
||||
@ -5365,7 +5300,6 @@ int SeqSlide(TransInfo *t, const int UNUSED(mval[2]))
|
||||
VECCOPY(t->values, tvec);
|
||||
}
|
||||
else {
|
||||
applyNDofInput(&t->ndof, t->values);
|
||||
snapGrid(t, t->values);
|
||||
applyNumInput(&t->num, t->values);
|
||||
}
|
||||
@ -5925,54 +5859,3 @@ void BIF_TransformSetUndo(char *UNUSED(str))
|
||||
// TRANSFORM_FIX_ME
|
||||
//Trans.undostr= str;
|
||||
}
|
||||
|
||||
|
||||
#if 0 // TRANSFORM_FIX_ME
|
||||
static void NDofTransform(void)
|
||||
{
|
||||
float fval[7];
|
||||
float maxval = 50.0f; // also serves as threshold
|
||||
int axis = -1;
|
||||
int mode = 0;
|
||||
int i;
|
||||
|
||||
getndof(fval);
|
||||
|
||||
for(i = 0; i < 6; i++)
|
||||
{
|
||||
float val = fabs(fval[i]);
|
||||
if (val > maxval)
|
||||
{
|
||||
axis = i;
|
||||
maxval = val;
|
||||
}
|
||||
}
|
||||
|
||||
switch(axis)
|
||||
{
|
||||
case -1:
|
||||
/* No proper axis found */
|
||||
break;
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
mode = TFM_TRANSLATION;
|
||||
break;
|
||||
case 4:
|
||||
mode = TFM_ROTATION;
|
||||
break;
|
||||
case 3:
|
||||
case 5:
|
||||
mode = TFM_TRACKBALL;
|
||||
break;
|
||||
default:
|
||||
printf("ndof: what we are doing here ?");
|
||||
}
|
||||
|
||||
if (mode != 0)
|
||||
{
|
||||
initTransform(mode, CTX_NDOF);
|
||||
Transform();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -360,6 +360,12 @@ static int transform_modal(bContext *C, wmOperator *op, wmEvent *event)
|
||||
|
||||
TransInfo *t = op->customdata;
|
||||
|
||||
if (event->type == NDOF_MOTION)
|
||||
{
|
||||
// puts("transform_modal: passing through NDOF_MOTION");
|
||||
return OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
|
||||
/* XXX insert keys are called here, and require context */
|
||||
t->context= C;
|
||||
exit_code = transformEvent(t, event);
|
||||
|
@ -365,7 +365,6 @@ typedef struct UserDef {
|
||||
short recent_files; /* maximum number of recently used files to remember */
|
||||
short smooth_viewtx; /* miliseconds to spend spinning the view */
|
||||
short glreslimit;
|
||||
short ndof_pan, ndof_rotate;
|
||||
short curssize;
|
||||
short color_picker_type;
|
||||
short ipo_new; /* interpolation mode for newly added F-Curves */
|
||||
@ -376,6 +375,10 @@ typedef struct UserDef {
|
||||
|
||||
short widget_unit; /* defaults to 20 for 72 DPI setting */
|
||||
short anisotropic_filter;
|
||||
/*short pad[3]; */
|
||||
|
||||
float ndof_sensitivity; /* overall sensitivity of 3D mouse */
|
||||
int ndof_flag; /* flags for 3D mouse */
|
||||
|
||||
char versemaster[160];
|
||||
char verseuser[160];
|
||||
@ -384,7 +387,7 @@ typedef struct UserDef {
|
||||
short autokey_mode; /* autokeying mode */
|
||||
short autokey_flag; /* flags for autokeying */
|
||||
|
||||
short text_render, pad9; /*options for text rendering*/
|
||||
short text_render, pad9[3]; /*options for text rendering*/
|
||||
|
||||
struct ColorBand coba_weight; /* from texture.h */
|
||||
|
||||
@ -577,6 +580,28 @@ extern UserDef U; /* from blenkernel blender.c */
|
||||
#define TH_OLDSKOOL 3
|
||||
#define TH_SHADED 4
|
||||
|
||||
/* ndof_flag (3D mouse options) */
|
||||
#define NDOF_SHOW_GUIDE (1 << 0)
|
||||
#define NDOF_FLY_HELICOPTER (1 << 1)
|
||||
#define NDOF_LOCK_HORIZON (1 << 2)
|
||||
/* the following might not need to be saved between sessions,
|
||||
but they do need to live somewhere accessible... */
|
||||
#define NDOF_SHOULD_PAN (1 << 3)
|
||||
#define NDOF_SHOULD_ZOOM (1 << 4)
|
||||
#define NDOF_SHOULD_ROTATE (1 << 5)
|
||||
/* orbit navigation modes
|
||||
only two options, so it's sort of a hyrbrid bool/enum
|
||||
if ((U.ndof_flag & NDOF_ORBIT_MODE) == NDOF_OM_OBJECT)... */
|
||||
/*
|
||||
#define NDOF_ORBIT_MODE (1 << 6)
|
||||
#define NDOF_OM_TARGETCAMERA 0
|
||||
#define NDOF_OM_OBJECT NDOF_ORBIT_MODE
|
||||
*/
|
||||
/* actually... users probably don't care about what the mode
|
||||
is called, just that it feels right */
|
||||
#define NDOF_ORBIT_INVERT_AXES (1 << 6)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -130,7 +130,11 @@ typedef struct RegionView3D {
|
||||
|
||||
float twangle[3];
|
||||
|
||||
float padf;
|
||||
/* active rotation from NDOF or elsewhere */
|
||||
float rot_angle;
|
||||
float rot_axis[3];
|
||||
|
||||
char pad2[4];
|
||||
|
||||
} RegionView3D;
|
||||
|
||||
@ -190,8 +194,7 @@ typedef struct View3D {
|
||||
/* drawflags, denoting state */
|
||||
short zbuf, transp, xray;
|
||||
|
||||
char ndofmode; /* mode of transform for 6DOF devices -1 not found, 0 normal, 1 fly, 2 ob transform */
|
||||
char ndoffilter; /* filter for 6DOF devices 0 normal, 1 dominant */
|
||||
char pad3[2];
|
||||
|
||||
void *properties_storage; /* Nkey panel stores stuff here (runtime only!) */
|
||||
|
||||
|
@ -2738,15 +2738,28 @@ static void rna_def_userdef_input(BlenderRNA *brna)
|
||||
RNA_def_property_range(prop, 3, 40);
|
||||
RNA_def_property_ui_text(prop, "Drag Threshold", "Amount of pixels you have to drag before dragging UI items happens");
|
||||
|
||||
prop= RNA_def_property(srna, "ndof_pan_speed", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "ndof_pan");
|
||||
RNA_def_property_range(prop, 0, 200);
|
||||
RNA_def_property_ui_text(prop, "NDof Pan Speed", "The overall panning speed of an NDOF device, as percent of standard");
|
||||
/* 3D mouse settings */
|
||||
prop= RNA_def_property(srna, "ndof_sensitivity", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_range(prop, 0.25f, 4.0f);
|
||||
RNA_def_property_ui_text(prop, "Sensitivity", "Overall sensitivity of the 3D Mouse");
|
||||
|
||||
prop= RNA_def_property(srna, "ndof_show_guide", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_SHOW_GUIDE);
|
||||
RNA_def_property_ui_text(prop, "Show Navigation Guide", "Display the center and axis during rotation");
|
||||
/* TODO: update description when fly-mode visuals are in place ("projected position in fly mode")*/
|
||||
|
||||
prop= RNA_def_property(srna, "ndof_orbit_invert_axes", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_ORBIT_INVERT_AXES);
|
||||
RNA_def_property_ui_text(prop, "Invert Axes", "Toggle between moving the viewpoint or moving the scene being viewed");
|
||||
|
||||
prop= RNA_def_property(srna, "ndof_lock_horizon", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_LOCK_HORIZON);
|
||||
RNA_def_property_ui_text(prop, "Lock Horizon", "Keep horizon level while flying with 3D Mouse");
|
||||
|
||||
prop= RNA_def_property(srna, "ndof_fly_helicopter", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "ndof_flag", NDOF_FLY_HELICOPTER);
|
||||
RNA_def_property_ui_text(prop, "Helicopter Mode", "Device up/down directly controls your Z position");
|
||||
|
||||
prop= RNA_def_property(srna, "ndof_rotate_speed", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "ndof_rotate");
|
||||
RNA_def_property_range(prop, 0, 200);
|
||||
RNA_def_property_ui_text(prop, "NDof Rotation Speed", "The overall rotation speed of an NDOF device, as percent of standard");
|
||||
|
||||
prop= RNA_def_property(srna, "mouse_double_click_time", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, NULL, "dbl_click_time");
|
||||
|
@ -106,6 +106,46 @@ EnumPropertyItem event_timer_type_items[]= {
|
||||
{TIMER2, "TIMER2", 0, "Timer 2", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
EnumPropertyItem event_ndof_type_items[]= {
|
||||
/* buttons on all 3dconnexion devices */
|
||||
{NDOF_BUTTON_MENU, "NDOF_BUTTON_MENU", 0, "Menu", ""},
|
||||
{NDOF_BUTTON_FIT, "NDOF_BUTTON_FIT", 0, "Fit", ""},
|
||||
/* view buttons */
|
||||
{NDOF_BUTTON_TOP, "NDOF_BUTTON_TOP", 0, "Top", ""},
|
||||
{NDOF_BUTTON_BOTTOM, "NDOF_BUTTON_BOTTOM", 0, "Bottom", ""},
|
||||
{NDOF_BUTTON_LEFT, "NDOF_BUTTON_LEFT", 0, "Left", ""},
|
||||
{NDOF_BUTTON_RIGHT, "NDOF_BUTTON_RIGHT", 0, "Right", ""},
|
||||
{NDOF_BUTTON_FRONT, "NDOF_BUTTON_FRONT", 0, "Front", ""},
|
||||
{NDOF_BUTTON_BACK, "NDOF_BUTTON_BACK", 0, "Back", ""},
|
||||
/* more views */
|
||||
{NDOF_BUTTON_ISO1, "NDOF_BUTTON_ISO1", 0, "ISO 1", ""},
|
||||
{NDOF_BUTTON_ISO2, "NDOF_BUTTON_ISO2", 0, "ISO 2", ""},
|
||||
/* 90 degree rotations */
|
||||
{NDOF_BUTTON_ROLL_CW, "NDOF_BUTTON_ROLL_CW", 0, "Roll CW", ""},
|
||||
{NDOF_BUTTON_ROLL_CCW, "NDOF_BUTTON_ROLL_CCW", 0, "Roll CCW", ""},
|
||||
{NDOF_BUTTON_SPIN_CW, "NDOF_BUTTON_SPIN_CW", 0, "Spin CW", ""},
|
||||
{NDOF_BUTTON_SPIN_CCW, "NDOF_BUTTON_SPIN_CCW", 0, "Spin CCW", ""},
|
||||
{NDOF_BUTTON_TILT_CW, "NDOF_BUTTON_TILT_CW", 0, "Tilt CW", ""},
|
||||
{NDOF_BUTTON_TILT_CCW, "NDOF_BUTTON_TILT_CCW", 0, "Tilt CCW", ""},
|
||||
/* device control */
|
||||
{NDOF_BUTTON_ROTATE, "NDOF_BUTTON_ROTATE", 0, "Rotate", ""},
|
||||
{NDOF_BUTTON_PANZOOM, "NDOF_BUTTON_PANZOOM", 0, "Pan/Zoom", ""},
|
||||
{NDOF_BUTTON_DOMINANT, "NDOF_BUTTON_DOMINANT", 0, "Dominant", ""},
|
||||
{NDOF_BUTTON_PLUS, "NDOF_BUTTON_PLUS", 0, "Plus", ""},
|
||||
{NDOF_BUTTON_MINUS, "NDOF_BUTTON_MINUS", 0, "Minus", ""},
|
||||
/* general-purpose buttons */
|
||||
{NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "Button 1", ""},
|
||||
{NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "Button 2", ""},
|
||||
{NDOF_BUTTON_3, "NDOF_BUTTON_3", 0, "Button 3", ""},
|
||||
{NDOF_BUTTON_4, "NDOF_BUTTON_4", 0, "Button 4", ""},
|
||||
{NDOF_BUTTON_5, "NDOF_BUTTON_5", 0, "Button 5", ""},
|
||||
{NDOF_BUTTON_6, "NDOF_BUTTON_6", 0, "Button 6", ""},
|
||||
{NDOF_BUTTON_7, "NDOF_BUTTON_7", 0, "Button 7", ""},
|
||||
{NDOF_BUTTON_8, "NDOF_BUTTON_8", 0, "Button 8", ""},
|
||||
{NDOF_BUTTON_9, "NDOF_BUTTON_9", 0, "Button 9", ""},
|
||||
{NDOF_BUTTON_10, "NDOF_BUTTON_10", 0, "Button 10", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
/* not returned: CAPSLOCKKEY, UNKNOWNKEY */
|
||||
EnumPropertyItem event_type_items[] = {
|
||||
|
||||
@ -256,6 +296,44 @@ EnumPropertyItem event_type_items[] = {
|
||||
{TIMER0, "TIMER0", 0, "Timer 0", ""},
|
||||
{TIMER1, "TIMER1", 0, "Timer 1", ""},
|
||||
{TIMER2, "TIMER2", 0, "Timer 2", ""},
|
||||
{0, "", 0, NULL, NULL},
|
||||
/* buttons on all 3dconnexion devices */
|
||||
{NDOF_BUTTON_MENU, "NDOF_BUTTON_MENU", 0, "Menu", ""},
|
||||
{NDOF_BUTTON_FIT, "NDOF_BUTTON_FIT", 0, "Fit", ""},
|
||||
/* view buttons */
|
||||
{NDOF_BUTTON_TOP, "NDOF_BUTTON_TOP", 0, "Top", ""},
|
||||
{NDOF_BUTTON_BOTTOM, "NDOF_BUTTON_BOTTOM", 0, "Bottom", ""},
|
||||
{NDOF_BUTTON_LEFT, "NDOF_BUTTON_LEFT", 0, "Left", ""},
|
||||
{NDOF_BUTTON_RIGHT, "NDOF_BUTTON_RIGHT", 0, "Right", ""},
|
||||
{NDOF_BUTTON_FRONT, "NDOF_BUTTON_FRONT", 0, "Front", ""},
|
||||
{NDOF_BUTTON_BACK, "NDOF_BUTTON_BACK", 0, "Back", ""},
|
||||
/* more views */
|
||||
{NDOF_BUTTON_ISO1, "NDOF_BUTTON_ISO1", 0, "ISO 1", ""},
|
||||
{NDOF_BUTTON_ISO2, "NDOF_BUTTON_ISO2", 0, "ISO 2", ""},
|
||||
/* 90 degree rotations */
|
||||
{NDOF_BUTTON_ROLL_CW, "NDOF_BUTTON_ROLL_CW", 0, "Roll CW", ""},
|
||||
{NDOF_BUTTON_ROLL_CCW, "NDOF_BUTTON_ROLL_CCW", 0, "Roll CCW", ""},
|
||||
{NDOF_BUTTON_SPIN_CW, "NDOF_BUTTON_SPIN_CW", 0, "Spin CW", ""},
|
||||
{NDOF_BUTTON_SPIN_CCW, "NDOF_BUTTON_SPIN_CCW", 0, "Spin CCW", ""},
|
||||
{NDOF_BUTTON_TILT_CW, "NDOF_BUTTON_TILT_CW", 0, "Tilt CW", ""},
|
||||
{NDOF_BUTTON_TILT_CCW, "NDOF_BUTTON_TILT_CCW", 0, "Tilt CCW", ""},
|
||||
/* device control */
|
||||
{NDOF_BUTTON_ROTATE, "NDOF_BUTTON_ROTATE", 0, "Rotate", ""},
|
||||
{NDOF_BUTTON_PANZOOM, "NDOF_BUTTON_PANZOOM", 0, "Pan/Zoom", ""},
|
||||
{NDOF_BUTTON_DOMINANT, "NDOF_BUTTON_DOMINANT", 0, "Dominant", ""},
|
||||
{NDOF_BUTTON_PLUS, "NDOF_BUTTON_PLUS", 0, "Plus", ""},
|
||||
{NDOF_BUTTON_MINUS, "NDOF_BUTTON_MINUS", 0, "Minus", ""},
|
||||
/* general-purpose buttons */
|
||||
{NDOF_BUTTON_1, "NDOF_BUTTON_1", 0, "Button 1", ""},
|
||||
{NDOF_BUTTON_2, "NDOF_BUTTON_2", 0, "Button 2", ""},
|
||||
{NDOF_BUTTON_3, "NDOF_BUTTON_3", 0, "Button 3", ""},
|
||||
{NDOF_BUTTON_4, "NDOF_BUTTON_4", 0, "Button 4", ""},
|
||||
{NDOF_BUTTON_5, "NDOF_BUTTON_5", 0, "Button 5", ""},
|
||||
{NDOF_BUTTON_6, "NDOF_BUTTON_6", 0, "Button 6", ""},
|
||||
{NDOF_BUTTON_7, "NDOF_BUTTON_7", 0, "Button 7", ""},
|
||||
{NDOF_BUTTON_8, "NDOF_BUTTON_8", 0, "Button 8", ""},
|
||||
{NDOF_BUTTON_9, "NDOF_BUTTON_9", 0, "Button 9", ""},
|
||||
{NDOF_BUTTON_10, "NDOF_BUTTON_10", 0, "Button 10", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
EnumPropertyItem keymap_propvalue_items[] = {
|
||||
@ -303,6 +381,7 @@ EnumPropertyItem wm_report_items[] = {
|
||||
#define KMI_TYPE_TWEAK 2
|
||||
#define KMI_TYPE_TEXTINPUT 3
|
||||
#define KMI_TYPE_TIMER 4
|
||||
#define KMI_TYPE_NDOF 5
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
@ -433,6 +512,7 @@ static int rna_wmKeyMapItem_map_type_get(PointerRNA *ptr)
|
||||
if(ISKEYBOARD(kmi->type)) return KMI_TYPE_KEYBOARD;
|
||||
if(ISTWEAK(kmi->type)) return KMI_TYPE_TWEAK;
|
||||
if(ISMOUSE(kmi->type)) return KMI_TYPE_MOUSE;
|
||||
if(ISNDOF(kmi->type)) return KMI_TYPE_NDOF;
|
||||
if(kmi->type == KM_TEXTINPUT) return KMI_TYPE_TEXTINPUT;
|
||||
return KMI_TYPE_KEYBOARD;
|
||||
}
|
||||
@ -464,6 +544,10 @@ static void rna_wmKeyMapItem_map_type_set(PointerRNA *ptr, int value)
|
||||
kmi->type= TIMER;
|
||||
kmi->val= KM_NOTHING;
|
||||
break;
|
||||
case KMI_TYPE_NDOF:
|
||||
kmi->type = NDOF_BUTTON_MENU;
|
||||
kmi->val = KM_NOTHING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -475,6 +559,7 @@ static EnumPropertyItem *rna_KeyMapItem_type_itemf(bContext *UNUSED(C), PointerR
|
||||
if(map_type == KMI_TYPE_MOUSE) return event_mouse_type_items;
|
||||
if(map_type == KMI_TYPE_TWEAK) return event_tweak_type_items;
|
||||
if(map_type == KMI_TYPE_TIMER) return event_timer_type_items;
|
||||
if(map_type == KMI_TYPE_NDOF) return event_ndof_type_items;
|
||||
else return event_type_items;
|
||||
}
|
||||
|
||||
@ -482,7 +567,7 @@ static EnumPropertyItem *rna_KeyMapItem_value_itemf(bContext *UNUSED(C), Pointer
|
||||
{
|
||||
int map_type= rna_wmKeyMapItem_map_type_get(ptr);
|
||||
|
||||
if(map_type == KMI_TYPE_MOUSE || map_type == KMI_TYPE_KEYBOARD) return event_keymouse_value_items;
|
||||
if(map_type == KMI_TYPE_MOUSE || map_type == KMI_TYPE_KEYBOARD || map_type == KMI_TYPE_NDOF) return event_keymouse_value_items;
|
||||
if(map_type == KMI_TYPE_TWEAK) return event_tweak_value_items;
|
||||
else return event_value_items;
|
||||
}
|
||||
@ -1653,6 +1738,7 @@ static void rna_def_keyconfig(BlenderRNA *brna)
|
||||
{KMI_TYPE_KEYBOARD, "KEYBOARD", 0, "Keyboard", ""},
|
||||
{KMI_TYPE_TWEAK, "TWEAK", 0, "Tweak", ""},
|
||||
{KMI_TYPE_MOUSE, "MOUSE", 0, "Mouse", ""},
|
||||
{KMI_TYPE_NDOF, "NDOF", 0, "NDOF", ""},
|
||||
{KMI_TYPE_TEXTINPUT, "TEXTINPUT", 0, "Text Input", ""},
|
||||
{KMI_TYPE_TIMER, "TIMER", 0, "Timer", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
@ -377,6 +377,26 @@ typedef struct wmTabletData {
|
||||
float Ytilt; /* as above */
|
||||
} wmTabletData;
|
||||
|
||||
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.
|
||||
// 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 {
|
||||
struct wmTimer *next, *prev;
|
||||
|
||||
|
@ -1815,6 +1815,9 @@ void wm_event_do_handlers(bContext *C)
|
||||
/* for regions having custom cursors */
|
||||
wm_paintcursor_test(C, event);
|
||||
}
|
||||
else if (event->type==NDOF_MOTION) {
|
||||
win->addmousemove = TRUE;
|
||||
}
|
||||
|
||||
for(sa= win->screen->areabase.first; sa; sa= sa->next) {
|
||||
if(wm_event_inside_i(event, &sa->totrct)) {
|
||||
@ -1879,7 +1882,10 @@ void wm_event_do_handlers(bContext *C)
|
||||
if(doit && win->screen && win->screen->subwinactive != win->screen->mainwin) {
|
||||
win->eventstate->prevx= event->x;
|
||||
win->eventstate->prevy= event->y;
|
||||
//printf("win->eventstate->prev = %d %d\n", event->x, event->y);
|
||||
}
|
||||
else
|
||||
;//printf("not setting prev to %d %d\n", event->x, event->y);
|
||||
}
|
||||
|
||||
/* store last event for this window */
|
||||
@ -1922,6 +1928,7 @@ void wm_event_do_handlers(bContext *C)
|
||||
/* only add mousemove when queue was read entirely */
|
||||
if(win->addmousemove && win->eventstate) {
|
||||
wmEvent tevent= *(win->eventstate);
|
||||
//printf("adding MOUSEMOVE %d %d\n", tevent.x, tevent.y);
|
||||
tevent.type= MOUSEMOVE;
|
||||
tevent.prevx= tevent.x;
|
||||
tevent.prevy= tevent.y;
|
||||
@ -2309,6 +2316,30 @@ 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");
|
||||
|
||||
const float s = U.ndof_sensitivity;
|
||||
|
||||
data->tx = s * ghost->tx;
|
||||
data->ty = s * ghost->ty;
|
||||
data->tz = s * ghost->tz;
|
||||
|
||||
data->rx = s * ghost->rx;
|
||||
data->ry = s * ghost->ry;
|
||||
data->rz = s * ghost->rz;
|
||||
|
||||
data->dt = ghost->dt;
|
||||
|
||||
data->progress = (wmProgress) ghost->progress;
|
||||
|
||||
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)
|
||||
{
|
||||
@ -2385,6 +2416,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
|
||||
update_tablet_data(win, &event);
|
||||
wm_event_add(win, &event);
|
||||
|
||||
//printf("sending MOUSEMOVE %d %d\n", event.x, event.y);
|
||||
|
||||
/* also add to other window if event is there, this makes overdraws disappear nicely */
|
||||
/* it remaps mousecoord to other window in event */
|
||||
owin= wm_event_cursor_other_windows(wm, win, &event);
|
||||
@ -2557,6 +2590,38 @@ 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);
|
||||
|
||||
//printf("sending NDOF_MOTION, prev = %d %d\n", event.x, event.y);
|
||||
|
||||
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;
|
||||
|
@ -183,8 +183,6 @@ void WM_init(bContext *C, int argc, const char **argv)
|
||||
|
||||
ED_preview_init_dbase();
|
||||
|
||||
G.ndofdevice = -1; /* XXX bad initializer, needs set otherwise buttons show! */
|
||||
|
||||
WM_read_history();
|
||||
|
||||
/* allow a path of "", this is what happens when making a new file */
|
||||
|
@ -1411,6 +1411,22 @@ static void WM_OT_search_menu(wmOperatorType *ot)
|
||||
ot->poll= wm_search_menu_poll;
|
||||
}
|
||||
|
||||
static int wm_ndof_menu_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
|
||||
{
|
||||
uiPupMenuInvoke(C,"VIEW3D_MT_ndof_settings");
|
||||
|
||||
return OPERATOR_FINISHED; // <-- correct?
|
||||
return OPERATOR_CANCELLED; // <-- correct?
|
||||
}
|
||||
|
||||
static void WM_OT_ndof_menu(wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "NDOF Menu";
|
||||
ot->idname = "WM_OT_ndof_menu";
|
||||
|
||||
ot->invoke = wm_ndof_menu_invoke;
|
||||
}
|
||||
|
||||
static int wm_call_menu_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
char idname[BKE_ST_MAXNAME];
|
||||
@ -3417,6 +3433,54 @@ static void WM_OT_memory_statistics(wmOperatorType *ot)
|
||||
|
||||
/* ******************************************************* */
|
||||
|
||||
static int wm_ndof_sensitivity_exec(bContext *UNUSED(C), wmOperator *op)
|
||||
{
|
||||
const float min = 0.25f, max = 4.f; // TODO: get these from RNA property
|
||||
float change;
|
||||
float sensitivity = U.ndof_sensitivity;
|
||||
|
||||
if(RNA_boolean_get(op->ptr, "fast"))
|
||||
change = 0.5f; // 50% change
|
||||
else
|
||||
change = 0.1f; // 10%
|
||||
|
||||
if(RNA_boolean_get(op->ptr, "decrease"))
|
||||
{
|
||||
sensitivity -= sensitivity * change;
|
||||
if (sensitivity < min)
|
||||
sensitivity = min;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensitivity += sensitivity * change;
|
||||
if (sensitivity > max)
|
||||
sensitivity = max;
|
||||
}
|
||||
|
||||
if (sensitivity != U.ndof_sensitivity)
|
||||
{
|
||||
U.ndof_sensitivity = sensitivity;
|
||||
printf("new sensitivity: %f\n", U.ndof_sensitivity);
|
||||
}
|
||||
else
|
||||
printf("same sensitivity: %f\n", U.ndof_sensitivity);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static void WM_OT_ndof_sensitivity_change(wmOperatorType *ot)
|
||||
{
|
||||
ot->name= "Change NDOF sensitivity";
|
||||
ot->idname= "WM_OT_ndof_sensitivity_change";
|
||||
ot->description="Change NDOF sensitivity";
|
||||
|
||||
ot->exec= wm_ndof_sensitivity_exec;
|
||||
|
||||
RNA_def_boolean(ot->srna, "decrease", 1, "Decrease NDOF sensitivity", "If true then action decreases NDOF sensitivity instead of increasing");
|
||||
RNA_def_boolean(ot->srna, "fast", 0, "Fast NDOF sensitivity change", "If true then sensitivity changes 50%, otherwise 10%");
|
||||
}
|
||||
|
||||
/* ******************************************************* */
|
||||
/* called on initialize WM_exit() */
|
||||
void wm_operatortype_free(void)
|
||||
{
|
||||
@ -3453,8 +3517,10 @@ void wm_operatortype_init(void)
|
||||
WM_operatortype_append(WM_OT_debug_menu);
|
||||
WM_operatortype_append(WM_OT_splash);
|
||||
WM_operatortype_append(WM_OT_search_menu);
|
||||
WM_operatortype_append(WM_OT_ndof_menu);
|
||||
WM_operatortype_append(WM_OT_call_menu);
|
||||
WM_operatortype_append(WM_OT_radial_control);
|
||||
WM_operatortype_append(WM_OT_ndof_sensitivity_change);
|
||||
#if defined(WIN32)
|
||||
WM_operatortype_append(WM_OT_console_toggle);
|
||||
#endif
|
||||
@ -3674,11 +3740,12 @@ void wm_window_keymap(wmKeyConfig *keyconf)
|
||||
/* debug/testing */
|
||||
WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
|
||||
WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT|KM_CTRL, 0);
|
||||
|
||||
/* menus that can be accessed anywhere in blender */
|
||||
WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0);
|
||||
WM_keymap_add_item(keymap, "WM_OT_ndof_menu", NDOF_BUTTON_MENU, KM_PRESS, 0, 0);
|
||||
|
||||
/* Space switching */
|
||||
|
||||
|
||||
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F2KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was DXF export */
|
||||
RNA_string_set(kmi->ptr, "data_path", "area.type");
|
||||
RNA_string_set(kmi->ptr, "value", "LOGIC_EDITOR");
|
||||
@ -3723,6 +3790,23 @@ void wm_window_keymap(wmKeyConfig *keyconf)
|
||||
RNA_string_set(kmi->ptr, "data_path", "area.type");
|
||||
RNA_string_set(kmi->ptr, "value", "DOPESHEET_EDITOR");
|
||||
|
||||
/* ndof speed */
|
||||
kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_PLUS, KM_PRESS, 0, 0);
|
||||
RNA_boolean_set(kmi->ptr, "decrease", FALSE);
|
||||
RNA_boolean_set(kmi->ptr, "fast", FALSE);
|
||||
|
||||
kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_MINUS, KM_PRESS, 0, 0);
|
||||
RNA_boolean_set(kmi->ptr, "decrease", TRUE);
|
||||
RNA_boolean_set(kmi->ptr, "fast", FALSE);
|
||||
|
||||
kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_PLUS, KM_PRESS, KM_SHIFT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "decrease", FALSE);
|
||||
RNA_boolean_set(kmi->ptr, "fast", TRUE);
|
||||
|
||||
kmi= WM_keymap_add_item(keymap, "WM_OT_ndof_sensitivity_change", NDOF_BUTTON_MINUS, KM_PRESS, KM_SHIFT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "decrease", TRUE);
|
||||
RNA_boolean_set(kmi->ptr, "fast", TRUE);
|
||||
|
||||
gesture_circle_modal_keymap(keyconf);
|
||||
gesture_border_modal_keymap(keyconf);
|
||||
gesture_zoom_border_modal_keymap(keyconf);
|
||||
|
@ -621,12 +621,12 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private)
|
||||
if (!ghostwin) {
|
||||
// XXX - should be checked, why are we getting an event here, and
|
||||
// what is it?
|
||||
|
||||
puts("<!> event has no window");
|
||||
return 1;
|
||||
} else if (!GHOST_ValidWindow(g_system, ghostwin)) {
|
||||
// XXX - should be checked, why are we getting an event here, and
|
||||
// what is it?
|
||||
|
||||
puts("<!> event has invalid window");
|
||||
return 1;
|
||||
} else {
|
||||
win= GHOST_GetWindowUserData(ghostwin);
|
||||
|
@ -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
|
||||
@ -78,6 +79,56 @@
|
||||
#define INBETWEEN_MOUSEMOVE 17
|
||||
|
||||
|
||||
/* NDOF (from SpaceNavigator & friends)
|
||||
These should be kept in sync with GHOST_NDOFManager.h
|
||||
Ordering matters, exact values do not. */
|
||||
|
||||
#define NDOF_MOTION 400
|
||||
|
||||
enum {
|
||||
// used internally, never sent
|
||||
NDOF_BUTTON_NONE = NDOF_MOTION,
|
||||
// these two are available from any 3Dconnexion device
|
||||
NDOF_BUTTON_MENU,
|
||||
NDOF_BUTTON_FIT,
|
||||
// standard views
|
||||
NDOF_BUTTON_TOP,
|
||||
NDOF_BUTTON_BOTTOM,
|
||||
NDOF_BUTTON_LEFT,
|
||||
NDOF_BUTTON_RIGHT,
|
||||
NDOF_BUTTON_FRONT,
|
||||
NDOF_BUTTON_BACK,
|
||||
// more views
|
||||
NDOF_BUTTON_ISO1,
|
||||
NDOF_BUTTON_ISO2,
|
||||
// 90 degree rotations
|
||||
NDOF_BUTTON_ROLL_CW,
|
||||
NDOF_BUTTON_ROLL_CCW,
|
||||
NDOF_BUTTON_SPIN_CW,
|
||||
NDOF_BUTTON_SPIN_CCW,
|
||||
NDOF_BUTTON_TILT_CW,
|
||||
NDOF_BUTTON_TILT_CCW,
|
||||
// device control
|
||||
NDOF_BUTTON_ROTATE,
|
||||
NDOF_BUTTON_PANZOOM,
|
||||
NDOF_BUTTON_DOMINANT,
|
||||
NDOF_BUTTON_PLUS,
|
||||
NDOF_BUTTON_MINUS,
|
||||
// general-purpose buttons
|
||||
NDOF_BUTTON_1,
|
||||
NDOF_BUTTON_2,
|
||||
NDOF_BUTTON_3,
|
||||
NDOF_BUTTON_4,
|
||||
NDOF_BUTTON_5,
|
||||
NDOF_BUTTON_6,
|
||||
NDOF_BUTTON_7,
|
||||
NDOF_BUTTON_8,
|
||||
NDOF_BUTTON_9,
|
||||
NDOF_BUTTON_10,
|
||||
NDOF_LAST
|
||||
};
|
||||
|
||||
|
||||
/* SYSTEM : 0x01xx */
|
||||
#define INPUTCHANGE 0x0103 /* input connected or disconnected */
|
||||
#define WINDEACTIVATE 0x0104 /* window is deactivated, focus lost */
|
||||
@ -240,8 +291,11 @@
|
||||
/* test whether the event is tweak event */
|
||||
#define ISTWEAK(event) (event >= EVT_TWEAK_L && event <= EVT_GESTURE)
|
||||
|
||||
/* test whether the event is a NDOF event */
|
||||
#define ISNDOF(event) (event >= NDOF_MOTION && event < NDOF_LAST)
|
||||
|
||||
/* test whether event type is acceptable as hotkey, excluding modifiers */
|
||||
#define ISHOTKEY(event) ((ISKEYBOARD(event) || ISMOUSE(event)) && event!=ESCKEY && !(event>=LEFTCTRLKEY && event<=LEFTSHIFTKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY))
|
||||
#define ISHOTKEY(event) ((ISKEYBOARD(event) || ISMOUSE(event) || ISNDOF(event)) && event!=ESCKEY && !(event>=LEFTCTRLKEY && event<=LEFTSHIFTKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY))
|
||||
|
||||
/* **************** BLENDER GESTURE EVENTS (0x5000) **************** */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user