[Source] NPE fix proposal

Don Brutzman brutzman at nps.edu
Thu Jun 7 13:07:48 PDT 2012


Offline rendering triggers a bug in line (195/197) of OGLInline.java,
here is a fix.  Note that root cause isn't addressed...

        if (implGroup.isLive()) {
            stateManager.addEndOfThisFrameListener(this);
        } else {
            updateNodeBoundsChanges(null);
        }

to
        // avoid occasional null-pointer exception (NPE) when offline rendering scenes, such as
        // http://www.web3d.org/x3d/content/examples/Basic/Vrml97Specification/ChopperRotor.x3d
        if ((implGroup != null) && implGroup.isLive()) {
etc.

C:\Xj3D.nps\src\java\org\web3d\vrml\renderer\ogl\nodes\networking\OGLInline.java

all the best, Don
-- 
Don Brutzman  Naval Postgraduate School, Code USW/Br       brutzman at nps.edu
Watkins 270,  MOVES Institute, Monterey CA 93943-5000 USA   +1.831.656.2149
X3D graphics, virtual worlds, navy robotics http://faculty.nps.edu/brutzman
-------------- next part --------------
/*****************************************************************************
 *                        Web3d.org Copyright (c) 2001-2005
 *                               Java Source
 *
 * This source is licensed under the GNU LGPL v2.1
 * Please read http://www.gnu.org/copyleft/lgpl.html for more information
 *
 * This software comes with the standard NO WARRANTY disclaimer for any
 * purpose. Use it at your own risk. If there's a problem you get to fix it.
 *
 ****************************************************************************/

package org.web3d.vrml.renderer.ogl.nodes.networking;

// External imports
import org.j3d.aviatrix3d.*;

// Local imports
import org.web3d.vrml.lang.InvalidFieldException;
import org.web3d.vrml.nodes.VRMLFieldData;
import org.web3d.vrml.nodes.VRMLNodeType;
import org.web3d.vrml.renderer.common.nodes.networking.BaseInline;
import org.web3d.vrml.renderer.ogl.nodes.OGLVRMLNode;

/**
 * A node that can handle inlined content from other VRML worlds.
 * <p>
 *
 * This implementation does not care whether the source world came from a
 * UTF8 or XML encoded file.
 * <p>
 *
 * While the node is awaiting content to be downloaded, it will put a wireframe
 * box around the suggested bounds of the content. If no bounds are set then
 * a 1x1x1 box is placed at the local origin. If the URL given is null, then
 * the outline box will not be shown.
 * <p>
 * TODO:<br>
 * - Implement a scheme to allow the updating of the contents at runtime when
 *   the URL changes. It currently removes the old content, but does not
 *   inform any ContentLoadManager to fetch it's new values.
 *
 * @author Justin Couch
 * @version $Revision: 1.12 $
 */
public class OGLInline extends BaseInline
    implements OGLVRMLNode, NodeUpdateListener {

    /** The renderable scenegraph node */
    private SharedNode implGroup;

    /**
     * Create a new, default instance of this class.
     */
    public OGLInline() {
    }

    /**
     * Construct a new instance of this node based on the details from the
     * given node. If the node is not the same type, an exception will be
     * thrown.
     *
     * @param node The node to copy
     * @throws IllegalArgumentException Incorrect Node Type
     */
    public OGLInline(VRMLNodeType node) {
        super(node);
    }

    //----------------------------------------------------------
    // Methods defined by OGLVRMLNode
    //----------------------------------------------------------

    /**
     * Notification that the construction phase of this node has finished.
     * If the node would like to do any internal processing, such as setting
     * up geometry, then go for it now.
     */
    public void setupFinished() {
        if(!inSetup)
            return;

        super.setupFinished();

        implGroup = new SharedNode();

        if(vfBboxSize[0] != -1 && vfBboxSize[1] != -1 && vfBboxSize[2] != -1) {
            float[] min = new float[3];
            min[0] = vfBboxCenter[0] - vfBboxSize[0] * 0.5f;
            min[1] = vfBboxCenter[1] - vfBboxSize[1] * 0.5f;
            min[2] = vfBboxCenter[2] - vfBboxSize[2] * 0.5f;

            float[] max = new float[3];
            max[0] = vfBboxCenter[0] + vfBboxSize[0] * 0.5f;
            max[1] = vfBboxCenter[1] + vfBboxSize[1] * 0.5f;
            max[2] = vfBboxCenter[2] + vfBboxSize[2] * 0.5f;

            BoundingBox bbox = new BoundingBox(min, max);
            implGroup.setBounds(bbox);
        }
    }

    //----------------------------------------------------------
    // Methods from OGLVRMLNode class.
    //----------------------------------------------------------

    /**
     * Get the OpenGL scene graph object representation of this node. This will
     * need to be cast to the appropriate parent type when being used. Default
     * implementation returns null.
     *
     * @return The OpenGL representation.
     */
    public SceneGraphObject getSceneGraphObject() {
        return implGroup;
    }

    //----------------------------------------------------------
    // Methods defined by FrameStateManagerListener
    //----------------------------------------------------------

    /**
     * Notification that the rendering of the event model is complete and that
     * rendering is about to begin. Used to update the scene graph with the
     * loaded scene structure at the end of the frame to avoid issues with
     * multiple access to the scen graph.
     */
    public void allEventsComplete() {
        if (implGroup.isLive())
            implGroup.boundsChanged(this);
        else
            updateNodeBoundsChanges(implGroup);
    }

    //----------------------------------------------------------
    // Methods defined by UpdateListener
    //----------------------------------------------------------

    /**
     * Notification that its safe to update the node now with any operations
     * that could potentially effect the node's bounds.
     *
     * @param src The node or Node Component that is to be updated.
     */
    public void updateNodeBoundsChanges(Object src) {
        // The content has already been cleared with the setUrl call so this
        // just adds the new geometry in or removes the old geometry if
        // the load field was set to FALSE.
        if(scene == null)
            return;

        OGLVRMLNode root_node = (OGLVRMLNode)scene.getRootNode();
        Group grp = (Group)root_node.getSceneGraphObject();

        if(vfLoad)
            implGroup.setChild(grp);
        else {
            implGroup.setChild(null);
            scene = null;
        }
    }

    /**
     * Notification that its safe to update the node now with any operations
     * that only change the node's properties, but do not change the bounds.
     *
     * @param src The node or Node Component that is to be updated.
     */
    public void updateNodeDataChanges(Object src) {
    }

    //----------------------------------------------------------
    // Methods defined by VRMLExternalNodeType
    //----------------------------------------------------------

    /**
     * Set the content of this node to the given object. The object is then
     * cast by the internal representation to the form it needs. This assumes
     * at least some amount of intelligence on the part of the caller, but
     * we also know that we should not pass something dumb to it when we can
     * check what sort of content types it likes to handle. We assume the
     * loader thread is operating in the same context as the one that created
     * the node in the first place and thus knows the general types of items
     * to pass through.
     *
     * @param mimetype The mime type of this object if known
     * @param content The content of the object
     * @throws IllegalArguementException The content object is not supported
     */
    public void setContent(String mimetype, Object content)
        throws IllegalArgumentException {

        super.setContent(mimetype, content);

        // avoid occasional null-pointer exception (NPE) when offline rendering scenes, such as
        // http://www.web3d.org/x3d/content/examples/Basic/Vrml97Specification/ChopperRotor.x3d
        if ((implGroup != null) && implGroup.isLive()) {
            stateManager.addEndOfThisFrameListener(this);
        } else {
            updateNodeBoundsChanges(null);
        }
    }

    //----------------------------------------------------------
    // Methods defined by BaseInline
    //----------------------------------------------------------

    /**
     * Convenience method to handle the load field value. When value is
     * <code>true</code> replace the new URL with the old value by placing it
     * immediately on the load queue. If the value is <code>false</code> then
     * it should immediately remove the content. The derived classes should
     * make sure they override this method and handle the content removal.
     * The derived class should do all it's work before calling this method.
     *
     * @param value The new load field state
     */
    protected void setLoad(boolean value)
        throws InvalidFieldException {

        if(!inSetup && !value) {
            if (implGroup.isLive())
                implGroup.boundsChanged(this);
            else
                updateNodeBoundsChanges(implGroup);
        }

        super.setLoad(value);
    }

    //----------------------------------------------------------
    // Internal convenience methods
    //----------------------------------------------------------

    /**
     * Check the given list of URLs for relative references. If found, add the
     * base URL to it to make them all fully qualified. This will also set the
     * urlRelativeCheck flag to true.
     *
     * @param urls The list of URLs to check
     * @return The list of updated URLs.
     */
    private String[] checkURLs(String[] urls) {

        String[] ret_val = new String[urls.length];

        for(int i = 0; i < urls.length; i++) {
            if(urls[i].indexOf(':') == -1) {
                ret_val[i] = worldURL + urls[i];
            } else {
                ret_val[i] = urls[i];
            }
        }

        return ret_val;
    }
}


More information about the Source mailing list