Using your own Classes with scenegraph.io

The scenegraph.io APIs will handle the IO for all the core Java3D SceneGraphObjects. However, if you create a subclass of one of these objects and add it to your Scene Graph, the IO system, by default, will not store any state information specific to your class.

The default behavior when an unrecognized SceneGraphObject class is encountered is to traverse up the superclasses of the object until a recognized Java3D class is located. The data structures for this class are then used for IO. The system does store the class name of the original object.

For example:


public class MyBranchGroup extends org.scijava.java3d.BranchGroup {
    private int myData;
    ....
}

When the Scene Graph is written to a file and this node is encountered, the superclass org.scijava.java3d.BranchGroup will be used to store all the state for the object so any children of MyBranchGroup, the capabilities, etc. will be stored, but myData will be lost. When the scene graph is loaded, MyBranchGroup will be instantiated and will be populated with all the state from BranchGroup but myData will have been lost.

To overcome this, the scenegraph.io API provides an interface for you to implement in your own classes that provides the opportunity for you to save the state of your classes during the IO processes. This is the SceneGraphIO interface.

When the scenegraph is saved, the methods of SceneGraphIO are called in this order

  1. createSceneGraphObjectReferences

  2. saveChildren

  3. writeSceneGraphObject

During the load cycle the method call order is

  1. Instantiate Object using default constructor

  2. Populate object with state from superclasses

  3. readSceneGraphObject

  4. restoreSceneGraphObjectReferences

Within each method you need to perform the following actions:

Here are some examples. Only the parts of the source pertaining to IO are show....

Behavior Example

public class BehaviorIO extends org.scijava.java3d.Behavior implements SceneGraphIO private TransformGroup target; // The TG on which this behavior acts private int targetRef; // Object Reference for target public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) { targetRef = ref.addReference( target ); } public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) { target = (TransformGroup)ref.resolveReference( targetRef ); } public void writeSceneGraphObject( java.io.DataOutput out ) throws IOException { out.writeInt( targetRef ); } public void readSceneGraphObject( java.io.DataInput in ) throws IOException { targetRef = in.readInt(); } // This has no effect as this is not a subclass of Group public boolean saveChildren() { return true; }

`BlackBox' Group Example

This example is a Group node that creates its subgraph during its instantiation. An example where you might use this is to represent some geometry that is loaded from an external file format such a OpenFLT.

public class House extends Group implements SceneGraphIO {
    public House() {
        super();
        this.addChild( OpenFlightLoader.load( "/dir/house.flt" );
    }

    public void createSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
        // No references
    }

    public void restoreSceneGraphObjectReferences( SceneGraphObjectReferenceControl ref ) {
        // No references
    }

    public void writeSceneGraphObject( java.io.DataOutput out ) throws IOException {
        // No local state
    }

    public void readSceneGraphObject( java.io.DataInput in ) throws IOException {
        // No local state
    }

    public boolean saveChildren() {
        // Don't save the children as they will be restored by the openflightloader
        return false;
    }