This chapter shows how to capture and process data from input devices, and then covers the internals of Syzygy's input framework.
Input data in Syzygy comes as three types of
1. A matrix event, a 4x4 matrix, usually represents the position and orientation (referred to in combination as the placement) of a tracking sensor.
2. An axis event contains a floating-point number representing the state of a scalar input (a slider, or one axis of a joystick).
3. A button event contains an integer, often boolean in meaning (1 or 0).
Within each class, events are identified by a zero-based index. In applications, a particular event type and index is generally associated with a particular function. For example, matrix 0 often represents the placement of the user's head, matrix 1 that of the wand. All event types have a default value reported for exceptional cases like disconnected sensors or out-of-bound indices. These are the identity matrix, 0.0, and 0 respectively.
arInputEvents can be packed into
arStructuredData records. These records
can be either the native binary format for fast transmission, or ASCII
XML for disk storage. Syzygy provides functions for converting between
arStructuredData, and for reading/writing such XML files.
Input events are organized into trees by input object classes. Input events from devices on separate branches can combine into a single event stream, corresponding to a compound virtual input device. For example, a motion-tracked gamepad can start out as two separate <input_sources> streams of data (from different computers) and then combine into a single stream.
In cluster mode, each computer with input hardware runs its own DeviceServer. Each DeviceServer has a service name corresponding to a group of Syzygy database parameters, determined by the device driver it is running. To listen to that device through a particular IP address and port, an application checks this group of database parameters. Here is a list of supported input devices.
New in Syzygy 1.2: Applications running in Standalone Mode can now load device drivers.
Finally, there are classes and functions for how the user interacts with objects in the virtual world: grabbing, various kinds of dragging, and hooks for implementing other user-initiated object manipulation.
The input framework has two programs that produce input events.
device-driver libraries. The second,
is a GUI emulating a traditional VR tracked wand and head. Both publish
their input events on the network for other Syzyzy programs to read.
The generic event-reader DeviceClient can listen to either of these two
and print out the events it receives.
DeviceServer -s [-netinput] driver_name input_slot [pforth_program]
The flag -s indicates Simple mode: DeviceServer loads only driver_name, rather than a whole pile of device drivers (an "input node configuration".)
The integer input_slot specifies which slot DeviceServer transmits on. In a cluster of PCs, slots are like CB radio channels. Given a slot, at most one DeviceServer transmits on it and arbitrarily many programs (such as DeviceClients) can listen to it.
The string pforth_program is a global parameter whose text is a PForth program used to filter input events from driver_name.
The flag -netinput makes DeviceServer listen for events from the network. on input_slot+1.
DeviceServer [-netinput] node_config_name input_slot [pforth_program_name]
Without "-s driver_name," DeviceServer instead uses the configuration of input nodes defined in the global parameter node_config_name.
Run DeviceClient on the same computer to see the events sent by that DeviceServer. If you pick a different input_slot, of course, the DeviceClient will "tune to a different station" and listen to any DeviceServer transmitting on that slot.
Plug a joystick or gamepad into a computer. On that computer, dlogin to the cluster and run:
DeviceServer -s arJoystickDriver 0
DeviceServer runs until you ctrl+C or dkill it. It won't run, though, if another DeviceServer is already transmitting on input slot 0. (In that case, pick a slot different from 0.) From another shell, type:
DeviceClient prints the raw joystick events. Mashing buttons and twiddling the joystick should make the numbers change. If not, see Troubleshooting.
You can run extra copies of
DeviceClient 0 on other computers where you're dlogin'd, too.
<param> <name> joystick_scaledown </name> <value> define filter_axis_0 getCurrentEventAxis 0.000031 * setCurrentEventAxis enddef define filter_axis_1 getCurrentEventAxis -0.000031 * setCurrentEventAxis enddef </value> </param>
Kill the old DeviceServer and run that dbatch file. DeviceClients may keep running. This new DeviceServer scales down two joystick axes by a factor of 32768, and reverses axis 1:
DeviceServer -s arJoystickDriver 0 joystick_scaledown
Here is a simple example of an input node configuration for DeviceServer:
<param> <name> idesk_tracker </name> <value> <szg_device> <input_sources> arSpacepadDriver arJoystickDriver </input_sources> <input_filters> </input_filters> <input_sinks> </input_sinks> <pforth> </pforth> </szg_device> </value> </param>
The fields <input_sources>, <input_filters>, and <input_sinks> each contain a list of libraries (DLL's or so's) on the SZG_EXEC/path, for example arMotionstarDriver.so. The filename's suffix is omitted, for OS independence. C++ classes defined in these three fields are subclasses of arInputSource, arIOFilter, and arInputSink respectively.
Given this global parameter in a dbatch file, and a computer with a Spacepad and joystick, typing this:
DeviceServer idesk_tracker 0
configures the DeviceServer with the global parameter named idesk_tracker. DeviceServer thus loads the two libraries listed in <input_sources>, and then transmits events from the Spacepad and joystick on slot 0.
At most one DeviceServer runs on one computer. If a computer has several input devices (here, a Spacepad and a joystick), put multiple entries in the input_sources field like this instead of trying to run multiple DeviceServers.
The field <pforth> contains a PForth program to filter data from the input sources, before the data reaches the chain of input_filters and finally the input_sinks. If left empty as here, obviously no special filtering happens.
For a HowTo about getting your tracker data mapped in to Syzygy coordinates, see Tracker Coordinate Conversion