treeform / windy

Windowing library for Nim using OS native APIs.
MIT License
117 stars 16 forks source link

Gamepad support #102

Open konsumer opened 1 year ago

konsumer commented 1 year ago

I really like windy's support of keyboard/mouse, but for making a game-engine I want to support gamepads, primarily.

I made a light wrapper for libstem_gamepad, which is made in C, and works on Windows, Linux, and OSX. I could make it feel a bit more like windy's state-helpers (like buttonPressed / buttonDown / buttonReleased / buttonToggle) and make a PR to include this, if there is interest. Is there a more nim-ish way to do this? Is this outside the scope of what windy is trying to do?

Usage currently looks like this:

let windowSize = ivec2(320, 240)
let window = newWindow("null0", windowSize)
makeContextCurrent(window)
loadExtensions()

proc onGamepadAttached(device: ptr Gamepad_device; context: pointer) =
  var js = device[]
  echo "attached: " & $js.deviceID

proc onGamepadRemoved(device: ptr Gamepad_device; context: pointer) =
  var js = device[]
  echo "removed: " & $js.deviceID

proc onButtonDown (device: ptr Gamepad_device; buttonID: cuint; timestamp: cdouble; context: pointer) =
  var js = device[]
  echo "buttonDown(" & $js.deviceID & "): " & $buttonID

proc onButtonUp (device: ptr Gamepad_device; buttonID: cuint; timestamp: cdouble; context: pointer) =
  var js = device[]
  echo "buttonUp(" & $js.deviceID & "): " & $buttonID

proc onAxisMoved (device: ptr Gamepad_device; axisID: cuint; value: cfloat; lastValue: cfloat; timestamp: cdouble; context: pointer) =
  var js = device[]
  echo "axis(" & $js.deviceID & "): " & $axisID & " : " & $value

const GAMEPAD_POLL_ITERATION_INTERVAL=30
gamepad.deviceAttachFunc(onGamepadAttached)
gamepad.deviceRemoveFunc(onGamepadRemoved)
gamepad.buttonDownFunc(onButtonDown)
gamepad.buttonUpFunc(onButtonUp)
gamepad.axisMoveFunc(onAxisMoved)
gamepad.init()

var iterationsToNextPoll = GAMEPAD_POLL_ITERATION_INTERVAL
while not window.closeRequested:
  pollEvents()
  dec iterationsToNextPoll
  if iterationsToNextPoll == 0:
    gamepad.detectDevices()
    iterationsToNextPoll = GAMEPAD_POLL_ITERATION_INTERVAL
  gamepad.processEvents()
konsumer commented 1 year ago

Running in Github actions, I realized the windows build-flags probably need some work, so I could use some help testing/tuning:

when defined(windows):
  {.compile: "vendor/gamepad/source/gamepad/Gamepad_windows_dinput.c".}
  {.compile: "vendor/gamepad/source/gamepad/Gamepad_windows_mm.c".}
  {.passC: "-DFREEGLUT_STATIC -I C://MinGW//dx9//include".}
  {.passL: "C://MinGW//dx9//lib//x64//Xinput.lib C://MinGW//dx9//lib//x64//dinput8.lib C://MinGW//dx9//lib//x64//dxguid.lib C://MinGW//WinSDK//Lib//x64//WbemUuid.Lib C://MinGW//WinSDK//Lib//x64//Ole32.Lib C://MinGW//WinSDK//Lib//x64//OleAut32.Lib".}

This seems to work on fresh OSX, though, and Linux is fine:

when defined(macosx):
  {.compile: "vendor/gamepad/source/gamepad/Gamepad_macosx.c".}
  {.passL: "-framework IOKit".}
konsumer commented 1 year ago

I ended up making a separate library. It still doesn't build right for windows, but I will try to set aside some to get it working this weekend. I have published it for nimble, but am happy to modify to make it fit better with windy, if there is interest.

Update: I got it building for Windows, so I think it's basically ready to go. I will use that for my thing, for now, but would be happy to make it more windy-ish.

treeform commented 1 year ago

Wow this is pretty cool! I like that you are makin the game pad support. We don't need it the moment, but I can see us needing this in the future!

konsumer commented 1 year ago

I could use some help publishing it, I am very new to nim. It builds fine, but if I try to install it in my test project from nimble, it says the C files are missing. I am probably missing some small thing in the nimble file. @treeform you have published a ton of packages, any hints?

Update: I think I fixed that too. It seems like nimble was not resolving the include correctly. I just changed all the includes in the C files, and it's working great.