Fix redundant glTexEnv calls
[neverball] / share / tilt_loop.c
1 /*
2  * Copyright (C) 2010 Neverball authors
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <SDL.h>
16 #include <SDL_thread.h>
17 #include <math.h>
18 #include <stdio.h>
19
20 #include "config.h"
21
22 /*---------------------------------------------------------------------------*/
23
24 /* FIXME: I did not copy paste this from tilt_wii.c, I swear! */
25
26 /*
27  * This data structure tracks button changes, counting transitions so that
28  * none are missed if the event handling thread falls significantly behind
29  * the device IO thread.
30  */
31
32 #define BUTTON_NC 0
33 #define BUTTON_DN 1
34 #define BUTTON_UP 2
35
36 struct button_state
37 {
38     unsigned char curr;
39     unsigned char last;
40     unsigned char upc;
41     unsigned char dnc;
42 };
43
44 static void set_button(struct button_state *B, int s)
45 {
46     if ((B->curr == 0) != (s == 0))
47     {
48         if (B->curr)
49         {
50             B->upc++;
51             B->curr = 0;
52         }
53         else
54         {
55             B->dnc++;
56             B->curr = 1;
57         }
58     }
59 }
60
61 static int get_button(struct button_state *B)
62 {
63     int ch = BUTTON_NC;
64
65     if      (B->last == 1 && B->upc > 0)
66     {
67         B->upc--;
68         B->last = 0;
69         ch = BUTTON_UP;
70     }
71     else if (B->last == 0 && B->dnc > 0)
72     {
73         B->dnc--;
74         B->last = 1;
75         ch = BUTTON_DN;
76     }
77
78     return ch;
79 }
80
81 /*---------------------------------------------------------------------------*/
82
83 struct tilt_state
84 {
85     int   status;
86     float x;
87     float z;
88     struct button_state A;
89     struct button_state B;
90     struct button_state plus;
91     struct button_state minus;
92     struct button_state home;
93     struct button_state L;
94     struct button_state R;
95     struct button_state U;
96     struct button_state D;
97 };
98
99 static struct tilt_state state;
100 static SDL_mutex        *mutex  = NULL;
101 static SDL_Thread       *thread = NULL;
102
103 /*---------------------------------------------------------------------------*/
104
105 #include "freespace/freespace.h"
106 #include "freespace/freespace_codecs.h"
107 #include "vec3.h"
108
109 #define FILTER 8
110 #define DAMPENING 1
111
112 static int tilt_func(void *data)
113 {
114     FreespaceDeviceId deviceId;
115     uint8_t buffer[FREESPACE_MAX_OUTPUT_MESSAGE_SIZE];
116     int rc;
117     float x, y, z;
118     struct freespace_DataMotionControl d;
119     struct freespace_UserFrame userFrame;
120     int running = 1;
121     int length;
122     int numIds;
123
124     float quat[4];
125     float eulerAngles[3];
126
127
128     rc = freespace_getDeviceList(&deviceId, 1, &numIds);
129     if (numIds == 0) {
130         return 1;
131     }
132
133     rc = freespace_openDevice(deviceId);
134     if (rc != FREESPACE_SUCCESS) {
135         return 1;
136     }
137
138     rc = freespace_flush(deviceId);
139     if (rc != FREESPACE_SUCCESS) {
140         return 1;
141     }
142
143     d.enableBodyMotion = 0;
144     d.enableUserPosition = 1;
145     d.inhibitPowerManager = 0;
146     d.enableMouseMovement = 1;
147     d.disableFreespace = 0;
148     rc = freespace_encodeDataMotionControl(&d, buffer, sizeof(buffer));
149     if (rc > 0) {
150         rc = freespace_send(deviceId, buffer, rc);
151         if (rc != FREESPACE_SUCCESS) {
152             return 1;
153         }
154     }
155
156
157     SDL_mutexP(mutex);
158     state.status = running;
159     SDL_mutexV(mutex);
160
161     while (mutex && running)
162     {
163         SDL_mutexP(mutex);
164         running = state.status;
165         SDL_mutexV(mutex);
166
167         rc = freespace_read(deviceId, buffer, FREESPACE_MAX_INPUT_MESSAGE_SIZE, 100, &length);
168         if (rc != FREESPACE_SUCCESS) {
169             continue;
170         }
171
172         if (length == 0) {
173             continue;
174         }
175
176         if (freespace_decodeUserFrame(buffer, length, &userFrame) == FREESPACE_SUCCESS) {
177             /* Hillcrest quaternion is rotate the world type, so make it rotate the object type by conjugating*/
178             quat[0] = userFrame.angularPosA;
179             quat[1] = -userFrame.angularPosB;
180             quat[2] = -userFrame.angularPosC;
181             quat[3] = -userFrame.angularPosD;
182             q_nrm(quat, quat);
183
184             /* This function does euler decomposition for rotate the object type (ZYX, aerospace) */
185             q_euler(eulerAngles, quat);
186
187             SDL_mutexP(mutex);
188             {
189                 /* Since the game expects "rotate the world type", conjugate by negating all angles & convert to degrees
190                  * Z is yaw
191                  * Y is pitch
192                  * X is roll */
193                 z = -eulerAngles[0] * 57.2957795;
194                 y = -eulerAngles[1] * 57.2957795;
195                 x = -eulerAngles[2] * 57.2957795;
196
197                 state.x = y * DAMPENING;
198                 state.z = -x * DAMPENING;
199
200                 set_button(&state.home, userFrame.button3);
201                 set_button(&state.U, userFrame.deltaWheel > 0);
202                 set_button(&state.D, userFrame.deltaWheel < 0);
203             }
204             SDL_mutexV(mutex);
205         }
206
207     }
208
209     freespace_closeDevice(deviceId);
210     return 0;
211 }
212
213 void tilt_init(void)
214 {
215     memset(&state, 0, sizeof (struct tilt_state));
216
217     freespace_init();
218
219     mutex  = SDL_CreateMutex();
220     thread = SDL_CreateThread(tilt_func, NULL);
221 }
222
223 void tilt_free(void)
224 {
225     int b = 0;
226
227     if (mutex)
228     {
229         /* Get/set the status of the tilt sensor thread. */
230
231         SDL_mutexP(mutex);
232         b = state.status;
233         state.status = 0;
234         SDL_mutexV(mutex);
235
236         /* Kill the thread and destroy the mutex. */
237
238         SDL_WaitThread(thread, &b);
239         SDL_DestroyMutex(mutex);
240
241         mutex  = NULL;
242         thread = NULL;
243
244         freespace_exit();
245     }
246 }
247
248 int tilt_get_button(int *b, int *s)
249 {
250     int ch = BUTTON_NC;
251
252     if (mutex)
253     {
254         SDL_mutexP(mutex);
255         {
256             if      ((ch = get_button(&state.A)))
257             {
258                 *b = config_get_d(CONFIG_JOYSTICK_BUTTON_A);
259                 *s = (ch == BUTTON_DN);
260             }
261             else if ((ch = get_button(&state.B)))
262             {
263                 *b = config_get_d(CONFIG_JOYSTICK_BUTTON_B);
264                 *s = (ch == BUTTON_DN);
265             }
266             else if ((ch = get_button(&state.home)))
267             {
268                 *b = config_get_d(CONFIG_JOYSTICK_BUTTON_EXIT);
269                 *s = (ch == BUTTON_DN);
270             }
271             else if ((ch = get_button(&state.U)))
272             {
273                 *b = config_get_d(CONFIG_JOYSTICK_DPAD_U);
274                 *s = (ch == BUTTON_DN);
275             }
276             else if ((ch = get_button(&state.D)))
277             {
278                 *b = config_get_d(CONFIG_JOYSTICK_DPAD_D);
279                 *s = (ch == BUTTON_DN);
280             }
281         }
282         SDL_mutexV(mutex);
283     }
284     return ch;
285 }
286
287 float tilt_get_x(void)
288 {
289     float x = 0.0f;
290
291     if (mutex)
292     {
293         SDL_mutexP(mutex);
294         x = state.x;
295         SDL_mutexV(mutex);
296     }
297
298     return x;
299 }
300
301 float tilt_get_z(void)
302 {
303     float z = 0.0f;
304
305     if (mutex)
306     {
307         SDL_mutexP(mutex);
308         z = state.z;
309         SDL_mutexV(mutex);
310     }
311
312     return z;
313 }
314
315 int tilt_stat(void)
316 {
317     int b = 0;
318
319     if (mutex)
320     {
321         SDL_mutexP(mutex);
322         b = state.status;
323         SDL_mutexV(mutex);
324     }
325     return b;
326 }
327
328 /*---------------------------------------------------------------------------*/