There are many types of input devices that VR Juggler
application objects can use including positional, digital, and
analog. All application objects share the same processes and
concepts for acquiring input from devices. The main thing to remember
about getting input in applications is that all VR Juggler
applications receive input through device proxies managed by
gadget::DeviceInterface<T> instantiations. There are
gadget::DeviceInterface<T> instantiations
for each type of input data that Gadgeteer can handle. There is one
for positional input, one for analog, and so on. In this section, we
will only demonstrate the use of position and digital device
interfaces. Refer to the section called “Device Proxies and Device Interfaces”
for more detailed information on the use of all the available device
interfaces.
While there has already been a brief presentation about getting input in an application, we need something more. Since all device interfaces look the same, we will focus on an example of getting positional input. All other types are very similar. We begin with a simple application object skeleton.
class myApp : public vrj::App
{
public:
init();
preFrame();
private:
gadget::PositionInterface mWand;
}Note the declaration of the variable mWand
of type gadget::PositionInterface. This is
the first addition to an application. Device interfaces are usually
member variables of the user application class, as in this
example.
myApp::init()
{
mWand.init("NameOfPosDevInConfiguration");
}The device interface has to be told about the device from
which it will get data. This is done by calling the device interface
object's init() method with the symbolic
string name of the device. This device name comes from the active
configuration. We are now ready to read from the device.
... const float units = getDrawScaleFactor(); gmtl::Matrix44f wand_pos(mWand->getData(units)); ...
The above code shows an example of using the positional device interface in an application. It shows some sample code where the application copies the positional information from a device interface. When it is dereferenced, the device interface figures out what device it points to and returns the data from that device. Again, refer to the section called “Device Proxies and Device Interfaces” for more information about using device proxies and device interfaces.
In the previous section, we showed how to get input from devices, but we never said where to put the code. The location, surprisingly, is application dependent. There are some very good guidelines regarding where applications should process input. Before explaining them, however, we should review the VR Juggler kernel control loop, presented again in Figure 4.1, “VR Juggler kernel control loop”.
This diagram looks complicated, but the key here is the
updateAllData() call near the bottom of the
diagram. This is where the Gadgeteer Input Manager updates all the
cached device data that will be used in drawing the next frame. This
updated copy is used by all user references to device data until the
next update and the end of the next frame of execution.
This means two things:
The device data is most fresh in
vrj::App::preFrame(), and
Any time spent in
vrj::App::preFrame() increases the
overall system latency.
The first point is important because it means that the copy of
the device data with the lowest latency is always available in the
preFrame() member function. The second
point is equally important because it says why user applications
should not waste any time in preFrame().
Any time spent in preFrame() increases
system latency and in turn decreases the perceived quality of the
environment. Hence, it is crucial to avoid placing computations in
preFrame().
In this section, we present a tutorial that demonstrates simple input handling using Gadgeteer device interfaces. The tutorial overview is as follows:
Description: Simple application that prints the location of the head and the wand.
Objective: Understand how to get positional and digital input in a VR Juggler application.
Member functions:
vrj::App::init(),
vrj::App::preFrame()
Directory:
$VJ_BASE_DIR/share/samples/OGL/simple/simpleInput
Files: simpleInput.h,
simpleInput.cpp
In the following class declaration, note the data members
(mWand, mHead, etc.). This
application has four device interface member variables: two for
positional input (mHead and
mWand) and two for digital input
(mButton0 and mButton1).
Each of these member variables will act as a handle to a
“real” device from which we will read data in
preFrame().
1 class simpleInput : public vrj::GlApp
{
public:
virtual void init();
5 virtual void preFrame();
public:
gadget::PositionInterface mWand; // Positional interface for Wand position
gadget::PositionInterface mHead; // Positional interface for Head position
10 gadget::DigitalInterface mButton0; // Digital interface for button 0
gadget::DigitalInterface mButton1; // Digital interface for button 1
};The devices are initialized in the
init() member function of the
application. For each device interface member variable, the
application calls the variable's own
init() method. The argument passed is the
symbolic name of the configured device from which data will be
read. From this point on in the application, the member variables
are handles to the named device.
1 virtual void init()
{
// Initialize devices
mWand.init("VJWand");
5 mHead.init("VJHead");
mButton0.init("VJButton0");
mButton1.init("VJButton1");
}The following member function implementation gives an example of how to examine the input data using the device interface member variables.
1 virtual void preFrame()
{
if ( mButton0->getData() )
{
5 std::cout << "Button 0 pressed" << std::endl;
}
if( mButton1->getData() )
{
std::cout << "Button 1 pressed" << std::endl;
10 }
std::cout << "Wand Buttons:"
<< " 0:" << mButton0->getData()
<< " 1:" << mButton1->getData()
15 << std::endl;
// -- Get Wand matrix --- //
const float units = getDrawScaleFactor();
gmtl::Matrix44f wand_matrix(mWand->getData(units));
20 std::cout << "Wand pos: \n" << wand_matrix << std::endl;
}![]() | These statements check the status of the two digital buttons and write out a line if the button has been pressed. |
![]() | This writes out the current state of both buttons. |
![]() | The final section prints out the current location of the wand in the VR environment. |