Skip to content

Commit c1f1c7c

Browse files
committed
Add a platform abstraction for 6-DOF input devices.
This commit mostly just moves code around.
1 parent 6b5db58 commit c1f1c7c

File tree

14 files changed

+400
-315
lines changed

14 files changed

+400
-315
lines changed

CMakeLists.txt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,11 +158,8 @@ if(WIN32 OR APPLE)
158158
else()
159159
# On Linux and BSDs we're a good citizen and link to system libraries.
160160

161-
find_package(PkgConfig REQUIRED)
162-
163161
find_package(Backtrace)
164-
find_package(SpaceWare)
165-
162+
find_package(PkgConfig REQUIRED)
166163
find_package(ZLIB REQUIRED)
167164
find_package(PNG REQUIRED)
168165
find_package(Freetype REQUIRED)
@@ -202,6 +199,7 @@ if(ENABLE_GUI)
202199
find_library(APPKIT_LIBRARY AppKit REQUIRED)
203200
else()
204201
find_package(OpenGL REQUIRED)
202+
find_package(SpaceWare)
205203
pkg_check_modules(FONTCONFIG REQUIRED fontconfig)
206204
pkg_check_modules(JSONC REQUIRED json-c)
207205
pkg_check_modules(GTKMM REQUIRED gtkmm-3.0>=3.18 pangomm-1.4 x11)

cmake/FindSpaceWare.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#
55
# SPACEWARE_INCLUDE_DIR - header location
66
# SPACEWARE_LIBRARIES - library to link against
7-
# SPACEWARE_FOUND - true if pugixml was found.
7+
# SPACEWARE_FOUND - true if libspnav was found.
88

99
if(UNIX)
1010

src/graphicswin.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ void GraphicsWindow::Init() {
405405
window->onRender = std::bind(&GraphicsWindow::Paint, this);
406406
window->onKeyboardEvent = std::bind(&GraphicsWindow::KeyboardEvent, this, _1);
407407
window->onMouseEvent = std::bind(&GraphicsWindow::MouseEvent, this, _1);
408+
window->onSixDofEvent = std::bind(&GraphicsWindow::SixDofEvent, this, _1);
408409
window->onEditingDone = std::bind(&GraphicsWindow::EditControlDone, this, _1);
409410
window->SetMinContentSize(720, 670);
410411
PopulateMainMenu();

src/mouse.cpp

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,15 +1495,18 @@ void GraphicsWindow::MouseLeave() {
14951495
SS.extraLine.draw = false;
14961496
}
14971497

1498-
void GraphicsWindow::SpaceNavigatorMoved(double tx, double ty, double tz,
1499-
double rx, double ry, double rz,
1500-
bool shiftDown)
1501-
{
1498+
void GraphicsWindow::SixDofEvent(Platform::SixDofEvent event) {
1499+
if(event.type == Platform::SixDofEvent::Type::RELEASE) {
1500+
ZoomToFit(/*includingInvisibles=*/false, /*useSelection=*/true);
1501+
Invalidate();
1502+
return;
1503+
}
1504+
15021505
if(!havePainted) return;
15031506
Vector out = projRight.Cross(projUp);
15041507

15051508
// rotation vector is axis of rotation, and its magnitude is angle
1506-
Vector aa = Vector::From(rx, ry, rz);
1509+
Vector aa = Vector::From(event.rotationX, event.rotationY, event.rotationZ);
15071510
// but it's given with respect to screen projection frame
15081511
aa = aa.ScaleOutOfCsys(projRight, projUp, out);
15091512
double aam = aa.Magnitude();
@@ -1516,38 +1519,38 @@ void GraphicsWindow::SpaceNavigatorMoved(double tx, double ty, double tz,
15161519
if(gs.points == 1 && gs.n == 1) e = SK.GetEntity(gs.point [0]);
15171520
if(gs.entities == 1 && gs.n == 1) e = SK.GetEntity(gs.entity[0]);
15181521
if(e) g = SK.GetGroup(e->group);
1519-
if(g && g->type == Group::Type::LINKED && !shiftDown) {
1522+
if(g && g->type == Group::Type::LINKED && !event.shiftDown) {
15201523
// Apply the transformation to a linked part. Gain down the Z
15211524
// axis, since it's hard to see what you're doing on that one since
15221525
// it's normal to the screen.
1523-
Vector t = projRight.ScaledBy(tx/scale).Plus(
1524-
projUp .ScaledBy(ty/scale).Plus(
1525-
out .ScaledBy(0.1*tz/scale)));
1526+
Vector t = projRight.ScaledBy(event.translationX/scale).Plus(
1527+
projUp .ScaledBy(event.translationY/scale).Plus(
1528+
out .ScaledBy(0.1*event.translationZ/scale)));
15261529
Quaternion q = Quaternion::From(aa, aam);
15271530

15281531
// If we go five seconds without SpaceNavigator input, or if we've
15291532
// switched groups, then consider that a new action and save an undo
15301533
// point.
15311534
int64_t now = GetMilliseconds();
1532-
if(now - lastSpaceNavigatorTime > 5000 ||
1533-
lastSpaceNavigatorGroup.v != g->h.v)
1535+
if(now - last6DofTime > 5000 ||
1536+
last6DofGroup.v != g->h.v)
15341537
{
15351538
SS.UndoRemember();
15361539
}
15371540

15381541
g->TransformImportedBy(t, q);
15391542

1540-
lastSpaceNavigatorTime = now;
1541-
lastSpaceNavigatorGroup = g->h;
1543+
last6DofTime = now;
1544+
last6DofGroup = g->h;
15421545
SS.MarkGroupDirty(g->h);
15431546
} else {
15441547
// Apply the transformation to the view of the everything. The
15451548
// x and y components are translation; but z component is scale,
15461549
// not translation, or else it would do nothing in a parallel
15471550
// projection
1548-
offset = offset.Plus(projRight.ScaledBy(tx/scale));
1549-
offset = offset.Plus(projUp.ScaledBy(ty/scale));
1550-
scale *= exp(0.001*tz);
1551+
offset = offset.Plus(projRight.ScaledBy(event.translationX/scale));
1552+
offset = offset.Plus(projUp.ScaledBy(event.translationY/scale));
1553+
scale *= exp(0.001*event.translationZ);
15511554

15521555
if(aam > 0.0) {
15531556
projRight = projRight.RotatedAbout(aa, -aam);
@@ -1559,9 +1562,3 @@ void GraphicsWindow::SpaceNavigatorMoved(double tx, double ty, double tz,
15591562
havePainted = false;
15601563
Invalidate();
15611564
}
1562-
1563-
void GraphicsWindow::SpaceNavigatorButtonUp() {
1564-
ZoomToFit(/*includingInvisibles=*/false, /*useSelection=*/true);
1565-
Invalidate();
1566-
}
1567-

src/platform/cocoamain.mm

Lines changed: 2 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -63,154 +63,6 @@ - (void)applicationTerminatePrompt {
6363
}
6464
@end
6565

66-
/*
67-
* Normally we would just link to the 3DconnexionClient framework.
68-
* We don't want to (are not allowed to) distribute the official
69-
* framework, so we're trying to use the one installed on the users
70-
* computer. There are some different versions of the framework,
71-
* the official one and re-implementations using an open source driver
72-
* for older devices (spacenav-plus). So weak-linking isn't an option,
73-
* either. The only remaining way is using CFBundle to dynamically
74-
* load the library at runtime, and also detect its availability.
75-
*
76-
* We're also defining everything needed from the 3DconnexionClientAPI,
77-
* so we're not depending on the API headers.
78-
*/
79-
80-
#pragma pack(push,2)
81-
82-
enum {
83-
kConnexionClientModeTakeOver = 1,
84-
kConnexionClientModePlugin = 2
85-
};
86-
87-
#define kConnexionMsgDeviceState '3dSR'
88-
#define kConnexionMaskButtons 0x00FF
89-
#define kConnexionMaskAxis 0x3F00
90-
91-
typedef struct {
92-
uint16_t version;
93-
uint16_t client;
94-
uint16_t command;
95-
int16_t param;
96-
int32_t value;
97-
UInt64 time;
98-
uint8_t report[8];
99-
uint16_t buttons8;
100-
int16_t axis[6];
101-
uint16_t address;
102-
uint32_t buttons;
103-
} ConnexionDeviceState, *ConnexionDeviceStatePtr;
104-
105-
#pragma pack(pop)
106-
107-
typedef void (*ConnexionAddedHandlerProc)(io_connect_t);
108-
typedef void (*ConnexionRemovedHandlerProc)(io_connect_t);
109-
typedef void (*ConnexionMessageHandlerProc)(io_connect_t, natural_t, void *);
110-
111-
typedef OSErr (*InstallConnexionHandlersProc)(ConnexionMessageHandlerProc, ConnexionAddedHandlerProc, ConnexionRemovedHandlerProc);
112-
typedef void (*CleanupConnexionHandlersProc)(void);
113-
typedef UInt16 (*RegisterConnexionClientProc)(UInt32, UInt8 *, UInt16, UInt32);
114-
typedef void (*UnregisterConnexionClientProc)(UInt16);
115-
116-
static BOOL connexionShiftIsDown = NO;
117-
static UInt16 connexionClient = 0;
118-
static UInt32 connexionSignature = 'SoSp';
119-
static UInt8 *connexionName = (UInt8 *)"\x10SolveSpace";
120-
static CFBundleRef spaceBundle = NULL;
121-
static InstallConnexionHandlersProc installConnexionHandlers = NULL;
122-
static CleanupConnexionHandlersProc cleanupConnexionHandlers = NULL;
123-
static RegisterConnexionClientProc registerConnexionClient = NULL;
124-
static UnregisterConnexionClientProc unregisterConnexionClient = NULL;
125-
126-
static void connexionAdded(io_connect_t con) {}
127-
static void connexionRemoved(io_connect_t con) {}
128-
static void connexionMessage(io_connect_t con, natural_t type, void *arg) {
129-
if (type != kConnexionMsgDeviceState) {
130-
return;
131-
}
132-
133-
ConnexionDeviceState *device = (ConnexionDeviceState *)arg;
134-
135-
dispatch_async(dispatch_get_main_queue(), ^(void){
136-
SolveSpace::SS.GW.SpaceNavigatorMoved(
137-
(double)device->axis[0] * -0.25,
138-
(double)device->axis[1] * -0.25,
139-
(double)device->axis[2] * 0.25,
140-
(double)device->axis[3] * -0.0005,
141-
(double)device->axis[4] * -0.0005,
142-
(double)device->axis[5] * -0.0005,
143-
(connexionShiftIsDown == YES) ? 1 : 0
144-
);
145-
});
146-
}
147-
148-
static void connexionInit() {
149-
NSString *bundlePath = @"/Library/Frameworks/3DconnexionClient.framework";
150-
NSURL *bundleURL = [NSURL fileURLWithPath:bundlePath];
151-
spaceBundle = CFBundleCreate(kCFAllocatorDefault, (__bridge CFURLRef)bundleURL);
152-
153-
// Don't continue if no Spacemouse driver is installed on this machine
154-
if (spaceBundle == NULL) {
155-
return;
156-
}
157-
158-
installConnexionHandlers = (InstallConnexionHandlersProc)
159-
CFBundleGetFunctionPointerForName(spaceBundle,
160-
CFSTR("InstallConnexionHandlers"));
161-
162-
cleanupConnexionHandlers = (CleanupConnexionHandlersProc)
163-
CFBundleGetFunctionPointerForName(spaceBundle,
164-
CFSTR("CleanupConnexionHandlers"));
165-
166-
registerConnexionClient = (RegisterConnexionClientProc)
167-
CFBundleGetFunctionPointerForName(spaceBundle,
168-
CFSTR("RegisterConnexionClient"));
169-
170-
unregisterConnexionClient = (UnregisterConnexionClientProc)
171-
CFBundleGetFunctionPointerForName(spaceBundle,
172-
CFSTR("UnregisterConnexionClient"));
173-
174-
// Only continue if all required symbols have been loaded
175-
if ((installConnexionHandlers == NULL) || (cleanupConnexionHandlers == NULL)
176-
|| (registerConnexionClient == NULL) || (unregisterConnexionClient == NULL)) {
177-
CFRelease(spaceBundle);
178-
spaceBundle = NULL;
179-
return;
180-
}
181-
182-
installConnexionHandlers(&connexionMessage, &connexionAdded, &connexionRemoved);
183-
connexionClient = registerConnexionClient(connexionSignature, connexionName,
184-
kConnexionClientModeTakeOver, kConnexionMaskButtons | kConnexionMaskAxis);
185-
186-
// Monitor modifier flags to detect Shift button state changes
187-
[NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyDownMask | NSFlagsChangedMask)
188-
handler:^(NSEvent *event) {
189-
if (event.modifierFlags & NSShiftKeyMask) {
190-
connexionShiftIsDown = YES;
191-
}
192-
return event;
193-
}];
194-
195-
[NSEvent addLocalMonitorForEventsMatchingMask:(NSKeyUpMask | NSFlagsChangedMask)
196-
handler:^(NSEvent *event) {
197-
if (!(event.modifierFlags & NSShiftKeyMask)) {
198-
connexionShiftIsDown = NO;
199-
}
200-
return event;
201-
}];
202-
}
203-
204-
static void connexionClose() {
205-
if (spaceBundle == NULL) {
206-
return;
207-
}
208-
209-
unregisterConnexionClient(connexionClient);
210-
cleanupConnexionHandlers();
211-
212-
CFRelease(spaceBundle);
213-
}
21466

21567
int main(int argc, const char *argv[]) {
21668
ApplicationDelegate *delegate = [[ApplicationDelegate alloc] init];
@@ -226,12 +78,12 @@ int main(int argc, const char *argv[]) {
22678
SolveSpace::SetLocale("en_US");
22779
}
22880

229-
connexionInit();
81+
SolveSpace::Platform::Open3DConnexion();
23082
SolveSpace::SS.Init();
23183

23284
[NSApp run];
23385

234-
connexionClose();
86+
SolveSpace::Platform::Close3DConnexion();
23587
SolveSpace::SK.Clear();
23688
SolveSpace::SS.Clear();
23789

src/platform/gtkmain.cpp

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@
4747
#include "solvespace.h"
4848
#include "config.h"
4949

50-
#ifdef HAVE_SPACEWARE
51-
#include <spnav.h>
52-
#endif
53-
5450
namespace SolveSpace {
5551

5652
void OpenWebsite(const char *url) {
@@ -78,40 +74,6 @@ std::vector<Platform::Path> GetFontFiles() {
7874
return fonts;
7975
}
8076

81-
82-
/* Space Navigator support */
83-
84-
#ifdef HAVE_SPACEWARE
85-
static GdkFilterReturn GdkSpnavFilter(GdkXEvent *gxevent, GdkEvent *, gpointer) {
86-
XEvent *xevent = (XEvent*) gxevent;
87-
88-
spnav_event sev;
89-
if(!spnav_x11_event(xevent, &sev))
90-
return GDK_FILTER_CONTINUE;
91-
92-
switch(sev.type) {
93-
case SPNAV_EVENT_MOTION:
94-
SS.GW.SpaceNavigatorMoved(
95-
(double)sev.motion.x,
96-
(double)sev.motion.y,
97-
(double)sev.motion.z * -1.0,
98-
(double)sev.motion.rx * 0.001,
99-
(double)sev.motion.ry * 0.001,
100-
(double)sev.motion.rz * -0.001,
101-
xevent->xmotion.state & ShiftMask);
102-
break;
103-
104-
case SPNAV_EVENT_BUTTON:
105-
if(!sev.button.press && sev.button.bnum == 0) {
106-
SS.GW.SpaceNavigatorButtonUp();
107-
}
108-
break;
109-
}
110-
111-
return GDK_FILTER_REMOVE;
112-
}
113-
#endif
114-
11577
};
11678

11779
int main(int argc, char** argv) {
@@ -149,10 +111,6 @@ int main(int argc, char** argv) {
149111
style_provider,
150112
600 /*Gtk::STYLE_PROVIDER_PRIORITY_APPLICATION*/);
151113

152-
#ifdef HAVE_SPACEWARE
153-
gdk_window_add_filter(NULL, GdkSpnavFilter, NULL);
154-
#endif
155-
156114
const char* const* langNames = g_get_language_names();
157115
while(*langNames) {
158116
if(SetLocale(*langNames++)) break;
@@ -163,15 +121,6 @@ int main(int argc, char** argv) {
163121

164122
SS.Init();
165123

166-
#if defined(HAVE_SPACEWARE) && defined(GDK_WINDOWING_X11)
167-
if(GDK_IS_X11_DISPLAY(Gdk::Display::get_default()->gobj())) {
168-
// We don't care if it can't be opened; just continue without.
169-
spnav_x11_open(gdk_x11_get_default_xdisplay(),
170-
gdk_x11_window_get_xid(((Gtk::Window *)SS.GW.window->NativePtr())
171-
->get_window()->gobj()));
172-
}
173-
#endif
174-
175124
if(argc >= 2) {
176125
if(argc > 2) {
177126
dbp("Only the first file passed on command line will be opened.");

0 commit comments

Comments
 (0)