Native joystick support

Hi guys,

I’m working on a cross-platform (Linux, Windows, MacOSX), plain-C library for use in reading input from joysticks and joypads, called libjstar:

http://code.google.com/p/libjstar

The idea is to develop this C-library and then wrap it in Panda, as suggested in this blueprint:

https://blueprints.launchpad.net/panda3d/+spec/joystick-support

Contributions are welcomed! :wink:

Hey, that’s great! I think it would be valuable to have native Joystick support in Panda3D (besides through VRPN or PyGame). Are you planning to make this as part of Panda, or as a separate library?

As I’ve already said, I want to make a separate library and then wrap it in Panda (in both C++ and Python implementations).

The simple API should make very easy to port it in Panda :slight_smile:

Ok, I’ve now a prototype of libjstar working on Windows and Linux. The next step is the integration into Panda code base.

The libjstar public API is simply composed by a few functions and one data structure:

/**
 * Device descriptor.
 */
typedef struct
{
    jstar_device_handle handle;
    char name[128];
    int num_buttons;
    int* buttons;
    int num_axes;
    int* axes;
} jstar_dd;

/**
 * Return the number of joystick/pad devices connected to the host machine.
 */
int jstar_count(void);

/**
 * Connect to a joystick/pad device and returns a device descriptor.
 */
jstar_dd jstar_connect(int jstar_id);

/**
 * Disconnect from a joystick/pad device.
 */
void jstar_disconnect(jstar_dd device);

/**
 * Check if a device is connected or not.
 */
int jstar_check(const jstar_dd device);

/**
 * Update the device's status.
 */
int jstar_update(jstar_dd device);

I’ve seen there is a device package which contains source files for keyboard, mouse, VR helmets, etc.

So, if I understood the Panda system, I should create a new Joystick class which inherits from DataNode. Is it correct?

Could you give me some hints about its implementation, please? :slight_smile:

Thanks!

I really don’t know anything about Panda’s data graph, sorry. I bet drwr could give you some hints there.

Sure, can you give me a day or two to get my stuff together? :slight_smile:

David

Good job on your library, and I like that it doesn’t use DirectInput on Windows. But have you considered a BSD license for it instead of LGPL? I mention it because you seem interested in Panda3D integration and it would go much better with it. My 2 cents.

@drwr: sure :wink:

@Gogg: why do you think the LGPL could cause any problems with Panda?

Zuck, panda3d is BSD. Many of us don’t like GPL and LGPL style licenses for their restrictiveness. So your library probably would not be treated with same love and kindness as a BSD version would. If the LGPL is important to you - nothing wrong with that and we respect your decision but I fear you would get the second class citizenship in the panda3d ecosystem.

No matter how this turns out, thank you for providing joystick support, we need people like you!

It’s not a problem for me…I’ve choosen the LGPL because my code in inspired by other libraries (from different 3d engines) which are GPL or LGPL.

I don’t like the GPL, but the LGPL I think could be a good license for libraries because it allows to use it even in commercial and close-source projects…But if it could be a problem, I can switch to BSD one.

zuck, we really hate to sound imposing. but yeah, if you could switch the license to bsd it would be awesome. many of us would build panda without your library and rather use something else if you kept it LGPL’d. If you have a fully BSD project, you can do some things with it that you can’t with a *GPL “tainted” project (such as using it in consoles or building statically).

You say it has LGPL/GPL dependencies, btw. I don’t see any of them in the Windows port. So I assume you must refer to the usage of kernel headers in the Linux port.

Even though the linux kernel is GPL there’s an exception, read here at the top (thanks rdb):

kernel.org/pub/linux/kernel/COPYING

I wish the language there was less vague though, it refers to system calls and it leaves wrapped code such as joystick.h in the air. In any case, this doesn’t mean anything for you, as the BSD is compatible with the GPL, and as long as your library doesn’t force LGPL terms in “mass consumption” platforms (mac, windows) I think that’s ok.

By the way, here’s a thread that talks a little about the details of implementing nodes in the Data Graph: https://discourse.panda3d.org/viewtopic.php?t=5243

David

Native joystick support would be a most welcome addition to Panda3d. I hate having people need to download Pygame to run some of my programs. As a game engine Panda3D should have joystick support natively.

Thanks for your work in this area.

The BSD finally won (but, honestly, I’m still not exactly sure why, for you, BSD license is so different, in pratical terms, from LGPL). :wink:

@drwr: Thanks for your link, it’s a good start point!

Please correct me if I am wrong, but if an LGPL library was included in Panda, panda could no longer be shipped with a BSD license.

No, it’s incorrect.

from Wikipedia:

The main difference between the GPL and the LGPL is that the latter can be linked to (in the case of a library, ‘used by’) a non-(L)GPLed program, regardless of whether it is free software or proprietary software.[1] This non-(L)GPLed program can then be distributed under any chosen terms if it is not a derivative work. If it is a derivative work, then the terms must allow “modification for the customer’s own use and reverse engineering for debugging such modifications.” Whether a work that uses an LGPL program is a derivative work or not is a legal issue. A standalone executable that dynamically links to a library is generally accepted as not being a derivative work. It would be considered a “work that uses the library” and paragraph 5 of the LGPL applies.

A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.

Essentially, if it is a “work that uses the library”, then it must be possible for the software to be linked with a newer version of the LGPL-covered program. The most commonly used method for doing so is to use “a suitable shared library mechanism for linking”. Alternatively, a statically linked library is allowed if either source code or linkable object files are provided.

One feature of the LGPL is that one can convert any LGPLed piece of software into a GPLed piece of software (section 3 of the license). This feature is useful for direct reuse of LGPLed code in GPLed libraries and applications, or if one wants to create a version of the code that cannot be used in proprietary software products.

Thanks. This is really appreciated. LGPL is actually very different than BSD, I’ll try to explain better.

  1. I repeat, you can’t use LGPL code in consoles. Console makers don’t allow it, period. This is one of the reasons Ogre3D recently changed from LGPL to MIT (Which is BSD-style).
  2. You can’t statically link a LGPL library. Incidentally, this aids cheating (think of a panda DLL with wallhacking that can be inserted in any panda game).
  3. A codebase with LGPL code has less value, because it has strings attached. So if I decide I want to sell my game in the future (not a copy, but the rights to the codebase) it will be much easier if it doesn’t have [L]GPL on it. This may be hard to believe to some but it’s true. Many businesses have a no [L]GPL policy, because when you are using [L]GPL there are costs associated with development (somebody has to make sure the company is in compliance, that means time, which means money, and that money is gonna be subtracted from your price tag.) Whereas with the BSD, it’s include and forget. You can argue all you want if this is justified or not, but this is the perception of the industry, and this perception affects the value of my code, and that part is an indisputable fact.

If my memory serves me well, panda copyright holders could mix licenses if they wanted. Of course, as an user, you’d have to comply with the LGPL if part of the code is LGPL yeah, so it would be problematic (just as it is with FFMPEG and stuff).

Gogg, thanks for your explanation! :slight_smile:

David, I need more help about “joystickDevice” implementation:

  1. should it inherit from “DataNode” or “ClientAnalogDevice”?
  2. could you provide a base header example with all required methods?

I think it should be something similar to:

#include "pandabase.h"

#include "clientAnalogDevice.h"

#include <jstar-types.h>

////////////////////////////////////////////////////////////////////
//       Class : JoystickDevice
// Description : Reads the data sent from an analogic controller
//               (joystick and similar), and transmits it down the
//               data graph.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_DEVICE JoystickDevice : public ClientAnalogDevice {
PUBLISHED:
  JoystickDevice(ClientBase *client, int device, const string &name);
  void set_source(int device);
  
public:
  string get_source_name() const;
  int get_source_num_axes() const;
  int get_source_num_buttons() const;
  
protected:
  // Inherited from DataNode
  virtual void do_transmit_data(DataGraphTraverser *trav,
                                const DataNodeTransmit &input,
                                DataNodeTransmit &output);

private:
  jstar_dd _device;

public:
  static TypeHandle get_class_type() {
    return _type_handle;
  }
  static void init_type() {
    DataNode::init_type();
    register_type(_type_handle, "JoystickDevice",
                  DataNode::get_class_type());
  }
  virtual TypeHandle get_type() const {
    return get_class_type();
  }
  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}

private:
  static TypeHandle _type_handle;
};

#endif

It should inherit from DataNode. ClientAnalogDevice is used for VRPN, and isn’t actually itself a DataNode, and therefore can’t be attached into the data graph.

Other than that, seems like a decent start. You can look at MouseAndKeyboard for more examples. Basically, you need to define the kinds of outputs it’s going to put onto the data graph: a data node can output any number of named values, and each of them is defined by an integer id number which it acquires in the constructor. MouseAndKeyboard, for instance, defines 5 outputs: _pixel_xy, which is the mouse (x, y) position in pixels, _pixel_size, which is the window size in pixels, _xy, which is the mouse (x, y) position in (-1, 1) space, _button_events, which is a list of recent mouse or keyboard button events, and _pointer_events, which is a list of recent mouse motion events.

You could generate some or all of these, for instance, you can define _pixel_xy, _pixel_size, _xy, and _button_events, so that the joystick object acts just like a mouse and can be attached into the data graph in lieu of a mouse (this way, the joystick could control the trackball view or even click on DirectGui objects if you wanted).

You could also make up some new data outputs that are unique to your joystick object. Of course, then you would also need to define one or more additional DataNodes that accept these as inputs and do something with them.

David