QUANTA Avatars

Improved object-oriented multiple user avatar library for QUANTA


I've worked with the CAVERNsoft and QUANTA avatar code in Performer, but we do not have any code available for using it with an Open Inventor scene graph. I decided that rather than trying to adapt the existing code's "template," it would be a lot easier to just start from scratch and create an entirely new set of code for handling avatars. This updated code exhibits better object-oriented design, and it separates class responsibilities. The old code required managing duplicate avatar and manager classes. A direct dependence existed between the two. I've tracked down a few minor bugs in QUANTA while integrating the networking. The server code included in the archive makes efficient use of threads and signals to reduce the CPU load.

Download: qavatar.zip (.zip, 126k, April 13, 2004)

Classes

The new code is organized in a similar manner, but I have added some Design Patterns. I have dropped the C++ templates to hopefully enhance compatibility. There are four main classes involved in QAvatar:

QAvatar
The main avatar class manages three buffers for aux, hello, and tracker data. It knows the specifics abou the data that is inserted into those buffers, and subclasses must implement methods to pack and unpack any specific data to and from those buffers.
QAvatarFactory
One nifty way to remove coupling between concrete manager and avatar classes is to use the Factory Method design pattern. This pattern encapsulates instantiation within a separate object. By creating different factories, different concrete avatar classes may be created. The key advantage to this approach is that a base manager class can easily create instances of concrete avatar subclasses.
QAvatarListener
The old code triggered C callbacks when responding to network messages. I use a modification of the Observer Pattern that is a less generic. The Observer Pattern typically uses a "pull" approach in that Observers must request information from the Subject. This class "pushes" the data within specific notification methods. Listener classes respond to those messages without having to request state information from the notifier. Information may still be requested from the avatar object to extract buffer information.
QAvatarManager
This class manages the networking between multiple users. It creates the hash tables that map multiple users to local avatar objects. Messages are sent to a server by querying its own "self avatar." This localizes all representation within avatar objects. The manager does nothing more than manage network communication. Any listeners attached to the manager are notified when new messages arrive.


Class Responsibilities

Class Diagram

Viewing the UML for the classes makes it clear that the QAvatar and QAvatarManager classes are heavyweight classes. However, the manager class is not likely to require subclasses. It operates through its avatar instance. QAvatarFactory is pretty lightweight, as all it has to do is create a concrete QAvatar instance. This approach behaves similar to templates without the need for using template code.


UML for QAvatar classes.

Programming with this library requires making new subclasses, but that's not a big deal. The biggest importance for subclasses is to set the QAvatar data buffer sizes. Subclasses should set the values for each of the aux, hello, and tracker buffers. The manager adjusts its own buffers based on the sizes specified within the avatar object. I thought about different ways to tackle this problem, but I really wanted to keep responsibilities separate to avoid the dual subclassing dictated by the older avatar code.

Examples

I wrote some simple classes to demonstrate the code's behavior on the command line. I implemented signal handling to properly operate blocking network updates, so the application behaves better while waiting for network data. The required subclasses is really basic. For example, consider a simple factory:

class DemoFactory : public QAvatarFactory
{
public:
virtual QAvatar* createAvatar(const long& newID)
{
return new QAvatar(newID);
}
};

It's very simple and straight-forward. When the QAvatarManager needs to create a new avatar, it generates a unique ID (or uses the one received over the network) and passes that to the factory method. The factory creates a new instance and returns it to the caller. Here's sample code for a very basic listener that receives notification from the manager:

class DemoListener : public QAvatarListener
{
public:
virtual ~DemoListener() {}
virtual void avatarArrive(QAvatar* avatar)
{
printf("WELCOME!!! AVATAR %i ARRIVED\n", avatar->getID());
}
virtual void avatarAux(QAvatar* avatar)
{
printf("AVATAR %i AUX\n", avatar->getID());
}
virtual void avatarBye(QAvatar* avatar)
{
printf("GOODBYE!! AVATAR %i LEFT\n", avatar->getID());
}
virtual void avatarHello(QAvatar* avatar)
{
printf("AVATAR %i HELLO\n", avatar->getID());
}
virtual void avatarTracker(QAvatar* avatar)
{
printf("AVATAR %i TRACKER\n", avatar->getID());
}
};

No callbacks... just simple notification messages. The manager passes the avatar instance, so that instance can be queried for any class-specific information. Creating graphic representations of avatars is thus within the domain of QAvatarListener, not QAvatarManager.

Key Improvements

  • Cleanly separates networking implementation from the data requirements.
  • User subclasses are not as tightly dependent upon each other.
  • Drops notion of callbacks and instead notifies individual objects.
  • Very effecient server uses threads and signals to reduce CPU load.
  • Easily configures and compiles with CMake!

Documentation is available using doxygen, so I just need to make sure that the example programs are clear enough.

Building the Library

The source code is configured using CMake, the same build tool used for the Visualization Toolkit. I work on multiple platforms, and it's a nightmare to separately manage Makefiles, Visual Studio Projects, and any other platform-specific build settings. CMake uses a single CMakeLists.txt file to configure everything on just about any platform. I have built qavatar on MacOS X, Windows 2000, IRIX, and Linux without any trouble.


CSS Research Page