SpaceNavigator Support for Sauerbraten

SpaceNavigator I recently got a 3dconnexion SpaceNavigator after trying a friend’s. Really neat device. 6 degrees of freedom in a slick little package, and only $50. And it’s actually fun to use – not frustrating and cheap-feeling like many other “weird” input devices I’ve tried. Its big brother is the same knob with some extra buttons – for only $400. Yikes. Yet I’m beginning to see why you might want to upgrade…

Anyway, I did a lame integration with Sauerbraten, an open-source 3d engine, under Win32 against the 3dconnexion SDK. The integration is pretty simple – even crude. This is another code post, skip if you’re not a techy! :)


First, grab this file (spaceNav.cpp) and add it to the Sauerbraten project. Then add a COM reference to the TDxInput that ships with the 3d connexion SDK (which you can download here). Finally, go to engine/main.cpp and add:

extern void spaceNav_start();
extern void spaceNav_poll();

void updateCameraFromSpaceNav(float tX, float tY, float tZ, float rX, float rY, float rZ, float rAngle)
{
   // Construct a matrix from our cur yaw/pitch/roll
   matrix m(vec(1,0,0), vec(0,1,0), vec(0,0,1));

   m.rotate(-camera1->yaw * RAD,   vec(0,0,1));

   m.X.mul(tX / 10.f);
   m.Y.mul(-tY / 10.f);
   m.Z.mul(tZ / 10.f);

   camera1->vel.add(m.X);
   camera1->vel.add(m.Y);
   camera1->vel.add(m.Z);
}

Right before the main function (around line 434).

Right after the line that reads:

    SDL_ShowCursor(0);

Add:

    spaceNav_start();

And around line 630, inside the for(;;), add:

               spaceNav_poll();

You can bind to the SpaceNavigator buttons by setting up keymaps like…

keymap -131 SPACENAV_LEFT

…and similar to a cfg file that gets executed when Sauerbraten starts up – I used keymap.cfg. Then you can bind to SPACENAV_LEFT and execute whatever commands you like. The binding uses button ids -100 through -132. 31 and 32 are the two buttons on the SpaceNavigator. On other 3dconnexion products there are more buttons and thus you can make use of the other binds.

And that’s it. spaceNav_start() loads up the SpaceNavigator COM object, Connect()s to the driver, and sets some global. spaceNav_poll() queries state and calls updateCameraFromSpaceNav() with the current state. It also dispatches to keypress() when a button is hit so the console can deal with binds.

Known issues:

  • Not networked properly. I’m just stuffing into the camera1 entity’s velocity field. It’s good enough to edit with, which is what I want.
  • Not based on frame time, so will give different behavior based on framerate.
  • No rotation. Since you have to aim with the mouse anyway this didn’t seem like a big need, but if someone made clicking independent of heading it could be a really useful feature… It does take the yaw into account when translating so you can fly around pretty well.
  • Not configurable. You can tweak the code in updateCameraFromSpaceNav to change how/how fast you move but it would be better to have that all be console-controllable.

Conclusion

I hope this is useful to someone! Feel free to do what you like with this code. Sauerbraten is under zlib, and 3d connexion SDK probably has some restrictions, too.

Author: Ben Garney

See https://bengarney.com/ and @bengarney for details.