Customising Xj3D's Functionality |
A customised loader is used when you want to build your own browser or have a more complete runtime environment than what a standard Java3D/Aviatrix3D loader will give you. Going down this route requires you to do a lot more work than the simple Loader code. Be prepared to get your hands very dirty (not to mention sometimes rapidly changing internal APIs)!
Note: If you would like to view the processes that are described here, the example browser code in theexamples/browserand the classDIYBrowserare used as the basis for this commentary
There are two properties to set
uri.content.handler.pkgs and
uri.protocol.handler.pkgs. The former is used to set the list of
base package names to find content handlers (classes that transform raw bytes
into Java objects). The latter is used to control the base package that holds
the handlers for different network protocols, such as HTTP, FTP etc. The
default install comes with a set of standard implementations and using the
following two lines will allow you to run the code with no problems.
System.setProperty("uri.content.handler.pkgs", "vlc.net.content");
System.setProperty("uri.protocol.handler.pkgs", "vlc.net.protocol");
If you know how content handlers work, then these can easily be extended by
adding more base packages to the lists, but separating each package name with
a pipe character '|' in the property value.
org.web3d.net.content package. These are registered with the
URI class from the org.ietf.uri package.
ContentHandlerFactory fac = URI.getContentHandlerFactory();
if(!(fac instanceof J3DContentHandlerFactory)) {
fac = new J3DContentHandlerFactory(fac);
URI.setContentHandlerFactory(fac);
}
FileNameMap fn_map = URI.getFileNameMap();
if(!(fn_map instanceof VRMLFileNameMap)) {
fn_map = new VRMLFileNameMap(fn_map);
URI.setFileNameMap(fn_map);
}
At the current point in time, these two classes only handle UTF8 format files.
There is no capability to recognise XML format files. This is intended to be
handled in the future after some more work has been done sorting the
integration issues.
As part of the package, an abstract callback interface is created called the Simple API for VRML processing - SAV. This set of callbacks can be registered with a parser to feed file structure information into userland code. Internally, your code can make use of this to keep a common parser, but change renderer. We also make use of this internally within the Java3D code to swap around code for proto handling to build lightweight scenegraph structures.
Parsers are represented by the interface
org.web3d.vrml.sav.VRMLReader and are accessed from the factory
class org.web3d.vrml.parser.VRMLParserFactory. A default parser
is available, but you can provide a custom parser by setting a system
property org.web3d.vrml.parser.factory with the name of the
class that is to be used.
VRMLReader vrml_reader = parserFactory.newVRMLReader();If you already have a reader instance, you can re-use that if you wish.
Next you need to register with the reader the class(es) that implement the
SAV callback interfaces. Which classes you register here depends on the
renderer that you want to use. For Java3D code this class is
org.web3d.vrml.j3d.J3DVRMLSceneBuilder, which implements all of
the SAV interfaces.
sceneBuilder.reset(); vrml_reader.setContentHandler(sceneBuilder); vrml_reader.setScriptHandler(sceneBuilder); vrml_reader.setProtoHandler(sceneBuilder); vrml_reader.setRouteHandler(sceneBuilder);A very important step is the
reset() call. This is used to make
sure the internal state of the scene builder is ready to start a new document.
This is important because the internal state may be messed up from an error
in the previously parsed file. The next four lines just register each of the
SAV methods.
The next step is telling the scene builder what it should and should not be loading. These flags are used by the Java3D loader code to send information through from the loader flags. Read the documentation for more details on this.
Finally, we tell the parser to start loading. This is done by passing and
instance of org.web3d.vrml.sav.InputSource, which is constructed
by passing in a stream, URL or filename depending on your weapon of choice.
After constructing this,
try {
vrml_reader.parse(is);
} catch(IOException ioe) {
statusLabel.setText("I/O Error: " + ioe.getMessage());
} catch(VRMLParseException vpe) {
StringBuffer buf = new StringBuffer("Error Parsing VRML file\n");
buf.append("Line: ");
buf.append(vpe.getLineNumber());
buf.append("\nStarting at column: ");
buf.append(vpe.getColumnNumber());
buf.append("Message: ");
buf.append(vpe.getMessage());
System.out.println(buf.toString());
} catch(VRMLException se) {
// everything else. Just a format exception
System.out.println(se.getMessage());
}
J3DVRMLScene is the concrete representation of
VRMLScene)
J3DVRMLScene parsed_scene = sceneBuilder.getScene();The scene contains all of the important pieces that are needed to complete a runtime environment. Now we need to place them all together to build a fully fuctional scene. There are two parts to this - common code for everyone, and renderer specific code. However, the Java3D code contains all of the rest of management. All you need to do is place together the major pieces.
The main working class for the Java3D runtime handling is
org.web3d.vrml.j3d.browser.VRMLUniverse. This implementation of
the Java3D Universe does all of the handling of routes,
bindable nodes and user input. However, you must still choose some of the
capabilities. These are the classes that handle the file caching and
how routing is implemented - these come from the generalised implementations
in the packages org.web3d.vrml.nodes.loader and
org.web3d.vrml.nodes.runtime respectively. Again, check the
documentation for the available options.
ExternalLoadManager lm = new MemCacheLoadManager(); RouteManager rm = new ListsOfListsRouteManager(); universe = new VRMLUniverse(rm, lm);To load the current scene into the custom universe requires only one method call:
universe.setScene(parsed_scene);This is enough to get the application showing VRML content.
VRMLUniverse is
the centre of attention of runtime, that's where we look for getting feedback
about requests to change the loaded scene.
Notification of the request to change scenes is through the
LinkSelectionListener. As per standard listener methodology,
this is registered with VRMLUniverse so that you can deal with
the runtime telling you what has happened.
The important method here is linkSelected(). When this is called, you will
be passed the instance of the VRMLLinkNodeType that was selected
by the user. Once you have this link node, you will have the list of URLs
to load, and you can start the entire process all over again.
|
[
Xj3D Homepage |
Xj3D @ Web3d |
Screenshots |
Dev docs |
Dev Releases |
Contributors |
Getting Started
]
Last updated: $Date: 2005/02/04 22:16:23 $ |