/**
   * Add a single texture node to the list of textures. Override this to add render-specific
   * behavior, but remember to call this method.
   *
   * @param node The node to add
   * @throws InvalidFieldValueException This is a bindable node shared
   */
  protected void addTextureNode(VRMLNodeType node) throws InvalidFieldValueException {

    if (node instanceof VRMLProtoInstance) {
      VRMLNodeType impl = ((VRMLProtoInstance) node).getImplementationNode();

      // Walk down the proto impl looking for the real node to check it
      // is the right type.
      while ((impl != null) && (impl instanceof VRMLProtoInstance))
        impl = ((VRMLProtoInstance) impl).getImplementationNode();

      if ((impl != null) && !(impl instanceof VRMLTextureNodeType))
        throw new InvalidFieldValueException(TEXTURE_PROTO_MSG);

      // NOTE:
      // JC: This seems dodgy - particularly if we try to remove them. Should it
      // be adding the impl or the outer node here? In other classes we still always
      // add the outer to this array.

      vfTexture.add(impl);
      ((VRMLTextureNodeType) node).addTextureListener(this);
    } else {
      if (!(node instanceof VRMLTextureNodeType))
        throw new InvalidFieldValueException(TEXTURE_NODE_MSG);

      vfTexture.add(node);
      ((VRMLTextureNodeType) node).addTextureListener(this);
    }

    // TODO: Need to update loaded field
  }
  /**
   * Get a string for cacheing this object. Null means do not cache this texture.
   *
   * @param stage The stage number, 0 for all single stage textures.
   * @return A string to use in lookups. Typically the url loaded.
   */
  public String getCacheString(int stage) {
    VRMLTextureNodeType tex = (VRMLTextureNodeType) vfTexture.get(stage);

    if (tex == null) return null;

    return tex.getCacheString(0);
  }
  /**
   * 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();

    int len = vfTexture.size();
    VRMLTextureNodeType tex;
    loaded = new boolean[len];

    for (int i = 0; i < len; i++) {
      tex = (VRMLTextureNodeType) vfTexture.get(i);
      tex.setupFinished();

      switch (tex.getTextureType()) {
        case TextureConstants.TYPE_SINGLE_2D:
          if (((VRMLTexture2DNodeType) tex).getImage() != null) loaded[i] = true;
          break;
        default:
          System.out.println("Unhandled texture type in BaseMultiTexture");
      }
    }

    inSetup = false;
  }