/**
   * 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();

    SphereGenerator generator = new SphereGenerator(vfRadius, 32);
    GeometryData data = new GeometryData();

    data.geometryType = GeometryData.TRIANGLE_STRIPS;
    data.geometryComponents = GeometryData.NORMAL_DATA | GeometryData.TEXTURE_2D_DATA;

    generator.generate(data);

    impl = new TriangleStripArray(false, VertexGeometry.VBO_HINT_STATIC);
    impl.setVertices(TriangleStripArray.COORDINATE_3, data.coordinates, data.vertexCount);
    impl.setStripCount(data.stripCounts, data.numStrips);
    impl.setNormals(data.normals);

    // Make an array of objects for the texture setting
    float[][] textures = {data.textureCoordinates};
    int[] tex_type = {TriangleStripArray.TEXTURE_COORDINATE_2};
    impl.setTextureCoordinates(tex_type, textures, 1);

    // Setup 4 texture units
    int[] tex_maps = new int[4];

    for (int i = 0; i < 4; i++) tex_maps[i] = 0;

    impl.setTextureSetMap(tex_maps, 4);

    OGLUserData u_data = new OGLUserData();
    u_data.geometryData = data;

    impl.setUserData(u_data);
  }
  private Grid generateTorus() {
    double ir = 0.002f;
    double or = 0.006f;
    int facets = 64;
    TorusGenerator tg = new TorusGenerator((float) ir, (float) or, facets, facets);
    GeometryData geom = new GeometryData();
    geom.geometryType = GeometryData.TRIANGLES;
    tg.generate(geom);

    double bounds = TriangleModelCreator.findMaxBounds(geom);
    double size = 2.1 * bounds; // Slightly over allocate

    Grid grid = new ArrayAttributeGridByte(size, size, size, 0.0005, 0.0005);

    double x = bounds;
    double y = x;
    double z = x;

    double rx = 0, ry = 1, rz = 0, rangle = 0;
    int outerMaterial = 1;
    int innerMaterial = 1;

    TorusCreator tc =
        new TorusCreator(ir, or, x, y, z, rx, ry, rz, rangle, innerMaterial, outerMaterial);

    grid = new RangeCheckWrapper(grid);

    tc.generate(grid);

    return grid;
  }
  /**
   * The geometry definition is now finished so take the given field values and generate the
   * triangle output.
   *
   * @param ch The content handler instance to write to
   * @param sh The script handler instance to write to
   * @param ph The proto handler instance to write to
   * @param rh The route handler instance to write to
   */
  void generateOutput(ContentHandler ch, ScriptHandler sh, ProtoHandler ph, RouteHandler rh) {

    // Set up the coordinate array and indices.
    ConeGenerator generator = new ConeGenerator(height, radius);

    GeometryData data = new GeometryData();
    data.geometryType = GeometryData.INDEXED_TRIANGLES;
    data.geometryComponents = GeometryData.NORMAL_DATA | GeometryData.TEXTURE_2D_DATA;

    generator.generate(data);

    ch.startNode("IndexedTriangleSet", null);
    ch.startField("coord");
    ch.startNode("Coordinate", null);
    ch.startField("point");

    if (ch instanceof BinaryContentHandler) {
      ((BinaryContentHandler) ch).fieldValue(data.coordinates, data.coordinates.length);
    } else if (ch instanceof StringContentHandler) {
      StringBuffer buf = new StringBuffer();
      for (int i = 0; i < data.coordinates.length; i++) {
        buf.append(data.coordinates[i]);
        buf.append(' ');
      }

      ((StringContentHandler) ch).fieldValue(buf.toString());
    }

    ch.endField(); // point
    ch.endNode(); // Coordinate
    ch.endField(); // coord

    ch.startField("index");

    if (ch instanceof BinaryContentHandler) {
      ((BinaryContentHandler) ch).fieldValue(data.indexes, data.indexes.length);
    } else if (ch instanceof StringContentHandler) {
      StringBuffer buf = new StringBuffer();
      for (int i = 0; i < data.indexes.length; i++) {
        buf.append(data.indexes[i]);
        buf.append(' ');
      }

      ((StringContentHandler) ch).fieldValue(buf.toString());
    }

    ch.endField(); // index

    if (!solid) {
      ch.startField("solid");

      if (ch instanceof BinaryContentHandler) {
        ((BinaryContentHandler) ch).fieldValue(solid);
      } else if (ch instanceof StringContentHandler) {

        ((StringContentHandler) ch).fieldValue("FALSE");
      }

      ch.endField(); // solid
    }

    ch.endNode(); // IndexedTriangleSet
  }