Heilan X3D Browser

Writing a Heilan X3D node

The doxygen documentation should cover most of the issues involved in writing an X3D node, but there are some issues that may not be obvious from those documents.

Basics

Child nodes should inherit from the ChildNode class (this is in fact a typedef of the AbstractNode class - the AbstractNode class is the equivalent of X3DNode in the X3D specification). Parent nodes should inherit from ParentNode. Make sure to read the documentation for ParentNode's methods - a number of them replace the methods used in ChildNode (i.e. you generally shouldn't override graphicDoStuff() in a ParentNode subclass - use preChildDraw() and postChildDraw() instead).

initialise()

If you have any setup to do which may take some time, or requires an OpenGL context to be active, do it in the initialise() method rather than your subclass' constructor. This helps to speed up Heilan's startup time.

Ambisonic spatialisation

In previous versions of Heilan (< v0.12), you would have to handle the Ambisonic spatialisation yourself, but that's changed now. If you're generating audio, you just fill a buffer with a mono stream in getMonoAudio(), and it will be encoded for you. The one thing to note is that getMonoAudio() returns an array of AmbisonicData, rather than single floats. As such, you should construct and maintain this array in your subclass, and in getMonoAudio(), write your audio data to the W component of the AmbisonicData structures.

Here's some basic example code:

//------------------------------------------------------------------------------
AmbisonicData *Example::getMonoAudio(int numSamples)
{
	int i;
	static float index = 0.0f;

	//Calculate audio, put in audioBuffer.
	for(i=0;i<numSamples;++i)
	{
		audioBuffer[i].W = sinf(index);

		index += 0.001f;
		if(index > TWO_PI)
			index = fmod(index);
	}

	return audioBuffer;
}



//------------------------------------------------------------------------------
void Example::setBlockSize(int newSize)
{
	if(audioBuffer)
		delete [] audioBuffer;

	bufferSize = newSize;
	audioBuffer = new AmbisonicData[bufferSize];
}
		

Construction

In order for nodes to be constructed on demand when an X3D file is parsed, a factory design pattern is used. For a node to make its constructor available to the factory, 3 things must be done (well, 2 really):

  1. Add a static 'NodeConstructor' instance to your class, like so:
    class Thing : public ChildNode
    {
      public:
    	...
    
    	static NodeConstructor<Thing> constructor;
    };
    			
  2. Make sure you define it in the source file:
    NodeConstructor<Thing> Thing::constructor;
    			
  3. Make sure you register the node with the NodeFactory instance somewhere:
    NodeFactory::getInstance().registerNode(&Thing::constructor);
    			

If you do this, you should be able to use your node in the browser.