Many GLUT applications can be easily turned into Master/Slave applications. A first step is creating a build environment that is compatible with Syzygy. The build template contained in szg/skeleton is discussed in the final section of the Compiling C++ Programs chapter.

szg/skeleton/src contains two simple master/slave programs. For some other examples, see the following demos in szg/src/demo:

Here is a general overview of the steps necessary to do a quick and dirty port:

In the source file containing main(),

  #include "arMasterSlaveFramework.h"

If you use any of the glut rendering functions (e.g. glutSolidTeapot()), also:

  #include "arGlut.h"

Please note that these are the only legal GLUT functions in a Syzygy program. Use any of the window/event-related GLUT functions and your program will go down in flames.

In main(),

  arMasterSlaveFramework framework;
  if( !framework.init( argc, argv ) ) {
    return 1;
  framework->setStartCallback( ... );
  framework->setWindowStartGLCallback( ... );
  framework->setPreExchangeCallback( ... );
  framework->setDrawCallback( ... );
  framework->setKeyboardCallback( ... );

Generally speaking, the init() function of your GLUT program should be split between the first two callbacks. Application-global initialization should go into the start callback (which should return true). OpenGL state initialization should go into the WindowStartGL callback. The start callback is called once in the body of the framework's start() method (which does not return) while the WindowStartGL callback is called once upon each window creation.

Sometimes computations and data exchanges need to occur before the scene is drawn. Computations whose results need to propagated from master to slave should occur in the framework's preExchangeCallback(...), which occurs before the data sharing exchange between master and slaves. These computations might, for instance, transform input events into navigational information. On the other hand, if each slave bases its actions on the next input event, then work might occur in the postExchangeCallback(...), which occurs after the data sharing exchange between masters and slaves.

Please note that only the master does the preExchange during an event loop, while the master and all slaves connected to a master do the postExchange. Unconnected slaves do not do the postExchange.

The user-defined display callback should go into the draw callback of the framework. This, and the WindowStartGL callback should be the only two places in the application where OpenGL calls are made.

The keyboard callback is only available when running in Standalone Mode; for running in a cluster, you'll want to convert your program to change state based on button events polled using e.g. the framework's getOnButton() method (see Programming) in the pre-exchange.

After the framework has been initialized and all necessary callbacks registered, the event loop needs to be set in motion:

  if( !framework.start() ) {
    return 1;
  // not reached, start() does not return unless an error occurred

If framework.start() is called from another thread, at the end of main do

  while( true ) {
    ar_usleep( 1000000 );

so that the application doesn't immediately terminate.

If the application needs to control the event loop (and window creation) itself, the framework can be started as follows:

  if( !framework.start( false, false ) ) {
    return 1;
  // this is reached, this version of start() **does** return

Thereafter, you need to invoke the framework's preDraw() method before drawing and the postDraw() method after drawing but before buffer swapping.

General issues with the framework: