Haptic coding bugs and fixes for Linux FF

Hi,

I sent this mail to you because I think you’re the author of most SDL
haptic implementation.

In the process of testing the new Linux FF kernel driver called
"ff-memless-next", I decided to review some applications that make use
of the Linux FF API: most important projects appeared to be Wine and
SDL.
I already sent an exhaustive collection of fixes to the wine-devel
mailing list after reviewing their DInput->Linux FF translation, and
it appears that my reviews are necessary.

After having reviewed your code, you did a really good job compared to
the Wine implementation.
But I still found some bugs:
(Also take a look at “Questions about the documentation/specification
of Linux ForceFeedback input.h”
(http://www.mail-archive.com/linux-input at vger.kernel.org/msg08463.html)
to confirm my reports.)

My first part will handle about “direction”:
(I also attached “DInputVsLinuxDirections.txt” to include the
derivation of the correct DInput<->Linux conversion, this may be handy
because you chose an identity mapping between SDL<->Dinput directions,
so you can use this file for the SDL<->Linux mapping)
One key point, is that Linux directions are defined as the direction
of applied force,
whereas DInput (and thus also SDL) directions are defined as the
direction to counteract the resulting force (=> reversed).

First, some documentation changes:
Change in SDL_haptic.h:369 :
North (0,-1)
^
|
|
(1,0) West <----[ HAPTIC ]----> East (-1,0)
|
|
v
South (0,1)
to :
North (0,-1)
^
|
|
(-1,0) West <----[ HAPTIC ]----> East (1,0)
|
|
v
South (0,1)
and change SDL_haptic.h:397 :

    • North: 0,-1, 0
    • East: -1, 0, 0
    • South: 0, 1, 0
    • West: 1, 0, 0
      to :
    • North: 0,-1, 0
    • East: 1, 0, 0
    • South: 0, 1, 0
    • West: -1, 0, 0

I can even prove this based on your own code that the above is a
contradiction: in the Linux “SDL_syshaptic.c” file, you wrote:
SDL_syshaptic.c:679 :

Polar direction, except that we have to add 90 degrees. It is the angle
from EAST {1,0} towards SOUTH {0,1}.
” => so you say that EAST is {+1, 0} (and you’re right :wink: )
SDL_syshaptic.c:693 :
"
- X-axis-value is the first coordinate (from center to EAST)
" => so you say that center to EAST is the positive x-axis (and once
again, you’re right )

There are also some code changes needed in the Linux "SDL_syshaptic.c"
file (DInput (or SDL) polar directions should be equal to Linux
directions, instead, you always added 180degrees which is wrong
according to Anssi Hannula):
So change SDL_syshaptic.c:672 :
tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000; /*
convert to range [0,0xFFFF] /
to :
tmp = ((dir->dir[0] % 36000) * 0x8000) / 18000; /
convert to
range [0,0xFFFF] */
and change SDL_syshaptic.c:682 :
–> finally add 18000 and convert to [0,0xFFFF]
as in case SDL_HAPTIC_POLAR.
/
tmp = ((dir->dir[0]) + 9000) % 36000; /
Convert to polars /
tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /
convert
to range [0,0xFFFF] */
to :
–> finally convert to [0,0xFFFF] as in case
SDL_HAPTIC_POLAR.
/
tmp = ((dir->dir[0]) + 9000) % 36000; /
Convert to polars /
tmp = (tmp * 0x8000) / 18000; /
convert to range [0,0xFFFF] */
and change SDL_syshaptic.c:698 :
–> finally add 18000 and convert to [0,0xFFFF]
as in case SDL_HAPTIC_POLAR.
/
tmp = (((int) (f * 18000. / M_PI)) + 45000) % 36000;
tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /
convert
to range [0,0xFFFF] */
to :
–> finally convert to [0,0xFFFF] as in case
SDL_HAPTIC_POLAR.
/
tmp = (((Sint32) (f * 18000. / M_PI)) + 45000) % 36000;
tmp = (tmp * 0x8000) / 18000; /
convert to range [0,0xFFFF] */

I also saw that you wrote (also in the Linux SDL_syshaptic.c):
float f; /* Ideally we’d use fixed point math instead of floats… */
which I agree with, we should avoid floats where possible.
You can practically achieve this by avoiding the “atan2” function on
line 689 when “dir->dir[0]” or/and “dir->dir[1]” equal zero, in that
case you can simply hardcode the corresponding cardinal directions.
This case is actually really common, e.g. in the game Life4Speed, they
always set “dir->dir[1]” equal to zero. This can save a lot of
performance.

For the conditional effects, you define both saturation parameters and
deadband as Uint16, which is conform the Linux API:
/* Condition */
Uint16 right_sat[3]; /< Level when joystick is to the positive side. */
Uint16 left_sat[3]; /
< Level when joystick is to the negative side. */
Sint16 right_coeff[3]; /< How fast to increase the force
towards the positive side. */
Sint16 left_coeff[3]; /
< How fast to increase the force
towards the negative side. */
Uint16 deadband[3]; /< Size of the dead zone. */
Sint16 center[3]; /
< Position of the dead zone. */
but in the Linux “SDL_syshaptic.c” file, you clamp them to 0x7FFF
(=32767), instead of to 0xFFFF:
dest->u.condition[0].right_saturation =
CLAMP(condition->right_sat[0]);
dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]);
and you defined CLAMP(x) as:
(((x) > 32767) ? 32767 : x)
So, please create don’t clamp these values (they can’t go out of
bounds because both Linux API types (u16) and SDL types (Uint16) are
the same)

But, you should also divide the saturation and deadband values in the
Windows and MAC OS cases by 2:
MACOS: change SDL_syshaptic.c:927 :
condition[i].dwPositiveSaturation =
CONVERT(hap_condition->right_sat[i]);
condition[i].dwNegativeSaturation =
CONVERT(hap_condition->left_sat[i]);
condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]);
to :
condition[i].dwPositiveSaturation =
CONVERT(hap_condition->right_sat[i] >> 1);
condition[i].dwNegativeSaturation =
CONVERT(hap_condition->left_sat[i] >> 1);
condition[i].lDeadBand = CONVERT(hap_condition->deadband[i] >> 1);
And something similar for Windows.

Elias

PS: I tried to send this message as soon as possible, because the
number of games that use SDL is rapidly increasing (mainly games from
Steam), and if I would have waited too long, the risk of backward
incompatibility would become high. (luckily there are still few games
that use Haptic, but that may change in the future.)
-------------- next part --------------
Directions==========

For conversions between different APIs, the physical behaviour should be the same.

DInput


Extracted from http://msdn.microsoft.com/en-us/library/windows/desktop/ee417536(v=vs.85).aspx :

Physical situation:

     North (polar 0, spher[0] 270)
        (0, -1)
        -y Far

West East (polar 90, spher[0] 0)
(-1, 0) O (+1, 0)
-x Left +x Right

         South
        (0, +1)
        +y Near


        .------.
        | User |
        '------'

Remember these are the ‘directions’:
as defined as the direction the user should exert force in to counteract the force.
So the direction in which the force is applied by the joystick, is opposite.

If we’re interested in the direction in which the force is applied by the joystick,
the physical situation becomes point-flipped:

              (polar 0, spher[0] 270)
                      (0, +1)
                        +y

(polar 270, spher[0] 180) (polar 90, spher[0] 0)
(+1, 0) O (-1, 0)
+x -x

              (polar 180, spher[0] 90)
                      (0, -1)
                        -y

Linux


Extracted from Linux input.h, and from ff-memless-next.txt for the cartesian coordinates :

Physical situation:

        Up (dir 180)
          (0, -1)
            -y

Left (dir 90) Right (dir 270)
(-1, 0) O (+1, 0)
-x +x

        Down (dir 0)
          (0, +1)
            +y


         .------.
         | User |
         '------'

It is unclear what is meant by ‘directions’ in this case:
Possibility #1: counteraction direction of user
Possibility #2: direction of force applied by joystick

Anssi Hannula confirmed that Possibility #2 is the right one:
(http://www.mail-archive.com/linux-input at vger.kernel.org/msg08463.html)

Mapping


In the “Carts” column, you can find the cartesian coordinates which indicate the counteraction direction of user.
(This choice is arbitrary (‘direction of force applied by joystick’ could also have been chosen), just to have a physical reference.)
These “Carts” tuples should be equal across APIs to ensure equal behaviour.

#Assume Possibility #1:

DInput <-> Linux

_________________ | ___________

Carts|Polar|Spher | Carts|Direc

-----±----±---- | -----±----

0, -1| 0 | 270 | 0, -1| 180

+1, 0| 90 | 0 | +1, 0| 270

0, +1| 180 | 90 | 0, +1| 0

-1, 0| 270 | 180 | -1, 0| 90

Assume Possibility #2:
=> Linux cartesian coordinates are opposite in respect to the “Carts” reference.

      DInput         <->     Linux
_________________     |   ___________
Carts|Polar|Spher     |   Carts|Direc
-----+-----+-----     |   -----+-----
0, -1|   0 | 270      |   0, -1|   0 
+1, 0|  90 |   0      |   +1, 0|  90 
0, +1| 180 |  90      |   0, +1| 180 
-1, 0| 270 | 180      |   -1, 0| 270 

If DInput now says: “Let’s swap the X and Y axes!”, then the following conversions hold:

#Assume Possibility #1:

DInput <-> Linux

_________________ | ___________

Carts|Polar|Spher | Carts|Direc

-----±----±---- | -----±----

-1, 0| 0 | 270 | -1, 0| 90

0, +1| 90 | 0 | 0, +1| 0

+1, 0| 180 | 90 | +1, 0| 270

0, -1| 270 | 180 | 0, -1| 180

Assume Possibility #2:
=> Linux cartesian coordinates are opposite in respect to the “Carts” reference.

      DInput         <->     Linux
_________________     |   ___________
Carts|Polar|Spher     |   Carts|Direc
-----+-----+-----     |   -----+-----
-1, 0|   0 | 270      |   -1, 0| 270 
0, +1|  90 |   0      |   0, +1| 180 
+1, 0| 180 |  90      |   +1, 0|  90 
0, -1| 270 | 180      |   0, -1|   0

@Ryan:
The reason I forwarded this message to you, is because the code Edgar
originally committed is 6 years old, and I saw that you did some
recent commits on the Haptic code, and because I’m unable to contact
Edgar via mail or IRC.

I did not file a bugreport about this message, because I did a review
of the code, rather than discovering a bug through running SDL.
But the things in this mail are actually very important: wrong
interface implementations, so if you’ve got some time, please take a
look at it. This should be merged into the next release of SDL as soon
as possible (because risk of backward incompatibility increases with
time).

Best regards,

EliasOn Thu, Mar 13, 2014 at 10:34 PM, Elias Vanderstuyft <@Elias_Vanderstuyft> wrote:

Hi,

I sent this mail to you because I think you’re the author of most SDL
haptic implementation.

In the process of testing the new Linux FF kernel driver called
"ff-memless-next", I decided to review some applications that make use
of the Linux FF API: most important projects appeared to be Wine and
SDL.
I already sent an exhaustive collection of fixes to the wine-devel
mailing list after reviewing their DInput->Linux FF translation, and
it appears that my reviews are necessary.

After having reviewed your code, you did a really good job compared to
the Wine implementation.
But I still found some bugs:
(Also take a look at “Questions about the documentation/specification
of Linux ForceFeedback input.h”
(http://www.mail-archive.com/linux-input at vger.kernel.org/msg08463.html)
to confirm my reports.)

My first part will handle about “direction”:
(I also attached “DInputVsLinuxDirections.txt” to include the
derivation of the correct DInput<->Linux conversion, this may be handy
because you chose an identity mapping between SDL<->Dinput directions,
so you can use this file for the SDL<->Linux mapping)
One key point, is that Linux directions are defined as the direction
of applied force,
whereas DInput (and thus also SDL) directions are defined as the
direction to counteract the resulting force (=> reversed).

First, some documentation changes:
Change in SDL_haptic.h:369 :
North (0,-1)
^
|
|
(1,0) West <----[ HAPTIC ]----> East (-1,0)
|
|
v
South (0,1)
to :
North (0,-1)
^
|
|
(-1,0) West <----[ HAPTIC ]----> East (1,0)
|
|
v
South (0,1)
and change SDL_haptic.h:397 :

    • North: 0,-1, 0
    • East: -1, 0, 0
    • South: 0, 1, 0
    • West: 1, 0, 0
      to :
    • North: 0,-1, 0
    • East: 1, 0, 0
    • South: 0, 1, 0
    • West: -1, 0, 0

I can even prove this based on your own code that the above is a
contradiction: in the Linux “SDL_syshaptic.c” file, you wrote:
SDL_syshaptic.c:679 :

Polar direction, except that we have to add 90 degrees. It is the angle
from EAST {1,0} towards SOUTH {0,1}.
” => so you say that EAST is {+1, 0} (and you’re right :wink: )
SDL_syshaptic.c:693 :
"
- X-axis-value is the first coordinate (from center to EAST)
" => so you say that center to EAST is the positive x-axis (and once
again, you’re right )

There are also some code changes needed in the Linux "SDL_syshaptic.c"
file (DInput (or SDL) polar directions should be equal to Linux
directions, instead, you always added 180degrees which is wrong
according to Anssi Hannula):
So change SDL_syshaptic.c:672 :
tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000; /*
convert to range [0,0xFFFF] /
to :
tmp = ((dir->dir[0] % 36000) * 0x8000) / 18000; /
convert to
range [0,0xFFFF] */
and change SDL_syshaptic.c:682 :
–> finally add 18000 and convert to [0,0xFFFF]
as in case SDL_HAPTIC_POLAR.
/
tmp = ((dir->dir[0]) + 9000) % 36000; /
Convert to polars /
tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /
convert
to range [0,0xFFFF] */
to :
–> finally convert to [0,0xFFFF] as in case
SDL_HAPTIC_POLAR.
/
tmp = ((dir->dir[0]) + 9000) % 36000; /
Convert to polars /
tmp = (tmp * 0x8000) / 18000; /
convert to range [0,0xFFFF] */
and change SDL_syshaptic.c:698 :
–> finally add 18000 and convert to [0,0xFFFF]
as in case SDL_HAPTIC_POLAR.
/
tmp = (((int) (f * 18000. / M_PI)) + 45000) % 36000;
tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /
convert
to range [0,0xFFFF] */
to :
–> finally convert to [0,0xFFFF] as in case
SDL_HAPTIC_POLAR.
/
tmp = (((Sint32) (f * 18000. / M_PI)) + 45000) % 36000;
tmp = (tmp * 0x8000) / 18000; /
convert to range [0,0xFFFF] */

I also saw that you wrote (also in the Linux SDL_syshaptic.c):
float f; /* Ideally we’d use fixed point math instead of floats… */
which I agree with, we should avoid floats where possible.
You can practically achieve this by avoiding the “atan2” function on
line 689 when “dir->dir[0]” or/and “dir->dir[1]” equal zero, in that
case you can simply hardcode the corresponding cardinal directions.
This case is actually really common, e.g. in the game Life4Speed, they
always set “dir->dir[1]” equal to zero. This can save a lot of
performance.

For the conditional effects, you define both saturation parameters and
deadband as Uint16, which is conform the Linux API:
/* Condition */
Uint16 right_sat[3]; /< Level when joystick is to the positive side. */
Uint16 left_sat[3]; /
< Level when joystick is to the negative side. */
Sint16 right_coeff[3]; /< How fast to increase the force
towards the positive side. */
Sint16 left_coeff[3]; /
< How fast to increase the force
towards the negative side. */
Uint16 deadband[3]; /< Size of the dead zone. */
Sint16 center[3]; /
< Position of the dead zone. */
but in the Linux “SDL_syshaptic.c” file, you clamp them to 0x7FFF
(=32767), instead of to 0xFFFF:
dest->u.condition[0].right_saturation =
CLAMP(condition->right_sat[0]);
dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]);
and you defined CLAMP(x) as:
(((x) > 32767) ? 32767 : x)
So, please create don’t clamp these values (they can’t go out of
bounds because both Linux API types (u16) and SDL types (Uint16) are
the same)

But, you should also divide the saturation and deadband values in the
Windows and MAC OS cases by 2:
MACOS: change SDL_syshaptic.c:927 :
condition[i].dwPositiveSaturation =
CONVERT(hap_condition->right_sat[i]);
condition[i].dwNegativeSaturation =
CONVERT(hap_condition->left_sat[i]);
condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]);
to :
condition[i].dwPositiveSaturation =
CONVERT(hap_condition->right_sat[i] >> 1);
condition[i].dwNegativeSaturation =
CONVERT(hap_condition->left_sat[i] >> 1);
condition[i].lDeadBand = CONVERT(hap_condition->deadband[i] >> 1);
And something similar for Windows.

Elias

PS: I tried to send this message as soon as possible, because the
number of games that use SDL is rapidly increasing (mainly games from
Steam), and if I would have waited too long, the risk of backward
incompatibility would become high. (luckily there are still few games
that use Haptic, but that may change in the future.)

I did not file a bugreport about this message, because I did a review
of the code, rather than discovering a bug through running SDL.
But the things in this mail are actually very important: wrong
interface implementations, so if you’ve got some time, please take a
look at it. This should be merged into the next release of SDL as soon
as possible (because risk of backward incompatibility increases with
time).

Thanks, I’ll try to find some time to look into this soon.

–ryan.

Thank you very much.On Wed, Mar 19, 2014 at 1:29 AM, Ryan C. Gordon wrote:

I did not file a bugreport about this message, because I did a review
of the code, rather than discovering a bug through running SDL.
But the things in this mail are actually very important: wrong
interface implementations, so if you’ve got some time, please take a
look at it. This should be merged into the next release of SDL as soon
as possible (because risk of backward incompatibility increases with
time).

Thanks, I’ll try to find some time to look into this soon.

Hi,

I realised you’re probably still too busy to take care of this,
so I decided to tackle the issue now that I have some time.
I created 6 patches based on-top of today’s current mercurial
changeset: 9062:74356aed1fa2 (revision 8a1d9a60f9be)
I tested everything on Linux (using a dummy force-feedback device that
visualizes all forces, so I’m pretty confident the correctness of my
code),
but some changes to code of other platforms (i.e. MacOS and Windows)
were not tested.

Summary:On Wed, Mar 19, 2014 at 9:02 AM, Elias Vanderstuyft <@Elias_Vanderstuyft> wrote:

On Wed, Mar 19, 2014 at 1:29 AM, Ryan C. Gordon wrote:

I did not file a bugreport about this message, because I did a review
of the code, rather than discovering a bug through running SDL.
But the things in this mail are actually very important: wrong
interface implementations, so if you’ve got some time, please take a
look at it. This should be merged into the next release of SDL as soon
as possible (because risk of backward incompatibility increases with
time).

Thanks, I’ll try to find some time to look into this soon.

Thank you very much.


vanilla-rev1.diff:
Don’t interpret a direction of polar 35999 (or linux-direction
0xFFFF) as “unsupported type”.

rev1-rev2.diff:
Fix the misconception that DInput’s POLAR direction doesn’t match
Linux’s direction.
Note: this also solves a rounding bug that e.g. caused
zero direction to give non-zero output of the X-force value.

rev2-rev3.diff:
Explicitly avoid floating point arithmetic if it’s not needed.
This appears to be the common case in games, especially
since the existence of multi-axes force-feedback devices is extremely
small.

rev3-rev4.diff:
Fix the misconception that Linux’ saturation and deadband
parameters - on which the corresponding SDL parameters were based -
use only half of the possible range
Note: untested on Darwin and Windows

rev4-rev5.diff:
Fix a number of clamping bugs for Windows haptics, by using the
Darwin haptics code
Note: untested on Windows

rev5-rev6.diff:
Add some missing haptic types to test, and fix wrong array-sizes

These should get in before releasing SDL2.1, as they fix some critical bugs.
Please let me know if you notice flaws with my patches or if there are
things unclear.
(I’ve never created patches for “mercurial” before)
You’ve got my:
Signed-off-by: Elias Vanderstuyft <@Elias_Vanderstuyft>

Cheers,
Elias
-------------- next part --------------
diff -uNrp rev1/include/SDL_haptic.h rev2/include/SDL_haptic.h
— rev1/include/SDL_haptic.h 2014-08-14 10:45:55.000000000 +0200
+++ rev2/include/SDL_haptic.h 2014-08-14 16:23:36.763519322 +0200
@@ -370,7 +370,7 @@ typedef struct _SDL_Haptic SDL_Haptic;
^
|
|

  • (1,0) West <----[ HAPTIC ]----> East (-1,0)
  • (-1,0) West <----[ HAPTIC ]----> East (1,0)
    |
    |
    v
    @@ -395,9 +395,9 @@ typedef struct _SDL_Haptic SDL_Haptic;
  • (X axis, Y axis and Z axis (with 3 axes)). ::SDL_HAPTIC_CARTESIAN uses
  • the first three \c dir parameters. The cardinal directions would be:
    • North: 0,-1, 0
      • East: -1, 0, 0
      • East: 1, 0, 0
      • South: 0, 1, 0
      • West: 1, 0, 0
      • West: -1, 0, 0
    • The Z axis represents the height of the effect if supported, otherwise
    • it’s unused. In cartesian encoding (1, 2) would be the same as (2, 4), you
      diff -uNrp rev1/src/haptic/linux/SDL_syshaptic.c rev2/src/haptic/linux/SDL_syshaptic.c
      — rev1/src/haptic/linux/SDL_syshaptic.c 2014-08-14 15:43:00.325973049 +0200
      +++ rev2/src/haptic/linux/SDL_syshaptic.c 2014-08-14 15:53:06.000000000 +0200
      @@ -671,7 +671,7 @@ SDL_SYS_ToDirection(Uint16 *dest, SDL_Ha
      180 deg -> 0x8000 (up)
      270 deg -> 0xC000 (right)
      */
  •    tmp = (((18000 + src->dir[0]) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
    
  •    tmp = ((src->dir[0] % 36000) * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
       *dest = (Uint16) tmp;
       break;
    

@@ -682,10 +682,10 @@ SDL_SYS_ToDirection(Uint16 *dest, SDL_Ha
Polar direction, except that we have to add 90 degrees. It is the angle
from EAST {1,0} towards SOUTH {0,1}.
–> add 9000

  •            --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
    
  •            --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
           */
           tmp = ((src->dir[0]) + 9000) % 36000;    /* Convert to polars */
    
  •    tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
    
  •    tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
       *dest = (Uint16) tmp;
       break;
    

@@ -699,10 +699,10 @@ SDL_SYS_ToDirection(Uint16 *dest, SDL_Ha
have the first spherical value. Therefore we proceed as in case
SDL_HAPTIC_SPHERICAL and add another 9000 to get the polar value.
–> add 45000 in total

  •                  --> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
    
  •                  --> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
                   */
    
  •            tmp = (((int) (f * 18000. / M_PI)) + 45000) % 36000;
    
  •    tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
    
  •            tmp = (((Sint32) (f * 18000. / M_PI)) + 45000) % 36000;
    
  •    tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
       *dest = (Uint16) tmp;
       break;
    

-------------- next part --------------
diff -uNrp rev2/src/haptic/linux/SDL_syshaptic.c rev3/src/haptic/linux/SDL_syshaptic.c
— rev2/src/haptic/linux/SDL_syshaptic.c 2014-08-14 15:53:06.000000000 +0200
+++ rev3/src/haptic/linux/SDL_syshaptic.c 2014-08-14 16:48:00.000000000 +0200
@@ -658,7 +658,6 @@ static int
SDL_SYS_ToDirection(Uint16 *dest, SDL_HapticDirection * src)
{
Uint32 tmp;

  • float f; /* Ideally we’d use fixed point math instead of floats… */

    switch (src->type) {
    case SDL_HAPTIC_POLAR:
    @@ -690,7 +689,12 @@ SDL_SYS_ToDirection(Uint16 *dest, SDL_Ha
    break;

    case SDL_HAPTIC_CARTESIAN:

  •    f = atan2(src->dir[1], src->dir[0]);
    
  •    if (!src->dir[1])
    
  •        *dest = (src->dir[0] >= 0 ? 0x4000 : 0xC000);
    
  •    else if (!src->dir[0])
    
  •        *dest = (src->dir[1] >= 0 ? 0x8000 : 0);
    
  •    else {
    
  •        float f = atan2(src->dir[1], src->dir[0]);    /* Ideally we'd use fixed point math instead of floats... */
                   /*
                     atan2 takes the parameters: Y-axis-value and X-axis-value (in that order)
                      - Y-axis-value is the second coordinate (from center to SOUTH)
    

@@ -702,8 +706,9 @@ SDL_SYS_ToDirection(Uint16 *dest, SDL_Ha
–> finally convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
*/
tmp = (((Sint32) (f * 18000. / M_PI)) + 45000) % 36000;

  •    tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
    
  •    *dest = (Uint16) tmp;
    
  •        tmp = (tmp * 0x8000) / 18000; /* convert to range [0,0xFFFF] */
    
  •        *dest = (Uint16) tmp;
    
  •    }
       break;
    

    default:
    -------------- next part --------------
    diff -uNrp rev3/include/SDL_haptic.h rev4/include/SDL_haptic.h
    — rev3/include/SDL_haptic.h 2014-08-14 16:23:36.000000000 +0200
    +++ rev4/include/SDL_haptic.h 2014-08-14 21:17:23.000000000 +0200
    @@ -604,11 +604,11 @@ typedef struct SDL_HapticCondition
    Uint16 interval; /**< How soon it can be triggered again after button. */

    /* Condition */

  • Uint16 right_sat[3]; /**< Level when joystick is to the positive side. */
  • Uint16 left_sat[3]; /**< Level when joystick is to the negative side. */
  • Uint16 right_sat[3]; /**< Level when joystick is to the positive side; max 0xFFFF. */
  • Uint16 left_sat[3]; /< Level when joystick is to the negative side; max 0xFFFF. */
    Sint16 right_coeff[3]; /
    < How fast to increase the force towards the positive side. */
    Sint16 left_coeff[3]; /**< How fast to increase the force towards the negative side. */
  • Uint16 deadband[3]; /**< Size of the dead zone. */
  • Uint16 deadband[3]; /< Size of the dead zone; max 0xFFFF: whole axis-range when 0-centered. */
    Sint16 center[3]; /
    < Position of the dead zone. */
    } SDL_HapticCondition;

diff -uNrp rev3/src/haptic/darwin/SDL_syshaptic.c rev4/src/haptic/darwin/SDL_syshaptic.c
— rev3/src/haptic/darwin/SDL_syshaptic.c 2014-08-14 10:45:54.000000000 +0200
+++ rev4/src/haptic/darwin/SDL_syshaptic.c 2014-08-14 21:18:41.000000000 +0200
@@ -924,10 +924,10 @@ SDL_SYS_ToFFEFFECT(SDL_Haptic * haptic,
condition[i].lNegativeCoefficient =
CONVERT(hap_condition->left_coeff[i]);
condition[i].dwPositiveSaturation =

  •            CCONVERT(hap_condition->right_sat[i]);
    
  •            CCONVERT(hap_condition->right_sat[i] / 2);
           condition[i].dwNegativeSaturation =
    
  •            CCONVERT(hap_condition->left_sat[i]);
    
  •        condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i]);
    
  •            CCONVERT(hap_condition->left_sat[i] / 2);
    
  •        condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2);
       }
       dest->cbTypeSpecificParams = sizeof(FFCONDITION) * dest->cAxes;
       dest->lpvTypeSpecificParams = condition;
    

diff -uNrp rev3/src/haptic/linux/SDL_syshaptic.c rev4/src/haptic/linux/SDL_syshaptic.c
— rev3/src/haptic/linux/SDL_syshaptic.c 2014-08-14 16:48:00.000000000 +0200
+++ rev4/src/haptic/linux/SDL_syshaptic.c 2014-08-14 21:11:32.000000000 +0200
@@ -847,20 +847,18 @@ SDL_SYS_ToFFEffect(struct ff_effect *des

     /* Condition */
     /* X axis */
  •    dest->u.condition[0].right_saturation =
    
  •        CLAMP(condition->right_sat[0]);
    
  •    dest->u.condition[0].left_saturation = CLAMP(condition->left_sat[0]);
    
  •    dest->u.condition[0].right_saturation = condition->right_sat[0];
    
  •    dest->u.condition[0].left_saturation = condition->left_sat[0];
       dest->u.condition[0].right_coeff = condition->right_coeff[0];
       dest->u.condition[0].left_coeff = condition->left_coeff[0];
    
  •    dest->u.condition[0].deadband = CLAMP(condition->deadband[0]);
    
  •    dest->u.condition[0].deadband = condition->deadband[0];
       dest->u.condition[0].center = condition->center[0];
       /* Y axis */
    
  •    dest->u.condition[1].right_saturation =
    
  •        CLAMP(condition->right_sat[1]);
    
  •    dest->u.condition[1].left_saturation = CLAMP(condition->left_sat[1]);
    
  •    dest->u.condition[1].right_saturation = condition->right_sat[1];
    
  •    dest->u.condition[1].left_saturation = condition->left_sat[1];
       dest->u.condition[1].right_coeff = condition->right_coeff[1];
       dest->u.condition[1].left_coeff = condition->left_coeff[1];
    
  •    dest->u.condition[1].deadband = CLAMP(condition->deadband[1]);
    
  •    dest->u.condition[1].deadband = condition->deadband[1];
       dest->u.condition[1].center = condition->center[1];
    
       /*
    

diff -uNrp rev3/src/haptic/windows/SDL_dinputhaptic.c rev4/src/haptic/windows/SDL_dinputhaptic.c
— rev3/src/haptic/windows/SDL_dinputhaptic.c 2014-08-14 10:45:54.000000000 +0200
+++ rev4/src/haptic/windows/SDL_dinputhaptic.c 2014-08-14 21:18:15.000000000 +0200
@@ -763,10 +763,10 @@ SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic,
condition[i].lNegativeCoefficient =
CONVERT(hap_condition->left_coeff[i]);
condition[i].dwPositiveSaturation =

  •            CONVERT(hap_condition->right_sat[i]);
    
  •            CONVERT(hap_condition->right_sat[i] / 2);
           condition[i].dwNegativeSaturation =
    
  •            CONVERT(hap_condition->left_sat[i]);
    
  •        condition[i].lDeadBand = CONVERT(hap_condition->deadband[i]);
    
  •            CONVERT(hap_condition->left_sat[i] / 2);
    
  •        condition[i].lDeadBand = CONVERT(hap_condition->deadband[i] / 2);
       }
       dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
       dest->lpvTypeSpecificParams = condition;
    

diff -uNrp rev3/test/testhaptic.c rev4/test/testhaptic.c
— rev3/test/testhaptic.c 2014-08-14 16:54:10.000000000 +0200
+++ rev4/test/testhaptic.c 2014-08-14 21:22:44.000000000 +0200
@@ -172,8 +172,8 @@ main(int argc, char **argv)
efx[nefx].type = SDL_HAPTIC_SPRING;
efx[nefx].condition.length = 5000;
for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {

  •        efx[nefx].condition.right_sat[i] = 0x7FFF;
    
  •        efx[nefx].condition.left_sat[i] = 0x7FFF;
    
  •        efx[nefx].condition.right_sat[i] = 0xFFFF;
    
  •        efx[nefx].condition.left_sat[i] = 0xFFFF;
           efx[nefx].condition.right_coeff[i] = 0x2000;
           efx[nefx].condition.left_coeff[i] = 0x2000;
           efx[nefx].condition.center[i] = 0x1000;     /* Displace the center for it to move. */
    

@@ -191,10 +191,11 @@ main(int argc, char **argv)
efx[nefx].type = SDL_HAPTIC_INERTIA;
efx[nefx].condition.length = 5000;
for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {

  •        efx[nefx].condition.right_sat[i] = 0x7FFF;
    
  •        efx[nefx].condition.left_sat[i] = 0x7FFF;
    
  •        efx[nefx].condition.right_sat[i] = 0xFFFF;
    
  •        efx[nefx].condition.left_sat[i] = 0xFFFF;
           efx[nefx].condition.right_coeff[i] = 0x2000;
           efx[nefx].condition.left_coeff[i] = 0x2000;
    
  •        efx[nefx].condition.deadband[i] = 0x1000;    /* 1/16th of axis-range around the center is 'dead'. */
       }
       id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
       if (id[nefx] < 0) {
    

-------------- next part --------------
diff -uNrp rev4/src/haptic/windows/SDL_dinputhaptic.c rev5/src/haptic/windows/SDL_dinputhaptic.c
— rev4/src/haptic/windows/SDL_dinputhaptic.c 2014-08-14 21:18:15.000000000 +0200
+++ rev5/src/haptic/windows/SDL_dinputhaptic.c 2014-08-14 21:45:38.000000000 +0200
@@ -602,7 +602,10 @@ SDL_SYS_SetDirection(DIEFFECT * effect,
}
}

-#define CONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)10000) / 0x7FFF)
+/
Clamps and converts. */
+#define CCONVERT(x) (((x) > 0x7FFF) ? 10000 : ((x)10000) / 0x7FFF)
+/
Just converts. */
+#define CONVERT(x) (((x)10000) / 0x7FFF)
/

  • Creates the DIEFFECT from a SDL_HapticEffect.
    */
    @@ -689,9 +692,9 @@ SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic,
    SDL_free(dest->lpEnvelope);
    dest->lpEnvelope = NULL;
    } else {
  •        envelope->dwAttackLevel = CONVERT(hap_constant->attack_level);
    
  •        envelope->dwAttackLevel = CCONVERT(hap_constant->attack_level);
           envelope->dwAttackTime = hap_constant->attack_length * 1000;
    
  •        envelope->dwFadeLevel = CONVERT(hap_constant->fade_level);
    
  •        envelope->dwFadeLevel = CCONVERT(hap_constant->fade_level);
           envelope->dwFadeTime = hap_constant->fade_length * 1000;
       }
    

@@ -736,9 +739,9 @@ SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic,
SDL_free(dest->lpEnvelope);
dest->lpEnvelope = NULL;
} else {

  •        envelope->dwAttackLevel = CONVERT(hap_periodic->attack_level);
    
  •        envelope->dwAttackLevel = CCONVERT(hap_periodic->attack_level);
           envelope->dwAttackTime = hap_periodic->attack_length * 1000;
    
  •        envelope->dwFadeLevel = CONVERT(hap_periodic->fade_level);
    
  •        envelope->dwFadeLevel = CCONVERT(hap_periodic->fade_level);
           envelope->dwFadeTime = hap_periodic->fade_length * 1000;
       }
    

@@ -763,10 +766,10 @@ SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic,
condition[i].lNegativeCoefficient =
CONVERT(hap_condition->left_coeff[i]);
condition[i].dwPositiveSaturation =

  •            CONVERT(hap_condition->right_sat[i] / 2);
    
  •            CCONVERT(hap_condition->right_sat[i] / 2);
           condition[i].dwNegativeSaturation =
    
  •            CONVERT(hap_condition->left_sat[i] / 2);
    
  •        condition[i].lDeadBand = CONVERT(hap_condition->deadband[i] / 2);
    
  •            CCONVERT(hap_condition->left_sat[i] / 2);
    
  •        condition[i].lDeadBand = CCONVERT(hap_condition->deadband[i] / 2);
       }
       dest->cbTypeSpecificParams = sizeof(DICONDITION) * dest->cAxes;
       dest->lpvTypeSpecificParams = condition;
    

@@ -819,9 +822,9 @@ SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic,
SDL_free(dest->lpEnvelope);
dest->lpEnvelope = NULL;
} else {

  •        envelope->dwAttackLevel = CONVERT(hap_ramp->attack_level);
    
  •        envelope->dwAttackLevel = CCONVERT(hap_ramp->attack_level);
           envelope->dwAttackTime = hap_ramp->attack_length * 1000;
    
  •        envelope->dwFadeLevel = CONVERT(hap_ramp->fade_level);
    
  •        envelope->dwFadeLevel = CCONVERT(hap_ramp->fade_level);
           envelope->dwFadeTime = hap_ramp->fade_length * 1000;
       }
    

@@ -842,7 +845,7 @@ SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic,
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]);
    
  •        custom->rglForceData[i] = CCONVERT(hap_custom->data[i]);
       }
       dest->cbTypeSpecificParams = sizeof(DICUSTOMFORCE);
       dest->lpvTypeSpecificParams = custom;
    

@@ -864,9 +867,9 @@ SDL_SYS_ToDIEFFECT(SDL_Haptic * haptic,
SDL_free(dest->lpEnvelope);
dest->lpEnvelope = NULL;
} else {

  •        envelope->dwAttackLevel = CONVERT(hap_custom->attack_level);
    
  •        envelope->dwAttackLevel = CCONVERT(hap_custom->attack_level);
           envelope->dwAttackTime = hap_custom->attack_length * 1000;
    
  •        envelope->dwFadeLevel = CONVERT(hap_custom->fade_level);
    
  •        envelope->dwFadeLevel = CCONVERT(hap_custom->fade_level);
           envelope->dwFadeTime = hap_custom->fade_length * 1000;
       }
    

-------------- next part --------------
diff -uNrp rev5/test/testhaptic.c rev6/test/testhaptic.c
— rev5/test/testhaptic.c 2014-08-14 21:22:44.000000000 +0200
+++ rev6/test/testhaptic.c 2014-08-14 22:46:08.000000000 +0200
@@ -45,8 +45,8 @@ main(int argc, char **argv)
int i;
char *name;
int index;

  • SDL_HapticEffect efx[5];
  • int id[5];
  • SDL_HapticEffect efx[9];
  • int id[9];
    int nefx;
    unsigned int supported;

@@ -149,6 +149,7 @@ main(int argc, char *argv)
}
nefx++;
}
+
/
Now the classical constant effect. */
if (supported & SDL_HAPTIC_CONSTANT) {
SDL_Log(" effect %d: Constant Force\n", nefx);
@@ -166,6 +167,7 @@ main(int argc, char *argv)
}
nefx++;
}
+
/
The cute spring effect. */
if (supported & SDL_HAPTIC_SPRING) {
SDL_Log(" effect %d: Condition Spring\n", nefx);
@@ -185,6 +187,24 @@ main(int argc, char **argv)
}
nefx++;
}

  • /* The interesting damper effect. */
  • if (supported & SDL_HAPTIC_DAMPER) {
  •    SDL_Log("   effect %d: Condition Damper\n", nefx);
    
  •    efx[nefx].type = SDL_HAPTIC_DAMPER;
    
  •    efx[nefx].condition.length = 5000;
    
  •    for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
    
  •        efx[nefx].condition.right_sat[i] = 0xFFFF;
    
  •        efx[nefx].condition.left_sat[i] = 0xFFFF;
    
  •        efx[nefx].condition.right_coeff[i] = 0x2000;
    
  •        efx[nefx].condition.left_coeff[i] = 0x2000;
    
  •    }
    
  •    id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    
  •    if (id[nefx] < 0) {
    
  •        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
    
  •        abort_execution();
    
  •    }
    
  •    nefx++;
    
  • }
    /* The pretty awesome inertia effect. */
    if (supported & SDL_HAPTIC_INERTIA) {
    SDL_Log(" effect %d: Condition Inertia\n", nefx);
    @@ -200,6 +220,44 @@ main(int argc, char **argv)
    id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    if (id[nefx] < 0) {
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, “UPLOADING EFFECT ERROR: %s\n”, SDL_GetError());
  •        abort_execution();
    
  •    }
    
  •    nefx++;
    
  • }
  • /* The hot friction effect. */
  • if (supported & SDL_HAPTIC_FRICTION) {
  •    SDL_Log("   effect %d: Condition Friction\n", nefx);
    
  •    efx[nefx].type = SDL_HAPTIC_FRICTION;
    
  •    efx[nefx].condition.length = 5000;
    
  •    for (i = 0; i < SDL_HapticNumAxes(haptic); i++) {
    
  •        efx[nefx].condition.right_sat[i] = 0xFFFF;
    
  •        efx[nefx].condition.left_sat[i] = 0xFFFF;
    
  •        efx[nefx].condition.right_coeff[i] = 0x2000;
    
  •        efx[nefx].condition.left_coeff[i] = 0x2000;
    
  •    }
    
  •    id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    
  •    if (id[nefx] < 0) {
    
  •        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
    
  •        abort_execution();
    
  •    }
    
  •    nefx++;
    
  • }
  • /* Now we’ll try a ramp effect */
  • if (supported & SDL_HAPTIC_RAMP) {
  •    SDL_Log("   effect %d: Ramp\n", nefx);
    
  •    efx[nefx].type = SDL_HAPTIC_RAMP;
    
  •    efx[nefx].ramp.direction.type = SDL_HAPTIC_CARTESIAN;
    
  •    efx[nefx].ramp.direction.dir[0] = 1;     /* Force comes from                 */
    
  •    efx[nefx].ramp.direction.dir[1] = -1;    /*                  the north-east. */
    
  •    efx[nefx].ramp.length = 5000;
    
  •    efx[nefx].ramp.start = 0x4000;
    
  •    efx[nefx].ramp.end = -0x4000;
    
  •    efx[nefx].ramp.attack_length = 1000;
    
  •    efx[nefx].ramp.fade_length = 1000;
    
  •    id[nefx] = SDL_HapticNewEffect(haptic, &efx[nefx]);
    
  •    if (id[nefx] < 0) {
    
  •        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "UPLOADING EFFECT ERROR: %s\n", SDL_GetError());
           abort_execution();
       }
       nefx++;
    

-------------- next part --------------
diff -uNrp vanilla/src/haptic/linux/SDL_syshaptic.c rev1/src/haptic/linux/SDL_syshaptic.c
— vanilla/src/haptic/linux/SDL_syshaptic.c 2014-08-14 14:24:39.000000000 +0200
+++ rev1/src/haptic/linux/SDL_syshaptic.c 2014-08-14 15:43:00.325973049 +0200
@@ -652,15 +652,15 @@ SDL_SYS_ToButton(Uint16 button)

/*

    • Returns the ff_effect usable direction from a SDL_HapticDirection.
    • Initializes the ff_effect usable direction from a SDL_HapticDirection.
      */
      -static Uint16
      -SDL_SYS_ToDirection(SDL_HapticDirection * dir)
      +static int
      +SDL_SYS_ToDirection(Uint16 dest, SDL_HapticDirection * src)
      {
      Uint32 tmp;
      float f; /
      Ideally we’d use fixed point math instead of floats… */
  • switch (dir->type) {
  • switch (src->type) {
    case SDL_HAPTIC_POLAR:
    /* Linux directions start from south.
    (and range from 0 to 0xFFFF)
    @@ -671,10 +671,11 @@ SDL_SYS_ToDirection(SDL_HapticDirection
    180 deg -> 0x8000 (up)
    270 deg -> 0xC000 (right)
    */
  •    tmp = (((18000 + dir->dir[0]) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
    
  •    return (Uint16) tmp;
    
  •    tmp = (((18000 + src->dir[0]) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
    
  •    *dest = (Uint16) tmp;
    
  •    break;
    
  •   case SDL_HAPTIC_SPHERICAL:
    
  • case SDL_HAPTIC_SPHERICAL:
    /*
    We convert to polar, because that’s the only supported direction on Linux.
    The first value of a spherical direction is practically the same as a
    @@ -683,12 +684,13 @@ SDL_SYS_ToDirection(SDL_HapticDirection
    –> add 9000
    –> finally add 18000 and convert to [0,0xFFFF] as in case SDL_HAPTIC_POLAR.
    */
  •        tmp = ((dir->dir[0]) + 9000) % 36000;    /* Convert to polars */
    
  •        tmp = ((src->dir[0]) + 9000) % 36000;    /* Convert to polars */
       tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /* convert to range [0,0xFFFF] */
    
  •    return (Uint16) tmp;
    
  •    *dest = (Uint16) tmp;
    
  •    break;
    

    case SDL_HAPTIC_CARTESIAN:

  •    f = atan2(dir->dir[1], dir->dir[0]);
    
  •    f = atan2(src->dir[1], src->dir[0]);
                   /*
                     atan2 takes the parameters: Y-axis-value and X-axis-value (in that order)
                      - Y-axis-value is the second coordinate (from center to SOUTH)
    

@@ -701,10 +703,11 @@ SDL_SYS_ToDirection(SDL_HapticDirection
/
tmp = (((int) (f * 18000. / M_PI)) + 45000) % 36000;
tmp = (((18000 + tmp) % 36000) * 0xFFFF) / 36000; /
convert to range [0,0xFFFF] */

  •    return (Uint16) tmp;
    
  •    *dest = (Uint16) tmp;
    
  •    break;
    

    default:

  •    return (Uint16) SDL_SetError("Haptic: Unsupported direction type.");
    
  •    return SDL_SetError("Haptic: Unsupported direction type.");
    

    }

    return 0;
    @@ -735,8 +738,7 @@ SDL_SYS_ToFFEffect(struct ff_effect *des

       /* Header */
       dest->type = FF_CONSTANT;
    
  •    dest->direction = SDL_SYS_ToDirection(&constant->direction);
    
  •    if (dest->direction == (Uint16) - 1)
    
  •    if (SDL_SYS_ToDirection(&dest->direction, &constant->direction) == -1)
           return -1;
    
       /* Replay */
    

@@ -771,8 +773,7 @@ SDL_SYS_ToFFEffect(struct ff_effect *des

     /* Header */
     dest->type = FF_PERIODIC;
  •    dest->direction = SDL_SYS_ToDirection(&periodic->direction);
    
  •    if (dest->direction == (Uint16) - 1)
    
  •    if (SDL_SYS_ToDirection(&dest->direction, &periodic->direction) == -1)
           return -1;
    
       /* Replay */
    

@@ -868,8 +869,7 @@ SDL_SYS_ToFFEffect(struct ff_effect *des

     /* Header */
     dest->type = FF_RAMP;
  •    dest->direction = SDL_SYS_ToDirection(&ramp->direction);
    
  •    if (dest->direction == (Uint16) - 1)
    
  •    if (SDL_SYS_ToDirection(&dest->direction, &ramp->direction) == -1)
           return -1;
    
       /* Replay */

I think you should file a bug on bugzilla.libsdl.org
It has a much nicer interface than the mailing list :wink:

Here you go:
https://bugzilla.libsdl.org/show_bug.cgi?id=2686

All the best,
EliasOn Fri, Aug 15, 2014 at 11:48 AM, Robotic-Brain wrote:

I think you should file a bug on bugzilla.libsdl.org
It has a much nicer interface than the mailing list :wink:

I think you should file a bug on bugzilla.libsdl.org
It has a much nicer interface than the mailing list :wink:

Here you go:
https://bugzilla.libsdl.org/show_bug.cgi?id=2686

These are in revision control now! Thanks again!

–ryan.

No problem!On Sat, Aug 16, 2014 at 11:03 PM, Ryan C. Gordon wrote:

I think you should file a bug on bugzilla.libsdl.org
It has a much nicer interface than the mailing list :wink:

Here you go:
https://bugzilla.libsdl.org/show_bug.cgi?id=2686

These are in revision control now! Thanks again!