Mercurial > sdl-ios-xcode
comparison src/haptic/win32/SDL_syshaptic.c @ 2551:f010e1d4e431 gsoc2008_force_feedback
First version of the windows haptic port, won't compile yet.
author | Edgar Simo <bobbens@gmail.com> |
---|---|
date | Wed, 30 Jul 2008 11:54:08 +0000 |
parents | |
children | 3696b9ce8a37 |
comparison
equal
deleted
inserted
replaced
2550:b5b8a7f4a965 | 2551:f010e1d4e431 |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 2008 Edgar Simo | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Lesser General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2.1 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Lesser General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Lesser General Public | |
16 License along with this library; if not, write to the Free Software | |
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | |
19 Sam Lantinga | |
20 slouken@libsdl.org | |
21 */ | |
22 #include "SDL_config.h" | |
23 | |
24 #ifdef SDL_HAPTIC_DINPUT | |
25 | |
26 #include "SDL_haptic.h" | |
27 #include "../SDL_syshaptic.h" | |
28 #include "SDL_joystick.h" | |
29 #include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */ | |
30 /*#include "../../joystick/win32/SDL_sysjoystick_c.h"*/ /* For joystick hwdata */ | |
31 | |
32 #define WIN32_LEAN_AND_MEAN | |
33 #include <windows.h> | |
34 | |
35 #define DIRECTINPUT_VERSION 0x0500 | |
36 #include <dinput.h> | |
37 #include <dxerr9.h> /* From DirectX SDK 9c */ | |
38 #ifdef _MSC_VER | |
39 # pragma comment (lib, "dxerr9.lib") | |
40 #endif /* _MSC_VER */ | |
41 | |
42 /* an ISO hack for VisualC++ */ | |
43 #ifdef _MSC_VER | |
44 #define snprintf _snprintf | |
45 #endif /* _MSC_VER */ | |
46 | |
47 | |
48 #define MAX_HAPTICS 32 | |
49 | |
50 | |
51 /* | |
52 * List of available haptic devices. | |
53 */ | |
54 static struct | |
55 { | |
56 DIDEVICEINSTANCE instance; | |
57 SDL_Haptic *haptic; | |
58 } SDL_hapticlist[MAX_HAPTICS]; | |
59 | |
60 | |
61 /* | |
62 * Haptic system hardware data. | |
63 */ | |
64 struct haptic_hwdata | |
65 { | |
66 LPDIRECTINPUTDEVICE2 device; | |
67 DIDEVCAPS capabilities; | |
68 }; | |
69 | |
70 | |
71 /* | |
72 * Haptic system effect data. | |
73 */ | |
74 struct haptic_hweffect | |
75 { | |
76 DIEFFECT effect; | |
77 }; | |
78 | |
79 | |
80 /* | |
81 * Internal stuff. | |
82 */ | |
83 static LPDIRECTINPUT dinput = NULL; | |
84 | |
85 | |
86 /* | |
87 * Prototypes. | |
88 */ | |
89 static BOOL CALLBACK EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext); | |
90 | |
91 | |
92 /* | |
93 * Like SDL_SetError but for DX error codes. | |
94 */ | |
95 static void | |
96 DI_SetError(const char *str, HRESULT err) | |
97 { | |
98 SDL_SetError( "Haptic: %s - %s: %s", str, | |
99 DXGetErrorString9(err), | |
100 DXGetErrorDescription9(err)); | |
101 } | |
102 | |
103 | |
104 /* | |
105 * Initializes the haptic subsystem. | |
106 */ | |
107 int | |
108 SDL_SYS_HapticInit(void) | |
109 { | |
110 HRESULT ret; | |
111 | |
112 if (dinput != NULL) { /* Already open. */ | |
113 SDL_SetError("Haptic: SubSystem already open."); | |
114 return -1; | |
115 } | |
116 | |
117 /* Clear all the memory. */ | |
118 SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist)); | |
119 | |
120 SDL_numhaptics = 0; | |
121 | |
122 ret = CoInitialize(NULL); | |
123 if (FAILED(ret)) { | |
124 DI_SetError("Coinitialize",ret); | |
125 return -1; | |
126 } | |
127 | |
128 ret = CoCreateInstance(&CLSID_DirectInput, NULL, CLSCTX_INPROC_SERVER, | |
129 &IID_IDirectInput, &dinput); | |
130 if (FAILED(ret)) { | |
131 DI_SetError("CoCreateInstance",ret); | |
132 return -1; | |
133 } | |
134 | |
135 /* Because we used CoCreateInstance, we need to Initialize it, first. */ | |
136 ret = IDirectInput_Initialize(dinput, SDL_Instance, DIRECTINPUT_VERSION); | |
137 if (FAILED(ret)) { | |
138 DI_SetError("Initializing DirectInput device",ret); | |
139 return -1; | |
140 } | |
141 | |
142 /* Look for haptic devices. */ | |
143 ret = IDirectInput_EnumDevices( dinput, | |
144 DIDEVTYPE_ALL, | |
145 EnumJoysticksCallback, | |
146 NULL, DIEDFL_FORCEFEEDBACK | DIEDFL_ATTACHEDONLY); | |
147 if (FAILED(ret)) { | |
148 DI_SetError("Enumerating DirectInput devices",ret); | |
149 return -1; | |
150 } | |
151 | |
152 return SDL_numhaptics; | |
153 } | |
154 | |
155 /* | |
156 * Callback to find the haptic devices. | |
157 */ | |
158 static BOOL CALLBACK | |
159 EnumHapticsCallback(const DIDEVICEINSTANCE * pdidInstance, VOID * pContext) | |
160 { | |
161 memcpy(&SDL_hapticlist[SDL_numhaptics].instance, pdidInstance, | |
162 sizeof(DIDEVICEINSTANCE)); | |
163 SDL_numhaptics++; | |
164 | |
165 if (SDL_numhaptics >= MAX_HAPTICS) | |
166 return DIENUM_STOP; | |
167 | |
168 return DIENUM_CONTINUE; | |
169 } | |
170 | |
171 | |
172 /* | |
173 * Return the name of a haptic device, does not need to be opened. | |
174 */ | |
175 const char * | |
176 SDL_SYS_HapticName(int index) | |
177 { | |
178 return SDL_hapticlist[index].instance.tszProductName; | |
179 } | |
180 | |
181 | |
182 /* | |
183 * Callback to get all supported effects. | |
184 */ | |
185 #define EFFECT_TEST(e,s) \ | |
186 if (pei->guid == (e)) \ | |
187 haptic->supported |= (s) | |
188 static BOOL CALLBACK | |
189 DI_EffectCallback(LPCDIEffectInfo pei, LPVOID pv) | |
190 { | |
191 /* Prepare the haptic device. */ | |
192 SDL_Haptic *haptic = (SDL_Haptic*) pv; | |
193 haptic->supported = 0; | |
194 | |
195 /* Get supported. */ | |
196 EFFECT_TEST(GUID_Spring, SDL_HAPTIC_SPRING); | |
197 EFFECT_TEST(GUID_Damper, SDL_HAPTIC_DAMPER); | |
198 EFFECT_TEST(GUID_Inertia, SDL_HAPTIC_INERTIA); | |
199 EFFECT_TEST(GUID_Friction, SDL_HAPTIC_FRICTION); | |
200 EFFECT_TEST(GUID_ConstantForce, SDL_HAPTIC_CONSTANT); | |
201 EFFECT_TEST(GUID_CustomForce, SDL_HAPTIC_CUSTOM); | |
202 EFFECT_TEST(GUID_Sine, SDL_HAPTIC_SINE); | |
203 EFFECT_TEST(GUID_Square, SDL_HAPTIC_SQUARE); | |
204 EFFECT_TEST(GUID_Triangle, SDL_HAPTIC_TRIANGLE); | |
205 EFFECT_TEST(GUID_SawtoothUp, SDL_HAPTIC_SAWTOOTHUP); | |
206 EFFECT_TEST(GUID_SawtoothDown, SDL_HAPTIC_SAWTOOTHDOWN); | |
207 EFFECT_TEST(GUID_RampForce, SDL_HAPTIC_RAMP); | |
208 | |
209 /* Check for more. */ | |
210 return DIENUM_CONTINUE; | |
211 } | |
212 | |
213 | |
214 /* | |
215 * Opens the haptic device from the file descriptor. | |
216 * | |
217 * Steps: | |
218 * - Open temporary DirectInputDevice interface. | |
219 * - Create DirectInputDevice2 interface. | |
220 * - Release DirectInputDevice interface. | |
221 * - Acquire exclusiveness. | |
222 * - Reset actuators. | |
223 * - Get supported featuers. | |
224 */ | |
225 static int | |
226 SDL_SYS_HapticOpenFromInstance(SDL_Haptic * haptic, DIDEVICEINSTANCE instance) | |
227 { | |
228 HRESULT ret; | |
229 LPDIRECTINPUTDEVICE device; | |
230 DIPROPDWORD dipdw; | |
231 | |
232 /* Allocate the hwdata */ | |
233 haptic->hwdata = (struct haptic_hwdata *) | |
234 SDL_malloc(sizeof(*haptic->hwdata)); | |
235 if (haptic->hwdata == NULL) { | |
236 SDL_OutOfMemory(); | |
237 goto creat_err; | |
238 } | |
239 SDL_memset(haptic->hwdata, 0, sizeof(*haptic->hwdata)); | |
240 | |
241 /* Open the device */ | |
242 ret = IDirectInput_CreateDevice( dinput, &instance, | |
243 guidInstance, &device, NULL); | |
244 if (FAILED(ret)) { | |
245 DI_SetError("Creating DirectInput device",ret); | |
246 goto creat_err; | |
247 } | |
248 | |
249 /* Now get the IDirectInputDevice2 interface, instead. */ | |
250 ret = IDirectInputDevice_QueryInterface( device, | |
251 &IID_IDirectInputDevice2, | |
252 haptic->hwdata->device ); | |
253 /* Done with the temporary one now. */ | |
254 IDirectInputDevice_Release(device); | |
255 if (FAILED(ret)) { | |
256 DI_SetError("Querying DirectInput interface",ret); | |
257 goto creat_err; | |
258 } | |
259 | |
260 /* Acquire the device. */ | |
261 ret = IDirectInputDevice2_Acquire(haptic->hwdata->device); | |
262 if (FAILED(ret)) { | |
263 DI_SetError("Acquiring DirectInput device",ret); | |
264 goto query_err; | |
265 } | |
266 | |
267 /* Grab it exclusively to use force feedback stuff. */ | |
268 ret =IDirectInputDevice2_SetCooperativeLevel( haptic->hwdata->device, | |
269 SDL_Window, | |
270 DISCL_EXCLUSIVE | DISCL_BACKGROUND ); | |
271 if (FAILED(ret)) { | |
272 DI_SetError("Setting cooperative level to exclusive",ret); | |
273 goto acquire_err; | |
274 } | |
275 | |
276 /* Reset all actuators - just in case. */ | |
277 ret = IDirectInputDevice2_SendForceFeedbackCommand( haptic->hwdata->device, | |
278 DISFFC_RESET ); | |
279 if (FAILED(ret)) { | |
280 DI_SetError("Resetting device",ret); | |
281 goto acquire_err; | |
282 } | |
283 | |
284 | |
285 /* Enabling actuators. */ | |
286 ret = IDirectInputDevice2_SendForceFeedbackCommand( haptic->hwdata->device, | |
287 DISFFC_SETACTUATORSON ); | |
288 if (FAILED(ret)) { | |
289 DI_SetError("Enabling actuators",ret); | |
290 goto acquire_err; | |
291 } | |
292 | |
293 | |
294 /* Get capabilities. */ | |
295 ret = IDirectInputDevice2_GetCapabilities( haptic->hwdata->device, | |
296 haptic->hwdata->capabilities ); | |
297 if (FAILED(ret)) { | |
298 DI_SetError("Getting device capabilities",ret); | |
299 goto acquire_err; | |
300 } | |
301 | |
302 | |
303 /* Get supported effects. */ | |
304 ret = IDirectInput_EnumEffects( DI_EffectCallback, haptic, DIEFT_ALL); | |
305 if (FAILED(ret)) { | |
306 DI_SetError("Enumerating supported effects",ret); | |
307 goto acquire_err; | |
308 } | |
309 if (haptic->supported == 0) { /* Error since device supports nothing. */ | |
310 SDL_SetError("Haptic: Internal error on finding supported effects."); | |
311 goto acquire_err; | |
312 } | |
313 | |
314 /* Check autogain and autocenter. */ | |
315 dipdw.diph.dwSize = sizeof(DIPROPDWORD); | |
316 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); | |
317 dipdw.diph.dwObj = 0; | |
318 dipdw.diph.dwHow = DIPH_DEVICE; | |
319 dipdw.dwData = 10000; | |
320 ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device, | |
321 DIPROP_FFGAIN, &dipdw.diph ); | |
322 if (FAILED(ret)) { | |
323 if (ret != DIERR_UNSUPPORTED) { | |
324 DI_SetError("Checking gain",ret); | |
325 goto acquire_err; | |
326 } | |
327 } | |
328 else { /* Gain is supported. */ | |
329 haptic->supported |= SDL_HAPTIC_GAIN; | |
330 } | |
331 dipdw.dwData = DIPROPAUTOCENTER_OFF; | |
332 ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device, | |
333 DIPROP_AUTOCENTER, &dipdw.diph ); | |
334 if (FAILED(ret)) { | |
335 if (ret != DIERR_UNSUPPORTED) { | |
336 DI_SetError("Checking autocenter",ret); | |
337 goto acquire_err; | |
338 } | |
339 } | |
340 else { /* Autocenter is supported. */ | |
341 haptic->supported |= SDL_HAPTIC_AUTOCENTER; | |
342 } | |
343 | |
344 | |
345 /* Check maximum effects. */ | |
346 haptic->neffects = 128; /* TODO actually figure this out. */ | |
347 haptic->nplaying = 128; | |
348 | |
349 | |
350 /* Prepare effects memory. */ | |
351 haptic->effects = (struct haptic_effect *) | |
352 SDL_malloc(sizeof(struct haptic_effect) * haptic->neffects); | |
353 if (haptic->effects == NULL) { | |
354 SDL_OutOfMemory(); | |
355 goto acquire_err; | |
356 } | |
357 /* Clear the memory */ | |
358 SDL_memset(haptic->effects, 0, | |
359 sizeof(struct haptic_effect) * haptic->neffects); | |
360 | |
361 return 0; | |
362 | |
363 /* Error handling */ | |
364 open_err: | |
365 IDirectInputDevice_Release(device); | |
366 goto creat_err; | |
367 acquire_err: | |
368 IDirectInputDevice2_Unacquire(haptic->hwdata->device); | |
369 query_err: | |
370 IDirectInputDevice2_Release(haptic->hwdata->device); | |
371 creat_err: | |
372 if (haptic->hwdata != NULL) { | |
373 free(haptic->hwdata); | |
374 haptic->hwdata = NULL; | |
375 } | |
376 return -1; | |
377 | |
378 } | |
379 | |
380 | |
381 /* | |
382 * Opens a haptic device for usage. | |
383 */ | |
384 int | |
385 SDL_SYS_HapticOpen(SDL_Haptic * haptic) | |
386 { | |
387 return SDL_SYS_HapticOpenFromInstance( haptic, | |
388 SDL_hapticlist[haptic->index].instance ); | |
389 } | |
390 | |
391 | |
392 /* | |
393 * Opens a haptic device from first mouse it finds for usage. | |
394 */ | |
395 int | |
396 SDL_SYS_HapticMouse(void) | |
397 { | |
398 return -1; | |
399 } | |
400 | |
401 | |
402 /* | |
403 * Checks to see if a joystick has haptic features. | |
404 */ | |
405 int | |
406 SDL_SYS_JoystickIsHaptic(SDL_Joystick * joystick) | |
407 { | |
408 return SDL_FALSE; | |
409 } | |
410 | |
411 | |
412 /* | |
413 * Checks to see if the haptic device and joystick and in reality the same. | |
414 */ | |
415 int | |
416 SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick) | |
417 { | |
418 return 0; | |
419 } | |
420 | |
421 | |
422 /* | |
423 * Opens a SDL_Haptic from a SDL_Joystick. | |
424 */ | |
425 int | |
426 SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) | |
427 { | |
428 return -1; | |
429 } | |
430 | |
431 | |
432 /* | |
433 * Closes the haptic device. | |
434 */ | |
435 void | |
436 SDL_SYS_HapticClose(SDL_Haptic * haptic) | |
437 { | |
438 int i; | |
439 | |
440 if (haptic->hwdata) { | |
441 | |
442 /* Free the effects. */ | |
443 for (i=0; i<haptic->neffects; i++) { | |
444 if (haptic->effects[i].hweffect != NULL) { | |
445 SDL_SYS_HapticFreeFFEFFECT( &haptic->effects[i].hweffect->effect, | |
446 haptic->effects[i].effect.type ); | |
447 SDL_free(haptic->effects[i].hweffect); | |
448 } | |
449 } | |
450 SDL_free(haptic->effects); | |
451 haptic->neffects = 0; | |
452 | |
453 /* Clean up */ | |
454 IDirectInputDevice2_Unacquire(haptic->hwdata->device); | |
455 IDirectInputDevice2_Release(haptic->hwdata->device); | |
456 | |
457 /* Free */ | |
458 SDL_free(haptic->hwdata); | |
459 haptic->hwdata = NULL; | |
460 } | |
461 } | |
462 | |
463 | |
464 /* | |
465 * Clean up after system specific haptic stuff | |
466 */ | |
467 void | |
468 SDL_SYS_HapticQuit(void) | |
469 { | |
470 IDirectInput_Release(dinput); | |
471 dinput = NULL; | |
472 } | |
473 | |
474 | |
475 /* | |
476 * Sets the direction. | |
477 */ | |
478 static int | |
479 SDL_SYS_SetDirection( FFEFFECT * effect, SDL_HapticDirection *dir, int naxes ) | |
480 { | |
481 LONG *rglDir; | |
482 | |
483 /* Handle no axes a part. */ | |
484 if (naxes == 0) { | |
485 effect->rglDirection = NULL; | |
486 return 0; | |
487 } | |
488 | |
489 /* Has axes. */ | |
490 rglDir = SDL_malloc( sizeof(LONG) * naxes ); | |
491 if (rglDir == NULL) { | |
492 SDL_OutOfMemory(); | |
493 return -1; | |
494 } | |
495 SDL_memset( rglDir, 0, sizeof(LONG) * naxes ); | |
496 effect->rglDirection = rglDir; | |
497 | |
498 switch (dir->type) { | |
499 case SDL_HAPTIC_POLAR: | |
500 effect->dwFlags |= FFEFF_POLAR; | |
501 rglDir[0] = dir->dir[0]; | |
502 return 0; | |
503 case SDL_HAPTIC_CARTESIAN: | |
504 effect->dwFlags |= FFEFF_CARTESIAN; | |
505 rglDir[0] = dir->dir[0]; | |
506 rglDir[1] = dir->dir[1]; | |
507 rglDir[2] = dir->dir[2]; | |
508 return 0; | |
509 case SDL_HAPTIC_SPHERICAL: | |
510 effect->dwFlags |= FFEFF_SPHERICAL; | |
511 rglDir[0] = dir->dir[0]; | |
512 rglDir[1] = dir->dir[1]; | |
513 rglDir[2] = dir->dir[2]; | |
514 return 0; | |
515 | |
516 default: | |
517 SDL_SetError("Haptic: Unknown direction type."); | |
518 return -1; | |
519 } | |
520 } | |
521 | |
522 #define CONVERT(x) (((x)*10000) / 0xFFFF ) | |
523 /* | |
524 * Creates the FFEFFECT from a SDL_HapticEffect. | |
525 */ | |
526 static int | |
527 SDL_SYS_ToFFEFFECT( SDL_Haptic * haptic, FFEFFECT * dest, SDL_HapticEffect * src ) | |
528 { | |
529 int i; | |
530 FFCONSTANTFORCE *constant; | |
531 FFPERIODIC *periodic; | |
532 FFCONDITION *condition; /* Actually an array of conditions - one per axis. */ | |
533 FFRAMPFORCE *ramp; | |
534 FFCUSTOMFORCE *custom; | |
535 FFENVELOPE *envelope; | |
536 SDL_HapticConstant *hap_constant; | |
537 SDL_HapticPeriodic *hap_periodic; | |
538 SDL_HapticCondition *hap_condition; | |
539 SDL_HapticRamp *hap_ramp; | |
540 SDL_HapticCustom *hap_custom; | |
541 DWORD *axes; | |
542 | |
543 /* Set global stuff. */ | |
544 SDL_memset(dest, 0, sizeof(FFEFFECT)); | |
545 dest->dwSize = sizeof(FFEFFECT); /* Set the structure size. */ | |
546 dest->dwSamplePeriod = 0; /* Not used by us. */ | |
547 dest->dwGain = 10000; /* Gain is set globally, not locally. */ | |
548 | |
549 /* Envelope. */ | |
550 envelope = SDL_malloc( sizeof(FFENVELOPE) ); | |
551 if (envelope == NULL) { | |
552 SDL_OutOfMemory(); | |
553 return -1; | |
554 } | |
555 SDL_memset(envelope, 0, sizeof(FFENVELOPE)); | |
556 dest->lpEnvelope = envelope; | |
557 envelope->dwSize = sizeof(FFENVELOPE); /* Always should be this. */ | |
558 | |
559 /* Axes. */ | |
560 dest->cAxes = haptic->naxes; | |
561 if (dest->cAxes > 0) { | |
562 axes = SDL_malloc(sizeof(DWORD) * dest->cAxes); | |
563 if (axes == NULL) { | |
564 SDL_OutOfMemory(); | |
565 return -1; | |
566 } | |
567 axes[0] = FFJOFS_X; /* Always at least one axis. */ | |
568 if (dest->cAxes > 1) { | |
569 axes[1] = FFJOFS_Y; | |
570 } | |
571 if (dest->cAxes > 2) { | |
572 axes[2] = FFJOFS_Z; | |
573 } | |
574 dest->rgdwAxes = axes; | |
575 } | |
576 | |
577 | |
578 /* The big type handling switch, even bigger then linux's version. */ | |
579 switch (src->type) { | |
580 case SDL_HAPTIC_CONSTANT: | |
581 hap_constant = &src->constant; | |
582 constant = SDL_malloc( sizeof(FFCONSTANTFORCE) ); | |
583 if (constant == NULL) { | |
584 SDL_OutOfMemory(); | |
585 return -1; | |
586 } | |
587 SDL_memset(constant, 0, sizeof(FFCONSTANTFORCE)); | |
588 | |
589 /* Specifics */ | |
590 constant->lMagnitude = CONVERT(hap_constant->level); | |
591 dest->cbTypeSpecificParams = sizeof(FFCONSTANTFORCE); | |
592 dest->lpvTypeSpecificParams = constant; | |
593 | |
594 /* Generics */ | |
595 dest->dwDuration = hap_constant->length * 1000; /* In microseconds. */ | |
596 dest->dwTriggerButton = FFJOFS_BUTTON(hap_constant->button); | |
597 dest->dwTriggerRepeatInterval = hap_constant->interval; | |
598 dest->dwStartDelay = hap_constant->delay * 1000; /* In microseconds. */ | |
599 | |
600 /* Direction. */ | |
601 if (SDL_SYS_SetDirection(dest, &hap_constant->direction, dest->cAxes) < 0) { | |
602 return -1; | |
603 } | |
604 | |
605 /* Envelope */ | |
606 envelope->dwAttackLevel = CONVERT(hap_constant->attack_level); | |
607 envelope->dwAttackTime = hap_constant->attack_length * 1000; | |
608 envelope->dwFadeLevel = CONVERT(hap_constant->fade_level); | |
609 envelope->dwFadeTime = hap_constant->fade_length * 1000; | |
610 | |
611 break; | |
612 | |
613 case SDL_HAPTIC_SINE: | |
614 case SDL_HAPTIC_SQUARE: | |
615 case SDL_HAPTIC_TRIANGLE: | |
616 case SDL_HAPTIC_SAWTOOTHUP: | |
617 case SDL_HAPTIC_SAWTOOTHDOWN: | |
618 hap_periodic = &src->periodic; | |
619 periodic = SDL_malloc(sizeof(FFPERIODIC)); | |
620 if (periodic == NULL) { | |
621 SDL_OutOfMemory(); | |
622 return -1; | |
623 } | |
624 SDL_memset(periodic, 0, sizeof(FFPERIODIC)); | |
625 | |
626 /* Specifics */ | |
627 periodic->dwMagnitude = CONVERT(hap_periodic->magnitude); | |
628 periodic->lOffset = CONVERT(hap_periodic->offset); | |
629 periodic->dwPhase = hap_periodic->phase; | |
630 periodic->dwPeriod = hap_periodic->period * 1000; | |
631 dest->cbTypeSpecificParams = sizeof(FFPERIODIC); | |
632 dest->lpvTypeSpecificParams = periodic; | |
633 | |
634 /* Generics */ | |
635 dest->dwDuration = hap_periodic->length * 1000; /* In microseconds. */ | |
636 dest->dwTriggerButton = FFJOFS_BUTTON(hap_periodic->button); | |
637 dest->dwTriggerRepeatInterval = hap_periodic->interval; | |
638 dest->dwStartDelay = hap_periodic->delay * 1000; /* In microseconds. */ | |
639 | |
640 /* Direction. */ | |
641 if (SDL_SYS_SetDirection(dest, &hap_periodic->direction, dest->cAxes) < 0) { | |
642 return -1; | |
643 } | |
644 | |
645 /* Envelope */ | |
646 envelope->dwAttackLevel = CONVERT(hap_periodic->attack_level); | |
647 envelope->dwAttackTime = hap_periodic->attack_length * 1000; | |
648 envelope->dwFadeLevel = CONVERT(hap_periodic->fade_level); | |
649 envelope->dwFadeTime = hap_periodic->fade_length * 1000; | |
650 | |
651 break; | |
652 | |
653 case SDL_HAPTIC_SPRING: | |
654 case SDL_HAPTIC_DAMPER: | |
655 case SDL_HAPTIC_INERTIA: | |
656 case SDL_HAPTIC_FRICTION: | |
657 hap_condition = &src->condition; | |
658 condition = SDL_malloc(sizeof(FFCONDITION) * dest->cAxes); | |
659 if (condition == NULL) { | |
660 SDL_OutOfMemory(); | |
661 return -1; | |
662 } | |
663 SDL_memset(condition, 0, sizeof(FFCONDITION)); | |
664 | |
665 /* Specifics */ | |
666 for (i=0; i<dest->cAxes; i++) { | |
667 condition[i].lOffset = CONVERT(hap_condition->center[i]); | |
668 condition[i].lPositiveCoefficient = CONVERT(hap_condition->right_coeff[i]); | |
669 condition[i].lNegativeCoefficient = CONVERT(hap_condition->left_coeff[i]); | |
670 condition[i].dwPositiveSaturation = CONVERT(hap_condition->right_sat[i]); | |
671 condition[i].dwNegativeSaturation = CONVERT(hap_condition->left_sat[i]); | |
672 condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]); | |
673 } | |
674 dest->cbTypeSpecificParams = sizeof(FFCONDITION) * dest->cAxes; | |
675 dest->lpvTypeSpecificParams = condition; | |
676 | |
677 /* Generics */ | |
678 dest->dwDuration = hap_condition->length * 1000; /* In microseconds. */ | |
679 dest->dwTriggerButton = FFJOFS_BUTTON(hap_condition->button); | |
680 dest->dwTriggerRepeatInterval = hap_condition->interval; | |
681 dest->dwStartDelay = hap_condition->delay * 1000; /* In microseconds. */ | |
682 | |
683 /* Direction. */ | |
684 if (SDL_SYS_SetDirection(dest, &hap_condition->direction, dest->cAxes) < 0) { | |
685 return -1; | |
686 } | |
687 | |
688 /* Envelope */ | |
689 /* TODO Check is envelope actually used. | |
690 envelope->dwAttackLevel = CONVERT(hap_condition->attack_level); | |
691 envelope->dwAttackTime = hap_condition->attack_length * 1000; | |
692 envelope->dwFadeLevel = CONVERT(hap_condition->fade_level); | |
693 envelope->dwFadeTime = hap_condition->fade_length * 1000; | |
694 */ | |
695 | |
696 break; | |
697 | |
698 case SDL_HAPTIC_RAMP: | |
699 hap_ramp = &src->ramp; | |
700 ramp = SDL_malloc(sizeof(FFRAMPFORCE)); | |
701 if (ramp == NULL) { | |
702 SDL_OutOfMemory(); | |
703 return -1; | |
704 } | |
705 SDL_memset(ramp, 0, sizeof(FFRAMPFORCE)); | |
706 | |
707 /* Specifics */ | |
708 ramp->lStart = CONVERT(hap_ramp->start); | |
709 ramp->lEnd = CONVERT(hap_ramp->end); | |
710 dest->cbTypeSpecificParams = sizeof(FFRAMPFORCE); | |
711 dest->lpvTypeSpecificParams = ramp; | |
712 | |
713 /* Generics */ | |
714 dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */ | |
715 dest->dwTriggerButton = FFJOFS_BUTTON(hap_ramp->button); | |
716 dest->dwTriggerRepeatInterval = hap_ramp->interval; | |
717 dest->dwStartDelay = hap_ramp->delay * 1000; /* In microseconds. */ | |
718 | |
719 /* Direction. */ | |
720 if (SDL_SYS_SetDirection(dest, &hap_ramp->direction, dest->cAxes) < 0) { | |
721 return -1; | |
722 } | |
723 | |
724 /* Envelope */ | |
725 envelope->dwAttackLevel = CONVERT(hap_ramp->attack_level); | |
726 envelope->dwAttackTime = hap_ramp->attack_length * 1000; | |
727 envelope->dwFadeLevel = CONVERT(hap_ramp->fade_level); | |
728 envelope->dwFadeTime = hap_ramp->fade_length * 1000; | |
729 | |
730 break; | |
731 | |
732 case SDL_HAPTIC_CUSTOM: | |
733 hap_custom = &src->custom; | |
734 custom = SDL_malloc(sizeof(FFCUSTOMFORCE)); | |
735 if (custom == NULL) { | |
736 SDL_OutOfMemory(); | |
737 return -1; | |
738 } | |
739 SDL_memset(custom, 0, sizeof(FFCUSTOMFORCE)); | |
740 | |
741 /* Specifics */ | |
742 custom->cChannels = hap_custom->channels; | |
743 custom->dwSamplePeriod = hap_custom->period * 1000; | |
744 custom->cSamples = hap_custom->samples; | |
745 custom->rglForceData = SDL_malloc(sizeof(LONG)*custom->cSamples*custom->cChannels); | |
746 for (i=0; i<hap_custom->samples*hap_custom->channels; i++) { /* Copy data. */ | |
747 custom->rglForceData[i] = CONVERT(hap_custom->data[i]); | |
748 } | |
749 dest->cbTypeSpecificParams = sizeof(FFCUSTOMFORCE); | |
750 dest->lpvTypeSpecificParams = custom; | |
751 | |
752 /* Generics */ | |
753 dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */ | |
754 dest->dwTriggerButton = FFJOFS_BUTTON(hap_custom->button); | |
755 dest->dwTriggerRepeatInterval = hap_custom->interval; | |
756 dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */ | |
757 | |
758 /* Direction. */ | |
759 if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) { | |
760 return -1; | |
761 } | |
762 | |
763 /* Envelope */ | |
764 envelope->dwAttackLevel = CONVERT(hap_custom->attack_level); | |
765 envelope->dwAttackTime = hap_custom->attack_length * 1000; | |
766 envelope->dwFadeLevel = CONVERT(hap_custom->fade_level); | |
767 envelope->dwFadeTime = hap_custom->fade_length * 1000; | |
768 | |
769 break; | |
770 | |
771 | |
772 default: | |
773 SDL_SetError("Haptic: Unknown effect type."); | |
774 return -1; | |
775 } | |
776 | |
777 return 0; | |
778 } | |
779 | |
780 | |
781 /* | |
782 * Frees an FFEFFECT allocated by SDL_SYS_ToFFEFFECT. | |
783 */ | |
784 static void | |
785 SDL_SYS_HapticFreeFFEFFECT( FFEFFECT * effect, int type ) | |
786 { | |
787 FFCUSTOMFORCE *custom; | |
788 | |
789 if (effect->lpEnvelope != NULL) { | |
790 SDL_free(effect->lpEnvelope); | |
791 effect->lpEnvelope = NULL; | |
792 } | |
793 if (effect->rgdwAxes != NULL) { | |
794 SDL_free(effect->rgdwAxes); | |
795 effect->rgdwAxes = NULL; | |
796 } | |
797 if (effect->lpvTypeSpecificParams != NULL) { | |
798 if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */ | |
799 custom = (FFCUSTOMFORCE*) effect->lpvTypeSpecificParams; | |
800 SDL_free(custom->rglForceData); | |
801 custom->rglForceData = NULL; | |
802 } | |
803 SDL_free(effect->lpvTypeSpecificParams); | |
804 effect->lpvTypeSpecificParams = NULL; | |
805 } | |
806 if (effect->rglDirection != NULL) { | |
807 SDL_free(effect->rglDirection); | |
808 effect->rglDirection = NULL; | |
809 } | |
810 } | |
811 | |
812 | |
813 /* | |
814 * Gets the effect type from the generic SDL haptic effect wrapper. | |
815 */ | |
816 REFGUID | |
817 SDL_SYS_HapticEffectType(struct haptic_effect * effect) | |
818 { | |
819 switch (effect->effect.type) { | |
820 case SDL_HAPTIC_CONSTANT: | |
821 return GUID_ConstantForce; | |
822 | |
823 case SDL_HAPTIC_RAMP: | |
824 return GUID_RampForce; | |
825 | |
826 case SDL_HAPTIC_SQUARE: | |
827 return GUID_Square; | |
828 | |
829 case SDL_HAPTIC_SINE: | |
830 return GUID_Sine; | |
831 | |
832 case SDL_HAPTIC_TRIANGLE: | |
833 return GUID_Triangle; | |
834 | |
835 case SDL_HAPTIC_SAWTOOTHUP: | |
836 return GUID_SawtoothUp; | |
837 | |
838 case SDL_HAPTIC_SAWTOOTHDOWN: | |
839 return GUID_SawtoothDown; | |
840 | |
841 case SDL_HAPTIC_SPRING: | |
842 return GUID_Spring; | |
843 | |
844 case SDL_HAPTIC_DAMPER: | |
845 return GUID_Damper; | |
846 | |
847 case SDL_HAPTIC_INERTIA: | |
848 return GUID_Inertia; | |
849 | |
850 case SDL_HAPTIC_FRICTION: | |
851 return GUID_Friction; | |
852 | |
853 case SDL_HAPTIC_CUSTOM: | |
854 return GUID_CustomForce; | |
855 | |
856 default: | |
857 SDL_SetError("Haptic: Unknown effect type."); | |
858 return NULL; | |
859 } | |
860 } | |
861 | |
862 | |
863 /* | |
864 * Creates a new haptic effect. | |
865 */ | |
866 int | |
867 SDL_SYS_HapticNewEffect(SDL_Haptic * haptic, struct haptic_effect * effect, | |
868 SDL_HapticEffect * base) | |
869 { | |
870 HRESULT ret; | |
871 REFGUID type; | |
872 | |
873 /* Alloc the effect. */ | |
874 effect->hweffect = (struct haptic_hweffect *) | |
875 SDL_malloc(sizeof(struct haptic_hweffect)); | |
876 if (effect->hweffect == NULL) { | |
877 SDL_OutOfMemory(); | |
878 goto err_hweffect; | |
879 } | |
880 | |
881 /* Get the type. */ | |
882 type = SDL_SYS_HapticEffectType(effect); | |
883 if (type == NULL) { | |
884 goto err_hweffect; | |
885 } | |
886 | |
887 /* Get the effect. */ | |
888 if (SDL_SYS_ToFFEFFECT(haptic, &effect->hweffect->effect, base) < 0) { | |
889 goto err_effectdone; | |
890 } | |
891 | |
892 /* Create the actual effect. */ | |
893 ret = FFDeviceCreateEffect(haptic->hwdata->device, type, | |
894 &effect->hweffect->effect, &effect->hweffect->ref); | |
895 if (ret != FF_OK) { | |
896 SDL_SetError("Haptic: Unable to create effect: %s.", FFStrError(ret)); | |
897 goto err_effectdone; | |
898 } | |
899 | |
900 return 0; | |
901 | |
902 err_effectdone: | |
903 SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, base->type); | |
904 err_hweffect: | |
905 if (effect->hweffect != NULL) { | |
906 SDL_free(effect->hweffect); | |
907 effect->hweffect = NULL; | |
908 } | |
909 return -1; | |
910 } | |
911 | |
912 | |
913 /* | |
914 * Updates an effect. | |
915 */ | |
916 int | |
917 SDL_SYS_HapticUpdateEffect(SDL_Haptic * haptic, | |
918 struct haptic_effect * effect, SDL_HapticEffect * data) | |
919 { | |
920 HRESULT ret; | |
921 FFEffectParameterFlag flags; | |
922 FFEFFECT temp; | |
923 | |
924 /* Get the effect. */ | |
925 SDL_memset(&temp, 0, sizeof(FFEFFECT)); | |
926 if (SDL_SYS_ToFFEFFECT(haptic, &temp, data) < 0) { | |
927 goto err_update; | |
928 } | |
929 | |
930 /* Set the flags. Might be worthwhile to diff temp with loaded effect and | |
931 * only change those parameters. */ | |
932 flags = FFEP_ALLPARAMS; | |
933 | |
934 /* Create the actual effect. */ | |
935 ret = FFEffectSetParameters(effect->hweffect->ref, &temp, flags); | |
936 if (ret != FF_OK) { | |
937 SDL_SetError("Haptic: Unable to update effect: %s.", FFStrError(ret)); | |
938 goto err_update; | |
939 } | |
940 | |
941 /* Copy it over. */ | |
942 SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, data->type); | |
943 SDL_memcpy(&effect->hweffect->effect, &temp, sizeof(FFEFFECT)); | |
944 | |
945 return 0; | |
946 | |
947 err_update: | |
948 SDL_SYS_HapticFreeFFEFFECT(&temp, data->type); | |
949 return -1; | |
950 } | |
951 | |
952 | |
953 /* | |
954 * Runs an effect. | |
955 */ | |
956 int | |
957 SDL_SYS_HapticRunEffect(SDL_Haptic * haptic, struct haptic_effect * effect, | |
958 Uint32 iterations) | |
959 { | |
960 HRESULT ret; | |
961 Uint32 iter; | |
962 | |
963 /* Check if it's infinite. */ | |
964 if (iterations == SDL_HAPTIC_INFINITY) { | |
965 iter = FF_INFINITE; | |
966 } | |
967 else | |
968 iter = iterations; | |
969 | |
970 /* Run the effect. */ | |
971 ret = FFEffectStart(effect->hweffect->ref, iter, 0); | |
972 if (ret != FF_OK) { | |
973 SDL_SetError("Haptic: Unable to run the effect: %s.", FFStrError(ret)); | |
974 return -1; | |
975 } | |
976 | |
977 return 0; | |
978 } | |
979 | |
980 | |
981 /* | |
982 * Stops an effect. | |
983 */ | |
984 int | |
985 SDL_SYS_HapticStopEffect(SDL_Haptic * haptic, struct haptic_effect * effect) | |
986 { | |
987 HRESULT ret; | |
988 | |
989 ret = FFEffectStop(effect->hweffect->ref); | |
990 if (ret != FF_OK) { | |
991 SDL_SetError("Haptic: Unable to stop the effect: %s.", FFStrError(ret)); | |
992 return -1; | |
993 } | |
994 | |
995 return 0; | |
996 } | |
997 | |
998 | |
999 /* | |
1000 * Frees the effect. | |
1001 */ | |
1002 void | |
1003 SDL_SYS_HapticDestroyEffect(SDL_Haptic * haptic, struct haptic_effect * effect) | |
1004 { | |
1005 HRESULT ret; | |
1006 | |
1007 ret = FFDeviceReleaseEffect(haptic->hwdata->device, effect->hweffect->ref); | |
1008 if (ret != FF_OK) { | |
1009 SDL_SetError("Haptic: Error removing the effect from the device: %s.", | |
1010 FFStrError(ret)); | |
1011 } | |
1012 SDL_free(effect->hweffect->effect.lpvTypeSpecificParams); | |
1013 effect->hweffect->effect.lpvTypeSpecificParams = NULL; | |
1014 SDL_free(effect->hweffect); | |
1015 effect->hweffect = NULL; | |
1016 } | |
1017 | |
1018 | |
1019 /* | |
1020 * Gets the status of a haptic effect. | |
1021 */ | |
1022 int | |
1023 SDL_SYS_HapticGetEffectStatus(SDL_Haptic * haptic, struct haptic_effect * effect) | |
1024 { | |
1025 } | |
1026 | |
1027 | |
1028 /* | |
1029 * Sets the gain. | |
1030 */ | |
1031 int | |
1032 SDL_SYS_HapticSetGain(SDL_Haptic * haptic, int gain) | |
1033 { | |
1034 HRESULT ret; | |
1035 DIPROPDWORD dipdw; | |
1036 | |
1037 /* Create the weird structure thingy. */ | |
1038 dipdw.diph.dwSize = sizeof(DIPROPDWORD); | |
1039 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); | |
1040 dipdw.diph.dwObj = 0; | |
1041 dipdw.diph.dwHow = DIPH_DEVICE; | |
1042 dipdw.dwData = gain * 100; /* 0 to 10,000 */ | |
1043 | |
1044 /* Try to set the autocenter. */ | |
1045 ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device, | |
1046 DIPROP_FFGAIN, &dipdw.diph ); | |
1047 if (FAILED(ret)) { | |
1048 DI_SetError("Setting gain",ret); | |
1049 return -1; | |
1050 } | |
1051 | |
1052 return 0; | |
1053 } | |
1054 | |
1055 | |
1056 /* | |
1057 * Sets the autocentering. | |
1058 */ | |
1059 int | |
1060 SDL_SYS_HapticSetAutocenter(SDL_Haptic * haptic, int autocenter) | |
1061 { | |
1062 HRESULT ret; | |
1063 DIPROPDWORD dipdw; | |
1064 | |
1065 /* Create the weird structure thingy. */ | |
1066 dipdw.diph.dwSize = sizeof(DIPROPDWORD); | |
1067 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER); | |
1068 dipdw.diph.dwObj = 0; | |
1069 dipdw.diph.dwHow = DIPH_DEVICE; | |
1070 dipdw.dwData = (autocenter == 0) ? DIPROPAUTOCENTER_OFF : | |
1071 DIPROPAUTOCENTER_ON; | |
1072 | |
1073 /* Try to set the autocenter. */ | |
1074 ret = IDirectInputDevice2_SetProperty( haptic->hwdata->device, | |
1075 DIPROP_AUTOCENTER, &dipdw.diph ); | |
1076 if (FAILED(ret)) { | |
1077 DI_SetError("Setting autocenter",ret); | |
1078 return -1; | |
1079 } | |
1080 | |
1081 return 0; | |
1082 | |
1083 } | |
1084 | |
1085 | |
1086 #endif /* SDL_HAPTIC_DINPUT */ |