public int compare(MercatorTextureTile ta, MercatorTextureTile tb) {
      int la =
          ta.getFallbackTile() == null
              ? ta.getLevelNumber()
              : ta.getFallbackTile().getLevelNumber();
      int lb =
          tb.getFallbackTile() == null
              ? tb.getLevelNumber()
              : tb.getFallbackTile().getLevelNumber();

      return la < lb ? -1 : la == lb ? 0 : 1;
    }
  private void addTile(DrawContext dc, MercatorTextureTile tile) {
    tile.setFallbackTile(null);

    if (tile.isTextureInMemory(dc.getTextureCache())) {
      //            System.out.printf("Sector %s, min = %f, max = %f\n", tile.getSector(),
      //                dc.getGlobe().getMinElevation(tile.getSector()),
      // dc.getGlobe().getMaxElevation(tile.getSector()));
      this.addTileToCurrent(tile);
      return;
    }

    // Level 0 loads may be forced
    if (tile.getLevelNumber() == 0
        && this.forceLevelZeroLoads
        && !tile.isTextureInMemory(dc.getTextureCache())) {
      this.forceTextureLoad(tile);
      if (tile.isTextureInMemory(dc.getTextureCache())) {
        this.addTileToCurrent(tile);
        return;
      }
    }

    // Tile's texture isn't available, so request it
    if (tile.getLevelNumber() < this.levels.getNumLevels()) {
      // Request only tiles with data associated at this level
      if (!this.levels.isResourceAbsent(tile)) this.requestTexture(dc, tile);
    }

    // Set up to use the currentResource tile's texture
    if (this.currentResourceTile != null) {
      if (this.currentResourceTile.getLevelNumber() == 0
          && this.forceLevelZeroLoads
          && !this.currentResourceTile.isTextureInMemory(dc.getTextureCache())
          && !this.currentResourceTile.isTextureInMemory(dc.getTextureCache()))
        this.forceTextureLoad(this.currentResourceTile);

      if (this.currentResourceTile.isTextureInMemory(dc.getTextureCache())) {
        tile.setFallbackTile(currentResourceTile);
        this.addTileToCurrent(tile);
      }
    }
  }
 private boolean meetsRenderCriteria(DrawContext dc, MercatorTextureTile tile) {
   return this.levels.isFinalLevel(tile.getLevelNumber()) || !needToSplit(dc, tile.getSector());
 }
  private void addTileOrDescendants(DrawContext dc, MercatorTextureTile tile) {
    if (this.meetsRenderCriteria(dc, tile)) {
      this.addTile(dc, tile);
      return;
    }

    // The incoming tile does not meet the rendering criteria, so it must be subdivided and those
    // subdivisions tested against the criteria.

    // All tiles that meet the selection criteria are drawn, but some of those tiles will not have
    // textures associated with them either because their texture isn't loaded yet or because they
    // are finer grain than the layer has textures for. In these cases the tiles use the texture of
    // the closest ancestor that has a texture loaded. This ancestor is called the
    // currentResourceTile.
    // A texture transform is applied during rendering to align the sector's texture coordinates
    // with the
    // appropriate region of the ancestor's texture.

    MercatorTextureTile ancestorResource = null;

    try {
      // TODO: Revise this to reflect that the parent layer is only requested while the algorithm
      // continues
      // to search for the layer matching the criteria.
      // At this point the tile does not meet the render criteria but it may have its texture in
      // memory.
      // If so, register this tile as the resource tile. If not, then this tile will be the next
      // level
      // below a tile with texture in memory. So to provide progressive resolution increase, add
      // this tile
      // to the draw list. That will cause the tile to be drawn using its parent tile's texture, and
      // it will
      // cause it's texture to be requested. At some future call to this method the tile's texture
      // will be in
      // memory, it will not meet the render criteria, but will serve as the parent to a tile that
      // goes
      // through this same process as this method recurses. The result of all this is that a tile
      // isn't rendered
      // with its own texture unless all its parents have their textures loaded. In addition to
      // causing
      // progressive resolution increase, this ensures that the parents are available as the user
      // zooms out, and
      // therefore the layer remains visible until the user is zoomed out to the point the layer is
      // no longer
      // active.
      if (tile.isTextureInMemory(dc.getTextureCache()) || tile.getLevelNumber() == 0) {
        ancestorResource = this.currentResourceTile;
        this.currentResourceTile = tile;
      } else if (!tile.getLevel().isEmpty()) {
        //                this.addTile(dc, tile);
        //                return;

        // Issue a request for the parent before descending to the children.
        if (tile.getLevelNumber() < this.levels.getNumLevels()) {
          // Request only tiles with data associated at this level
          if (!this.levels.isResourceAbsent(tile)) this.requestTexture(dc, tile);
        }
      }

      MercatorTextureTile[] subTiles =
          tile.createSubTiles(this.levels.getLevel(tile.getLevelNumber() + 1));
      for (MercatorTextureTile child : subTiles) {
        if (this.isTileVisible(dc, child)) this.addTileOrDescendants(dc, child);
      }
    } finally {
      if (ancestorResource != null) // Pop this tile as the currentResource ancestor
      this.currentResourceTile = ancestorResource;
    }
  }