Porting from VR Juggler 2.2 to 3.0

This document describes the process of updating VR Juggler 2.2 applications to VR Juggler 3.0. VR Juggler 2.0 users should read the 2.0 to 2.2 Migration Guide first. Considerations for VR Juggler 2.0 applications and configurations will not be made in this document.

Configuration Changes

IMPORTANT: All VR Juggler 2.2 configuration files must be updated using an XSLT processor prior to being loaded into VRJConfig for automatic upgrading. Changes to the cluster configuration have been made that cannot be expressed using the automatic updating capabilities, and thus off-line updates are required as the first step.

The transform is in the file modules/vrjuggler/data/xslt/2.2-2.3.xsl (or $VJ_BASE_DIR/share/vrjuggler-3.0/data/xslt/2.2-2.3.xsl), and it should be applied to all VR Juggler 2.2 configuration files. Instructions for using this transform can be found in the file after the copyright notice. The sample configuration files that come with VR Juggler have been updated.

For other configuration changes, VRJConfig can be used to migrate config elements to newer versions automatically, and it is recommended that all VR Juggler 2.2 configuration files be loaded into VRJConfig and saved using the "Save All" button. For sites that need to maintain configuration files for both versions, the VR Juggler 2.2 files should be copied into a new location for use by VR Juggler 3.0.

Gadgeteer Interface Changes

IMPORTANT: The Gadgeteer version number can be used at compile time to make decisions about which version of the API will be needed. The version number is available using the preprocessor symbol __GADGET_version, defined in gadget/gadgetParam.h. The encoding is based on the major, minor, and patch version numbers using the scheme MMMmmmPPP (three digits for the major version number, three for the minor, and three for the patch) with left zero padding. For example, Gadgeteer version 1.3.15 is encoded as 1003015. Code examples below will make use of __GADGET_version to demonstrate how to write code that works with Gadgeteer 1.2 and 2.0.

In many ways, Gadgeteer is the heart of the Juggler Suite. It handles input, and input drives VR applications. More than that, the cluster infrastructure, which is based on synchronized input data distribution, is part of Gadgeteer. The cluster infrastructure has been rewritten in Gadgeteer 2.0 to be based on a client/server model.

Device Drivers

Subclasses of gadget::Input need no longer overload operator delete and override gadget::Input::destroy(). This was deemed unnecessary and removed in Gadgeteer 1.3.11 (encoded as the __GADGET_version value 1003011).

Mouse Event Coordinate Frame

Prior to Gadgeteer 2.0, mouse events associated with a keyboard/mouse device utilized a coordinate frame with an origin at the upper left-hand corner of the window (or the display for root-level mouse positions). This was in contrast to the window positioning convention of using the lower left-hand corner as the origin. To resolve this discrepancy, the mouse event code was changed in Gadgeteer 1.3.16 (encoded as the __GADGET_version value 1003016) to use the lower left-hand corner as the origin. Thus, code using the X,Y coordinates from gadget::MouseEvent objects must be updated to reflect the inverted Y-axis values.

Shared Pointer Usage

Many uses of raw pointers in Gadgeteer have been replaced with instantiations of boost::shared_ptr<T>. The following list shows the classes, according to inheritance hierarchy, that are now accessed as boost::shared_ptr<T> instantiations:

  • gadget::Input as gadget::InputPtr for Gadgeteer 1.3.4 (__GADGET_version value 1003004) and newer
    • gadget::Analog as gadget::AnalogPtr
    • gadget::Command as gadget::CommandPtr
    • gadget::Digital as gadget::DigitalPtr
    • gadget::Gesture as gadget::GesturePtr
    • gadget::Glove as gadget::GlovePtr
    • gadget::KeyboardMouse as gadget::KeyboardMousePtr
    • gadget::Position as gadget::PositionPtr
    • gadget::String as gadget::StringPtr
  • gadget::Proxy as gadget::ProxyPtr for Gadgeteer 1.3.5 (__GADGET_version value 1003005) and newer
    • gadget::AnalogProxy as gadget::AnalogProxyPtr
    • gadget::CommandProxy as gadget::CommandProxyPtr
    • gadget::DigitalProxy as gadget::DigitalProxyPtr
    • gadget::GestureProxy as gadget::GestureProxyPtr
    • gadget::GloveProxy as gadget::GloveProxyPtr
    • gadget::KeyboardMouseProxy as gadget::KeyboardMouseProxyPtr
    • gadget::PositionProxy as gadget::PositionProxyPtr
    • gadget::StringProxy as gadget::StringProxyPtr

Most application-level code probably does not retain pointers to device or proxy instances. Normally, device proxy objects are accessed through automatically constructed temporary variables through usage of gadget::DeviceInterface<T>::operator->(). Input device instances can be retrieved either through the Input Manager singleton or through a device proxy object.

Nevertheless, it is valid for application code to have data members, stack variables, global variables, etc. that are pointers to Gadgeteer device instances and/or device proxy instances. The code shown below will work with all Gadgeteer versions between 1.0 and 2.0. The #if usage can be simplified by not worrying about Gadgeteer 1.3.x versions and simply testing against the 2.0.0 value (2000000).

#include <gadget/InputManager.h>
#include <gadget/Position.h>
#include <gadget/PositionProxy.h>
#include <gadget/gadgetParam.h>


#if __GADGET_version < 2000000
namespace gadget
{
#if __GADGET_version < 1003004
   typedef Input*         InputPtr;
   typedef Position*      PositionPtr;
#endif
#if __GADGET_version < 1003005
   typedef Proxy*         ProxyPtr;
   typedef PositionProxy* PositionProxyPtr;
#endif
}
#endif

void MyApp::preFrame()
{
   // Input device query.
   gadget::InputPtr dev =
      gadget::InputManager::instance()->getDevice("Some Device");

   // Downcast to a positional device instance.
   gadget::PositionPtr pos_dev =
#if __GADGET_version < 1003004
      dynamic_cast<gadget::PositionPtr>(dev);
#else
      boost::dynamic_pointer_cast<gadget::Position>(dev);
#endif

   // Proxy query.
   gadget::ProxyPtr proxy =
      gadget::InputManager::instance()->getProxy("Pos Proxy");

   // Downcast to a position proxy.
   gadget::PositionProxyPtr pos_proxy =
#if __GADGET_version < 1003005
      dynamic_cast<gadget::PositionProxyPtr>(proxy);
#else
      boost::dynamic_pointer_cast<gadget::PositionProxy>(proxy);
#endif

   // Rest of preFrame() ...
}

VR Juggler Interface Changes

IMPORTANT: The VR Juggler version number can be used at compile time to make decisions about which version of the API will be needed. The version number is available using the preprocessor symbol __VJ_version, defined in vrj/vrjParam.h. The encoding is based on the major, minor, and patch version numbers using the scheme MMMmmmPPP (three digits for the major version number, three for the minor, and three for the patch) with left zero padding. For example, VR Juggler version 2.3.15 is encoded as 2003015. Code examples below will make use of __VJ_version to demonstrate how to write code that works with VR Juggler 2.2 and 3.0.

New main() Function Step

VR Juggler 3.0 clustered applications must identify whether the application instance is the server or one of the clients. This is done using a command line option at launch time: either --vrjmaster or --vrjslave. In order for the kernel to know about the command line option, one of the vrj::Kernel::init() overloads must be invoked before any calls to vrj::Kernel::loadConfigFiles() or vrj::Kernel::start(). Moreover, vrj::Kernel::start() must not be called before configuration files are loaded—unless remote run-time reconfiguration is used to configure VR Juggler.

There are two ways to initialize the kernel from the application main() function. Both were introduced in VR Juggler 2.3.0 (encoded as the __VJ_version value 2003000). The first is suitable for the case when the application does not process command line options other than a list of VR Juggler configuration files. In this case, we use the vrj::Kernel::init(int&,char*[]) initialization method. This is demonstrated in the code below.

#include <cstdlib>
#include <vrj/Kernel.h>
#include <vrj/vrjParam.h>


int main(int argc, char* argv[])
{
   vrj::Kernel* kernel = vrj::Kernel::instance();
   MyApp* app = new MyApp();

#if ! defined(VRJ_USE_COCOA)
   if ( argc <= 1 )
   {
      std::cerr << "Missing command line options\n";
      return EXIT_FAILURE;
   }
#endif

#if __VRJ_version >= 2003000
   // Initialize the kernel.
   kernel->init(argc, argv);
#endif

   // Load any config files specified on the command line
   for ( int i = 1; i < argc; ++i )
   {
      kernel->loadConfigFile(argv[i]);
   }

   kernel->start();
   kernel->setApplication(app);
   kernel->waitForKernelStop();

   delete app;

   return EXIT_SUCCESS;
}

Draw Manager Namespaces