ClangFormat: apply to source, most of intern
[blender.git] / intern / ghost / intern / GHOST_NDOFManagerUnix.cpp
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16
17 #include "GHOST_NDOFManagerUnix.h"
18 #include "GHOST_System.h"
19
20 #include <spnav.h>
21 #include <stdio.h>
22 #include <unistd.h>
23
24 #define SPNAV_SOCK_PATH "/var/run/spnav.sock"
25
26 GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys)
27     : GHOST_NDOFManager(sys), m_available(false)
28 {
29   if (access(SPNAV_SOCK_PATH, F_OK) != 0) {
30 #ifdef DEBUG
31     /* annoying for official builds, just adds noise and most people don't own these */
32     puts("ndof: spacenavd not found");
33     /* This isn't a hard error, just means the user doesn't have a 3D mouse. */
34 #endif
35   }
36   else if (spnav_open() != -1) {
37     m_available = true;
38
39     /* determine exactly which device (if any) is plugged in */
40
41 #define MAX_LINE_LENGTH 100
42
43     /* look for USB devices with Logitech or 3Dconnexion's vendor ID */
44     FILE *command_output = popen("lsusb | grep '046d:\\|256f:'", "r");
45     if (command_output) {
46       char line[MAX_LINE_LENGTH] = {0};
47       while (fgets(line, MAX_LINE_LENGTH, command_output)) {
48         unsigned short vendor_id = 0, product_id = 0;
49         if (sscanf(line, "Bus %*d Device %*d: ID %hx:%hx", &vendor_id, &product_id) == 2)
50           if (setDevice(vendor_id, product_id)) {
51             break; /* stop looking once the first 3D mouse is found */
52           }
53       }
54       pclose(command_output);
55     }
56   }
57 }
58
59 GHOST_NDOFManagerUnix::~GHOST_NDOFManagerUnix()
60 {
61   if (m_available)
62     spnav_close();
63 }
64
65 bool GHOST_NDOFManagerUnix::available()
66 {
67   return m_available;
68 }
69
70 /*
71  * Workaround for a problem where we don't enter the 'GHOST_kFinished' state,
72  * this causes any proceeding event to have a very high 'dt' (time delta),
73  * many seconds for eg, causing the view to jump.
74  *
75  * this workaround expects continuous events, if we miss a motion event,
76  * immediately send a dummy event with no motion to ensure the finished state is reached.
77  */
78 #define USE_FINISH_GLITCH_WORKAROUND
79 /* TODO: make this available on all platforms */
80
81 #ifdef USE_FINISH_GLITCH_WORKAROUND
82 static bool motion_test_prev = false;
83 #endif
84
85 bool GHOST_NDOFManagerUnix::processEvents()
86 {
87   bool anyProcessed = false;
88
89   if (m_available) {
90     spnav_event e;
91
92 #ifdef USE_FINISH_GLITCH_WORKAROUND
93     bool motion_test = false;
94 #endif
95
96     while (spnav_poll_event(&e)) {
97       switch (e.type) {
98         case SPNAV_EVENT_MOTION: {
99           /* convert to blender view coords */
100           GHOST_TUns64 now = m_system.getMilliSeconds();
101           const int t[3] = {(int)e.motion.x, (int)e.motion.y, (int)-e.motion.z};
102           const int r[3] = {(int)-e.motion.rx, (int)-e.motion.ry, (int)e.motion.rz};
103
104           updateTranslation(t, now);
105           updateRotation(r, now);
106 #ifdef USE_FINISH_GLITCH_WORKAROUND
107           motion_test = true;
108 #endif
109           break;
110         }
111         case SPNAV_EVENT_BUTTON:
112           GHOST_TUns64 now = m_system.getMilliSeconds();
113           updateButton(e.button.bnum, e.button.press, now);
114           break;
115       }
116       anyProcessed = true;
117     }
118
119 #ifdef USE_FINISH_GLITCH_WORKAROUND
120     if (motion_test_prev == true && motion_test == false) {
121       GHOST_TUns64 now = m_system.getMilliSeconds();
122       const int v[3] = {0, 0, 0};
123
124       updateTranslation(v, now);
125       updateRotation(v, now);
126
127       anyProcessed = true;
128     }
129     motion_test_prev = motion_test;
130 #endif
131   }
132
133   return anyProcessed;
134 }