Added custom effect with support on darwin. gsoc2008_force_feedback
authorEdgar Simo <bobbens@gmail.com>
Sat, 19 Jul 2008 15:57:07 +0000
branchgsoc2008_force_feedback
changeset 2535 f0ed8471497d
parent 2534 e597de8dccd5
child 2536 fe3ee345a5d2
Added custom effect with support on darwin.
include/SDL_haptic.h
src/haptic/darwin/SDL_syshaptic.c
--- a/include/SDL_haptic.h	Fri Jul 18 19:22:56 2008 +0000
+++ b/include/SDL_haptic.h	Sat Jul 19 15:57:07 2008 +0000
@@ -591,6 +591,46 @@
    Uint16 fade_level; /**< Level at the end of the fade. */
 } SDL_HapticRamp;
 /**
+ * \struct SDL_HapticCustom
+ *
+ * \brief A structure containing a template for the SDL_HAPTIC_CUSTOM effect.
+ *
+ * A custom force feedback effect is much like a periodic effect, where the
+ *  application can define it's exact shape.  You will have to allocate the
+ *  data yourself.  Data should consist of channels * samples Uint16 samples.
+ *
+ * If channels is one, the effect is rotated using the defined direction.
+ *  Otherwise it uses the samples in data for the different axes.
+ *
+ * \sa SDL_HAPTIC_CUSTOM
+ * \sa SDL_HapticEffect
+ */
+typedef struct SDL_HapticCustom {
+   /* Header */
+   Uint16 type; /**< SDL_HAPTIC_CUSTOM */
+   SDL_HapticDirection direction; /**< Direction of the effect. */
+
+   /* Replay */
+   Uint32 length; /**< Duration of the effect. */
+   Uint16 delay; /**< Delay before starting the effect. */
+
+   /* Trigger */
+   Uint16 button; /**< Button that triggers the effect. */
+   Uint16 interval; /**< How soon it can be triggered again after button. */
+
+   /* Custom */
+   Uint8 channels; /**< Axes to use, minimum of one. */
+   Uint16 period; /**< Sample periods. */
+   Uint16 samples; /**< Amount of samples. */
+   Uint16 *data; /**< Should contain channels*samples items. */
+
+   /* Envelope */                                                         
+   Uint16 attack_length; /**< Duration of the attack. */
+   Uint16 attack_level; /**< Level at the start of the attack. */
+   Uint16 fade_length; /**< Duration of the fade. */
+   Uint16 fade_level; /**< Level at the end of the fade. */
+} SDL_HapticCustom;
+/**
  * \union SDL_HapticEffect
  *
  * \brief The generic template for any haptic effect.
@@ -652,6 +692,7 @@
  * \sa SDL_HapticPeriodic
  * \sa SDL_HapticCondition
  * \sa SDL_HapticRamp
+ * \sa SDL_HapticCustom
  */
 typedef union SDL_HapticEffect {
    /* Common for all force feedback effects */
@@ -660,6 +701,7 @@
    SDL_HapticPeriodic periodic; /**< Periodic effect. */
    SDL_HapticCondition condition; /**< Condition effect. */
    SDL_HapticRamp ramp; /**< Ramp effect. */
+   SDL_HapticCustom custom; /**< Custom effect. */
 } SDL_HapticEffect;
 
 
--- a/src/haptic/darwin/SDL_syshaptic.c	Fri Jul 18 19:22:56 2008 +0000
+++ b/src/haptic/darwin/SDL_syshaptic.c	Sat Jul 19 15:57:07 2008 +0000
@@ -69,7 +69,7 @@
 /*
  * Prototypes.
  */
-static void SDL_SYS_HapticFreeFFEFFECT( FFEFFECT * effect );
+static void SDL_SYS_HapticFreeFFEFFECT( FFEFFECT * effect, int type );
 
 
 /*
@@ -314,7 +314,8 @@
       /* Free the effects. */
       for (i=0; i<haptic->neffects; i++) {        
          if (haptic->effects[i].hweffect != NULL) {
-            SDL_SYS_HapticFreeFFEFFECT(&haptic->effects[i].hweffect->effect);
+            SDL_SYS_HapticFreeFFEFFECT(&haptic->effects[i].hweffect->effect,
+                                       haptic->effects[i].effect.type);
             SDL_free(haptic->effects[i].hweffect);
          } 
       }    
@@ -414,6 +415,7 @@
    SDL_HapticPeriodic *hap_periodic;
    SDL_HapticCondition *hap_condition;
    SDL_HapticRamp *hap_ramp;
+   SDL_HapticCustom *hap_custom;
    DWORD *axes;
 
    /* Set global stuff. */
@@ -460,6 +462,7 @@
             SDL_OutOfMemory();
             return -1;
          }
+         SDL_memset(constant, 0, sizeof(FFCONSTANTFORCE));
 
          /* Specifics */
          constant->lMagnitude = CONVERT(hap_constant->level);
@@ -496,6 +499,7 @@
             SDL_OutOfMemory();
             return -1;
          }
+         SDL_memset(periodic, 0, sizeof(FFPERIODIC));
 
          /* Specifics */
          periodic->dwMagnitude = CONVERT(hap_periodic->magnitude);
@@ -534,6 +538,7 @@
             SDL_OutOfMemory();
             return -1;
          }
+         SDL_memset(condition, 0, sizeof(FFCONDITION));
 
          /* Specifics */
          for (i=0; i<dest->cAxes; i++) {
@@ -575,10 +580,13 @@
             SDL_OutOfMemory();
             return -1;
          }
+         SDL_memset(ramp, 0, sizeof(FFRAMPFORCE));
 
          /* Specifics */
          ramp->lStart = CONVERT(hap_ramp->start);
          ramp->lEnd = CONVERT(hap_ramp->end);
+         dest->cbTypeSpecificParams = sizeof(FFRAMPFORCE);
+         dest->lpvTypeSpecificParams = ramp;
 
          /* Generics */
          dest->dwDuration = hap_ramp->length * 1000; /* In microseconds. */
@@ -599,6 +607,45 @@
 
          break;
 
+      case SDL_HAPTIC_CUSTOM:
+         hap_custom = &src->custom;
+         custom = SDL_malloc(sizeof(FFCUSTOMFORCE));
+         if (custom == NULL) {
+            SDL_OutOfMemory();
+            return -1;
+         }
+         SDL_memset(custom, 0, sizeof(FFCUSTOMFORCE));
+
+         /* Specifics */
+         custom->cChannels = hap_custom->channels;
+         custom->dwSamplePeriod = hap_custom->period * 1000;
+         custom->cSamples = hap_custom->samples;
+         custom->rglForceData = SDL_malloc(sizeof(LONG)*custom->cSamples*custom->cChannels);
+         for (i=0; i<hap_custom->samples*hap_custom->channels; i++) { /* Copy data. */
+            custom->rglForceData[i] = CONVERT(hap_custom->data[i]);
+         }
+         dest->cbTypeSpecificParams = sizeof(FFCUSTOMFORCE);
+         dest->lpvTypeSpecificParams = custom;
+
+         /* Generics */
+         dest->dwDuration = hap_custom->length * 1000; /* In microseconds. */
+         dest->dwTriggerButton = FFJOFS_BUTTON(hap_custom->button);
+         dest->dwTriggerRepeatInterval = hap_custom->interval;
+         dest->dwStartDelay = hap_custom->delay * 1000; /* In microseconds. */
+
+         /* Direction. */
+         if (SDL_SYS_SetDirection(dest, &hap_custom->direction, dest->cAxes) < 0) {
+            return -1;
+         }
+         
+         /* Envelope */
+         envelope->dwAttackLevel = CONVERT(hap_custom->attack_level);
+         envelope->dwAttackTime = hap_custom->attack_length * 1000;
+         envelope->dwFadeLevel = CONVERT(hap_custom->fade_level);
+         envelope->dwFadeTime = hap_custom->fade_length * 1000;
+
+         break;
+
 
       default:
          SDL_SetError("Haptic: Unknown effect type.");
@@ -613,8 +660,10 @@
  * Frees an FFEFFECT allocated by SDL_SYS_ToFFEFFECT.
  */
 static void
-SDL_SYS_HapticFreeFFEFFECT( FFEFFECT * effect )
+SDL_SYS_HapticFreeFFEFFECT( FFEFFECT * effect, int type )
 {
+   FFCUSTOMFORCE *custom;
+
    if (effect->lpEnvelope != NULL) {
       SDL_free(effect->lpEnvelope);
       effect->lpEnvelope = NULL;
@@ -624,6 +673,11 @@
       effect->rgdwAxes = NULL;
    }
    if (effect->lpvTypeSpecificParams != NULL) {
+      if (type == SDL_HAPTIC_CUSTOM) { /* Must free the custom data. */
+         custom = (FFCUSTOMFORCE*) effect->lpvTypeSpecificParams;
+         SDL_free(custom->rglForceData);
+         custom->rglForceData = NULL;
+      }
       SDL_free(effect->lpvTypeSpecificParams);
       effect->lpvTypeSpecificParams = NULL;
    }
@@ -725,7 +779,7 @@
    return 0;
 
 err_effectdone:
-   SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect);
+   SDL_SYS_HapticFreeFFEFFECT(&effect->hweffect->effect, effect->effect.type);
 err_hweffect:
    if (effect->hweffect != NULL) {
       SDL_free(effect->hweffect);