Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement controller rumble support to ui/Gamepad #1739

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions project/include/ui/Gamepad.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ namespace lime {
static void AddMapping (const char* content);
static const char* GetDeviceGUID (int id);
static const char* GetDeviceName (int id);

static void Rumble(int id, int duration, double largeStrength, double smallStrength);

};

Expand Down
16 changes: 16 additions & 0 deletions project/src/ExternalInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1678,6 +1678,20 @@ namespace lime {
}


void lime_gamepad_rumble (int id, int duration, double largeStrength, double smallStrength) {

Gamepad::Rumble (id, duration, largeStrength, smallStrength);

}


HL_PRIM void HL_NAME(hl_gamepad_rumble) (int id, int duration, double largeStrength, double smallStrength) {

Gamepad::Rumble (id, duration, largeStrength, smallStrength);

}


value lime_gzip_compress (value buffer, value bytes) {

#ifdef LIME_ZLIB
Expand Down Expand Up @@ -3970,6 +3984,7 @@ namespace lime {
DEFINE_PRIME2v (lime_gamepad_event_manager_register);
DEFINE_PRIME1 (lime_gamepad_get_device_guid);
DEFINE_PRIME1 (lime_gamepad_get_device_name);
DEFINE_PRIME4v (lime_gamepad_rumble);
DEFINE_PRIME2 (lime_gzip_compress);
DEFINE_PRIME2 (lime_gzip_decompress);
DEFINE_PRIME2v (lime_haptic_vibrate);
Expand Down Expand Up @@ -4159,6 +4174,7 @@ namespace lime {
DEFINE_HL_PRIM (_VOID, hl_gamepad_event_manager_register, _FUN(_VOID, _NO_ARG) _TGAMEPAD_EVENT);
DEFINE_HL_PRIM (_BYTES, hl_gamepad_get_device_guid, _I32);
DEFINE_HL_PRIM (_BYTES, hl_gamepad_get_device_name, _I32);
DEFINE_HL_PRIM (_VOID, hl_gamepad_rumble, _I32 _I32 _F64 _F64);
DEFINE_HL_PRIM (_TBYTES, hl_gzip_compress, _TBYTES _TBYTES);
DEFINE_HL_PRIM (_TBYTES, hl_gzip_decompress, _TBYTES _TBYTES);
DEFINE_HL_PRIM (_VOID, hl_haptic_vibrate, _I32 _I32);
Expand Down
74 changes: 54 additions & 20 deletions project/src/backend/sdl/SDLGamepad.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,47 @@
namespace lime {


std::map<int, SDL_GameController*> gameControllers = std::map<int, SDL_GameController*> ();
std::map<int, int> gameControllerIDs = std::map<int, int> ();
std::map<int, SDLGamepad> gameControllers;
std::map<int, int> gameControllerIDs;

void SDLGamepad::Rumble(int duration, double largeStrength, double smallStrength) {
// Make sure game controller is open
if (gameController == nullptr)
return;

// Rumble controller
if (smallStrength < 0.0f)
smallStrength = 0.0f;
else if (smallStrength > 1.0f)
smallStrength = 1.0f;

if (largeStrength < 0.0f)
largeStrength = 0.0f;
else if (largeStrength > 1.0f)
largeStrength = 1.0f;

if (duration < 0)
duration = 0;
else if (duration > 0xFFFF)
duration = 0xFFFF;

SDL_GameControllerRumble(gameController, largeStrength * 0xFFFF, smallStrength * 0xFFFF, duration);
}

// SDL static gamepad API

bool SDLGamepad::Connect (int deviceID) {

if (SDL_IsGameController (deviceID)) {

SDL_GameController *gameController = SDL_GameControllerOpen (deviceID);
SDL_GameController *gameController = SDL_GameControllerOpen(deviceID);

if (gameController) {
if (gameController != nullptr) {

SDL_Joystick *joystick = SDL_GameControllerGetJoystick (gameController);
int id = SDL_JoystickInstanceID (joystick);
SDL_Joystick *joystick = SDL_GameControllerGetJoystick(gameController);
int id = SDL_JoystickInstanceID(joystick);

gameControllers[id] = gameController;
gameControllers[id] = std::move(SDLGamepad(gameController));
gameControllerIDs[deviceID] = id;

return true;
Expand All @@ -35,12 +60,9 @@ namespace lime {

bool SDLGamepad::Disconnect (int id) {

if (gameControllers.find (id) != gameControllers.end ()) {

SDL_GameController *gameController = gameControllers[id];
SDL_GameControllerClose (gameController);
gameControllers.erase (id);
if (gameControllers.find(id) != gameControllers.end()) {

gameControllers.erase(id);
return true;

}
Expand All @@ -57,6 +79,7 @@ namespace lime {
}


// Gamepad API
void Gamepad::AddMapping (const char* content) {

SDL_GameControllerAddMapping (content);
Expand All @@ -65,8 +88,11 @@ namespace lime {


const char* Gamepad::GetDeviceGUID (int id) {

SDL_Joystick* joystick = SDL_GameControllerGetJoystick (gameControllers[id]);
auto it = gameControllers.find(id);
if (it == gameControllers.end())
return nullptr;

SDL_Joystick* joystick = SDL_GameControllerGetJoystick (it->second.gameController);

if (joystick) {

Expand All @@ -76,16 +102,24 @@ namespace lime {

}

return 0;
return nullptr;

}


const char* Gamepad::GetDeviceName (int id) {

return SDL_GameControllerName (gameControllers[id]);

auto it = gameControllers.find(id);
if (it == gameControllers.end())
return nullptr;

return SDL_GameControllerName(it->second.gameController);
}


}
void Gamepad::Rumble (int id, int duration, double largeStrength, double smallStrength) {
auto it = gameControllers.find(id);
if (it == gameControllers.end())
return;

it->second.Rumble(duration, largeStrength, smallStrength);
}
}
19 changes: 19 additions & 0 deletions project/src/backend/sdl/SDLGamepad.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,30 @@ namespace lime {
class SDLGamepad {

public:
SDL_GameController *gameController = nullptr;

SDLGamepad() {}
SDLGamepad(SDL_GameController *_gameController) : gameController(_gameController) {}

~SDLGamepad() {
// Close controller if opened
if (gameController != nullptr)
SDL_GameControllerClose(gameController);
}

void Rumble(int duration, double largeStrength, double smallStrength);

static bool Connect (int deviceID);
static int GetInstanceID (int deviceID);
static bool Disconnect (int id);

SDLGamepad &operator=(SDLGamepad &&other)
{
SDL_GameController *temp = gameController;
gameController = other.gameController;
other.gameController = temp;
return *this;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be clearer to define a Swap() function instead of overriding an operator?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was this the final thing that needed to be addressed for this PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know about "final" or otherwise. This was just something I was curious about.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, op overloading does seem to make, otherwise seemingly straightforward code have oddly obfuscated behavior

};


Expand Down
7 changes: 7 additions & 0 deletions src/lime/_internal/backend/native/NativeCFFI.hx
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ class NativeCFFI

@:cffi private static function lime_gamepad_get_device_name(id:Int):Dynamic;

@:cffi private static function lime_gamepad_rumble(id:Int, duration:Int, largeStrength:Float, smallStrength:Float):Void;

@:cffi private static function lime_gamepad_event_manager_register(callback:Dynamic, eventObject:Dynamic):Void;

@:cffi private static function lime_gzip_compress(data:Dynamic, bytes:Dynamic):Dynamic;
Expand Down Expand Up @@ -448,6 +450,8 @@ class NativeCFFI
false));
private static var lime_gamepad_get_device_name = new cpp.Callable<Int->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_gamepad_get_device_name", "io",
false));
private static var lime_gamepad_rumble = new cpp.Callable<Int->Int->Float->Float->cpp.Void>(cpp.Prime._loadPrime("lime", "lime_gamepad_rumble", "iiddv",
false));
private static var lime_gamepad_event_manager_register = new cpp.Callable<cpp.Object->cpp.Object->cpp.Void>(cpp.Prime._loadPrime("lime",
"lime_gamepad_event_manager_register", "oov", false));
private static var lime_gzip_compress = new cpp.Callable<cpp.Object->cpp.Object->cpp.Object>(cpp.Prime._loadPrime("lime", "lime_gzip_compress", "ooo",
Expand Down Expand Up @@ -680,6 +684,7 @@ class NativeCFFI
private static var lime_gamepad_add_mappings = CFFI.load("lime", "lime_gamepad_add_mappings", 1);
private static var lime_gamepad_get_device_guid = CFFI.load("lime", "lime_gamepad_get_device_guid", 1);
private static var lime_gamepad_get_device_name = CFFI.load("lime", "lime_gamepad_get_device_name", 1);
private static var lime_gamepad_rumble = CFFI.load("lime", "lime_gamepad_rumble", 4);
private static var lime_gamepad_event_manager_register = CFFI.load("lime", "lime_gamepad_event_manager_register", 2);
private static var lime_gzip_compress = CFFI.load("lime", "lime_gzip_compress", 2);
private static var lime_gzip_decompress = CFFI.load("lime", "lime_gzip_decompress", 2);
Expand Down Expand Up @@ -1012,6 +1017,8 @@ class NativeCFFI
return null;
}

@:hlNative("lime", "hl_gamepad_rumble") private static function lime_gamepad_rumble(id:Int, duration:Int, largeStrength:Float, smallStrength:Float):Void {}

@:hlNative("lime", "hl_gamepad_event_manager_register") private static function lime_gamepad_event_manager_register(callback:Void->Void,
eventObject:GamepadEventInfo):Void {}

Expand Down
13 changes: 13 additions & 0 deletions src/lime/ui/Gamepad.hx
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,17 @@ class Gamepad
return null;
#end
}

// Rumble
public inline function rumble(duration:Int, largeStrength:Float, smallStrength:Float):Void
{
#if (lime_cffi && !macro)
NativeCFFI.lime_gamepad_rumble(this.id, duration, largeStrength, smallStrength);
#elseif (js && html5)
// TODO: HTML5 Rumble
return;
#else
return;
#end
}
}