@Override
  public void eyePtChanged() {

    Point3d eyePt = getViewPosInLocal(frontRoot);

    // System.out.println("eye pt = " + eyePt)
    if (eyePt != null) {

      for (int i = 0; i < 6; i++) {
        // if (perspectiveAttr.getValue() == true)
        // {
        // eyeVec.sub(eyePt, faceCenter[i]);
        // } else
        {
          eyeVec.sub(eyePt, volCenter);
        }
        frontFaceBits.set(i);
        backFaceBits.clear(i);
        if (eyeVec.dot(faceNormal[i]) < 0) {
          backFaceBits.set(i);
          frontFaceBits.clear(i);
        } else {
          frontFaceBits.set(i);
          backFaceBits.clear(i);
        }
      }
      frontAnnotations.setChildMask(frontFaceBits);
      backAnnotations.setChildMask(backFaceBits);
    }
  }
  private void doUpdate() {
    if (restorePending) {
      return; // we will get called again
      // after the restore is
      // complete
    }
    canvas.stopRenderer();
    canvas.setDoubleBufferEnable(doubleBufferAttr.getValue());
    if (coordSysAttr.getValue()) {
      coordSwitch.setWhichChild(Switch.CHILD_ALL);
    } else {
      coordSwitch.setWhichChild(Switch.CHILD_NONE);
    }
    if (getAnnotationsAttr().getValue()) {
      staticBackAnnotationSwitch.setWhichChild(Switch.CHILD_ALL);
      dynamicBackAnnotationSwitch.setWhichChild(Switch.CHILD_ALL);
      staticFrontAnnotationSwitch.setWhichChild(Switch.CHILD_ALL);
      dynamicFrontAnnotationSwitch.setWhichChild(Switch.CHILD_ALL);
    } else {
      staticBackAnnotationSwitch.setWhichChild(Switch.CHILD_NONE);
      dynamicBackAnnotationSwitch.setWhichChild(Switch.CHILD_NONE);
      staticFrontAnnotationSwitch.setWhichChild(Switch.CHILD_NONE);
      dynamicFrontAnnotationSwitch.setWhichChild(Switch.CHILD_NONE);
    }
    if (perspectiveAttr.getValue()) {
      view.setProjectionPolicy(View.PERSPECTIVE_PROJECTION);
    } else {
      view.setProjectionPolicy(View.PARALLEL_PROJECTION);
    }
    if (renderer != renderers[rendererAttr.getValue()]) {
      // TODO: renderer.clear();
      // TODO: handle gui
      try {
        System.out.println("Clearing Attached : VolRend-doUpdate()");
        clearAttach();

      } catch (Exception e) {
        e.printStackTrace();
      }
      renderer = renderers[rendererAttr.getValue()];
      renderer.attach(dynamicAttachGroup, staticAttachGroup);
    }
    try {
      renderer.update();
      annotations.update();
    } catch (Exception e) {

      e.printStackTrace();
    } catch (OutOfMemoryError e) {
      JOptionPane.showMessageDialog(
          null, "Ran out of memory!", "Render Error", JOptionPane.ERROR_MESSAGE);
    }
    int newVolEditId;
    if ((newVolEditId = volume.update()) != volEditId) {
      updateCenter(volume.minCoord, volume.maxCoord);
      newVolEditId = volEditId;
    }
    eyePtChanged();
    canvas.startRenderer();
  }
  BranchGroup createSceneGraph() {
    Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f);
    Vector3f lDir1 = new Vector3f(0.0f, 0.0f, 1.0f);
    Color3f alColor = new Color3f(1.0f, 1.0f, 1.0f);

    // Create the root of the branch graph
    BranchGroup objRoot = new BranchGroup();

    // Create a transform group to scale the
    // whole scene
    TransformGroup scaleGroup = new TransformGroup();
    Transform3D scaleXform = new Transform3D();
    double scale = 1;
    scaleXform.setScale(scale);
    scaleGroup.setTransform(scaleXform);
    objRoot.addChild(scaleGroup);

    // Create the static ordered group
    OrderedGroup scaleOGroup = new OrderedGroup();
    scaleGroup.addChild(scaleOGroup);

    // Create the static annotation group
    staticBackAnnotationSwitch = new Switch();
    staticBackAnnotationSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
    staticBackAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_READ);
    staticBackAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_WRITE);
    staticBackAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
    scaleOGroup.addChild(staticBackAnnotationSwitch);

    // Create the static attachment group
    staticAttachGroup = new Group();
    staticAttachGroup.setCapability(Group.ALLOW_CHILDREN_READ);
    staticAttachGroup.setCapability(Group.ALLOW_CHILDREN_WRITE);
    staticAttachGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND);
    scaleOGroup.addChild(staticAttachGroup);

    // Create a TG at the origin
    objectGroup = new TransformGroup();

    // Enable the TRANSFORM_WRITE capability
    // so that our behavior code
    // can modify it at runtime. Add it to the
    // root of the subgraph.
    //
    objectGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    objectGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
    scaleOGroup.addChild(objectGroup);

    // Create the static annotation group
    staticFrontAnnotationSwitch = new Switch();
    staticFrontAnnotationSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
    staticFrontAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_READ);
    staticFrontAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_WRITE);
    staticFrontAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
    scaleOGroup.addChild(staticFrontAnnotationSwitch);
    // added after objectGroup so it shows up
    // in front

    // Create the transform group node and
    // initialize it center the
    // object around the origin
    centerGroup = new TransformGroup();
    updateCenter(new Point3d(0.0, 0.0, 0.0), new Point3d(1.0, 1.0, 1.0));
    centerGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    objectGroup.addChild(centerGroup);

    // Set up the annotation/volume/annotation
    // sandwitch
    OrderedGroup centerOGroup = new OrderedGroup();
    centerGroup.addChild(centerOGroup);

    // create the back dynamic annotation
    // point
    dynamicBackAnnotationSwitch = new Switch(Switch.CHILD_ALL);
    dynamicBackAnnotationSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
    dynamicBackAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_READ);
    dynamicBackAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_WRITE);
    dynamicBackAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
    centerOGroup.addChild(dynamicBackAnnotationSwitch);

    // create the dynamic attachment point
    dynamicAttachGroup = new Group();
    dynamicAttachGroup.setCapability(Group.ALLOW_CHILDREN_READ);
    dynamicAttachGroup.setCapability(Group.ALLOW_CHILDREN_WRITE);
    dynamicAttachGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND);
    centerOGroup.addChild(dynamicAttachGroup);

    // create the front dynamic annotation
    // point
    dynamicFrontAnnotationSwitch = new Switch(Switch.CHILD_ALL);
    dynamicFrontAnnotationSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
    dynamicFrontAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_READ);
    dynamicFrontAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_WRITE);
    dynamicFrontAnnotationSwitch.setCapability(Group.ALLOW_CHILDREN_EXTEND);
    centerOGroup.addChild(dynamicFrontAnnotationSwitch);

    // Create the annotations
    Annotations annotations = new Annotations(view, context, volume);
    annotations.attachBack(dynamicBackAnnotationSwitch, staticBackAnnotationSwitch);
    annotations.attach(dynamicFrontAnnotationSwitch, staticFrontAnnotationSwitch);

    coordSwitch = new Switch(Switch.CHILD_ALL);
    coordSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
    coordSwitch.addChild(new CoordSys(0.2, new Vector3d(-0.1, -0.1, -0.1)));
    centerGroup.addChild(coordSwitch);

    BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 10000000.0);

    FirstFramesBehavior ff = new FirstFramesBehavior(this);
    ff.setSchedulingBounds(bounds);
    objRoot.addChild(ff);

    updateBehavior = new UpdateBehavior();
    updateBehavior.setSchedulingBounds(bounds);
    objRoot.addChild(updateBehavior);

    // ExitKeyBehavior eb = new
    // ExitKeyBehavior();
    // eb.setSchedulingBounds(bounds);
    // objRoot.addChild(eb);

    BranchGroup trueRoot = new BranchGroup();
    TransformGroup trueTransform = new TransformGroup();

    trueTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    trueTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

    trueRoot.addChild(trueTransform);
    trueTransform.addChild(objRoot);

    // MouseTranslate mt = new
    // MouseTranslate();
    // mt.setupCallback(this);
    // mt.setTransformGroup(trueTransform);
    // mt.setSchedulingBounds(bounds);
    // trueRoot.addChild(mt);

    MouseZoom mz = new MouseZoom();
    mz.setupCallback(this);
    mz.setTransformGroup(trueTransform);
    mz.setSchedulingBounds(bounds);
    trueRoot.addChild(mz);

    MouseRotate mr = new MouseRotate();
    mr.setupCallback(this);
    mr.setTransformGroup(trueTransform);
    mr.setSchedulingBounds(bounds);
    mr.setFactor(0.007);
    trueRoot.addChild(mr);

    // trueTransform.addChild(objRoot);
    // trueRoot.addChild(trueTransform);
    return trueRoot;
  }
  public Annotations(View view, Context context, Volume vol) {
    super(view, context, vol);
    viewPtAttr = (CoordAttr) context.getAttr("Vol Ref Pt");
    perspectiveAttr = (ToggleAttr) context.getAttr("Perspective");
    boxAttr[PLUS_X] = (ToggleAttr) context.getAttr("Plus X Box");
    boxAttr[PLUS_Y] = (ToggleAttr) context.getAttr("Plus Y Box");
    boxAttr[PLUS_Z] = (ToggleAttr) context.getAttr("Plus Z Box");
    boxAttr[MINUS_X] = (ToggleAttr) context.getAttr("Minus X Box");
    boxAttr[MINUS_Y] = (ToggleAttr) context.getAttr("Minus Y Box");
    boxAttr[MINUS_Z] = (ToggleAttr) context.getAttr("Minus Z Box");
    imageAttr[PLUS_X] = (StringAttr) context.getAttr("Plus X Image");
    imageAttr[PLUS_Y] = (StringAttr) context.getAttr("Plus Y Image");
    imageAttr[PLUS_Z] = (StringAttr) context.getAttr("Plus Z Image");
    imageAttr[MINUS_X] = (StringAttr) context.getAttr("Minus X Image");
    imageAttr[MINUS_Y] = (StringAttr) context.getAttr("Minus Y Image");
    imageAttr[MINUS_Z] = (StringAttr) context.getAttr("Minus Z Image");

    volume = vol;
    frontRoot = new BranchGroup();
    frontRoot.setCapability(BranchGroup.ALLOW_DETACH);
    frontRoot.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ);
    backRoot = new BranchGroup();
    backRoot.setCapability(BranchGroup.ALLOW_DETACH);
    backRoot.setCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ);

    int stripLength[] = new int[1];
    stripLength[0] = 5;

    ColoringAttributes ca = new ColoringAttributes(1.0f, 0.0f, 0.0f, ColoringAttributes.SHADE_FLAT);
    Appearance boxAppearance = new Appearance();
    boxAppearance.setColoringAttributes(ca);

    TexCoord2f[] texCoords = new TexCoord2f[4];
    texCoords[0] = new TexCoord2f(0.0f, 0.0f);
    texCoords[1] = new TexCoord2f(1.0f, 0.0f);
    texCoords[2] = new TexCoord2f(1.0f, 1.0f);
    texCoords[3] = new TexCoord2f(0.0f, 1.0f);

    TransparencyAttributes ta = new TransparencyAttributes(TransparencyAttributes.BLENDED, 0.0f);
    TextureAttributes texAttr = new TextureAttributes();
    texAttr.setTextureMode(TextureAttributes.MODULATE);
    PolygonAttributes pa = new PolygonAttributes();
    pa.setCullFace(PolygonAttributes.CULL_NONE);
    RenderingAttributes ra = new RenderingAttributes();
    ra.setDepthBufferEnable(false);

    for (int i = 0; i < 6; i++) {
      faceGroup[i] = new SharedGroup();
      frontAnnotations.addChild(new Link(faceGroup[i]));
      backAnnotations.addChild(new Link(faceGroup[i]));
      boxLine[i] = new LineStripArray(5, GeometryArray.COORDINATES, stripLength);
      boxLine[i].setCoordinates(0, volume.facePoints[i], 0, 4);
      boxLine[i].setCoordinate(4, volume.facePoints[i][0]);
      boxLine[i].setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);
      Shape3D box = new Shape3D(boxLine[i], boxAppearance);
      boxSwitch[i] = new Switch();
      boxSwitch[i].setCapability(Switch.ALLOW_SWITCH_WRITE);
      boxSwitch[i].addChild(box);
      if (boxAttr[i].getValue() == true) {
        boxSwitch[i].setWhichChild(Switch.CHILD_ALL);
      } else {
        boxSwitch[i].setWhichChild(Switch.CHILD_NONE);
      }
      faceGroup[i].addChild(boxSwitch[i]);
      imageQuad[i] =
          new QuadArray(4, GeometryArray.COORDINATES | GeometryArray.TEXTURE_COORDINATE_2);
      imageQuad[i].setCapability(GeometryArray.ALLOW_COORDINATE_WRITE);
      imageQuad[i].setCoordinates(0, volume.facePoints[i], 0, 4);
      imageQuad[i].setTextureCoordinates(0, 0, texCoords, 0, 4);
      imageAppearance[i] = new Appearance();
      imageAppearance[i].setTransparencyAttributes(ta);
      imageAppearance[i].setPolygonAttributes(pa);
      imageAppearance[i].setRenderingAttributes(ra);
      imageAppearance[i].setTextureAttributes(texAttr);
      imageAppearance[i].setCapability(Appearance.ALLOW_TEXTURE_WRITE);
      imageSwitch[i] = new Switch();
      imageSwitch[i].setCapability(Switch.ALLOW_SWITCH_WRITE);
      imageFile[i] = imageAttr[i].getValue();
      if (imageFile[i].length() > 0) {
        try {
          URL imageURL = new URL(context.getCodeBase().toString() + imageFile[i]);
          imageTexture[i] = new TextureLoader(imageURL, null).getTexture();
        } catch (Exception e) {
          System.err.println("Error " + e + " loading image:" + imageFile[i] + ".");
        }
      }
      imageAppearance[i].setTexture(imageTexture[i]);
      if (imageTexture[i] != null) {
        imageSwitch[i].setWhichChild(Switch.CHILD_ALL);
      } else {
        imageSwitch[i].setWhichChild(Switch.CHILD_NONE);
      }
      Shape3D imageShape = new Shape3D(imageQuad[i], imageAppearance[i]);
      imageSwitch[i].addChild(imageShape);
      faceGroup[i].addChild(imageSwitch[i]);
    }
    frontAnnotations.setCapability(Switch.ALLOW_SWITCH_WRITE);
    backAnnotations.setCapability(Switch.ALLOW_SWITCH_WRITE);

    faceNormal[PLUS_X] = new Vector3d(1.0, 0.0, 0.0);
    faceCenter[PLUS_X] = new Point3d(volume.maxCoord.x, 0.0, 0.0);
    faceNormal[PLUS_Y] = new Vector3d(0.0, 1.0, 0.0);
    faceCenter[PLUS_Y] = new Point3d(0.0, volume.maxCoord.y, 0.0);
    faceNormal[PLUS_Z] = new Vector3d(0.0, 0.0, 1.0);
    faceCenter[PLUS_Z] = new Point3d(0.0, 0.0, volume.maxCoord.z);
    faceNormal[MINUS_X] = new Vector3d(-1.0, 0.0, 0.0);
    faceCenter[MINUS_X] = new Point3d(volume.minCoord.x, 0.0, 0.0);
    faceNormal[MINUS_Y] = new Vector3d(0.0, -1.0, 0.0);
    faceCenter[MINUS_Y] = new Point3d(0.0, volume.minCoord.y, 0.0);
    faceNormal[MINUS_Z] = new Vector3d(0.0, 0.0, -1.0);
    faceCenter[MINUS_Z] = new Point3d(0.0, 0.0, volume.minCoord.z);
    volCenter.x = (volume.maxCoord.x + volume.minCoord.x) / 2;
    volCenter.y = (volume.maxCoord.y + volume.minCoord.y) / 2;
    volCenter.z = (volume.maxCoord.z + volume.minCoord.z) / 2;

    frontRoot.addChild(frontAnnotations);
    backRoot.addChild(backAnnotations);
  }