private int packBitmaps(Atlas.Type type, int width, int height, Atlas.Entry entry) {
      int total = 0;
      Atlas atlas = new Atlas(type, width, height);

      final int count = mBitmaps.size();
      for (int i = 0; i < count; i++) {
        final Bitmap bitmap = mBitmaps.get(i);
        if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
          total++;
        }
      }

      return total;
    }
    /**
     * Renders a list of bitmaps into the atlas. The position of each bitmap was decided by the
     * packing algorithm and will be honored by this method.
     *
     * @param buffer The buffer to render the atlas entries into
     * @param atlas The atlas to pack the bitmaps into
     * @param packCount The number of bitmaps that will be packed in the atlas
     * @return true if the atlas was rendered, false otherwise
     */
    @SuppressWarnings("MismatchedReadAndWriteOfArray")
    private boolean renderAtlas(GraphicBuffer buffer, Atlas atlas, int packCount) {
      // Use a Source blend mode to improve performance, the target bitmap
      // will be zero'd out so there's no need to waste time applying blending
      final Paint paint = new Paint();
      paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));

      // We always render the atlas into a bitmap. This bitmap is then
      // uploaded into the GraphicBuffer using OpenGL to swizzle the content
      final Bitmap atlasBitmap =
          Bitmap.createBitmap(buffer.getWidth(), buffer.getHeight(), Bitmap.Config.ARGB_8888);
      final Canvas canvas = new Canvas(atlasBitmap);

      final Atlas.Entry entry = new Atlas.Entry();

      mAtlasMap = new long[packCount * ATLAS_MAP_ENTRY_FIELD_COUNT];
      long[] atlasMap = mAtlasMap;
      int mapIndex = 0;

      boolean result = false;
      final long startRender = System.nanoTime();
      final int count = mBitmaps.size();

      for (int i = 0; i < count; i++) {
        final Bitmap bitmap = mBitmaps.get(i);
        if (atlas.pack(bitmap.getWidth(), bitmap.getHeight(), entry) != null) {
          // We have more bitmaps to pack than the current configuration
          // says, we were most likely not able to detect a change in the
          // list of preloaded drawables, abort and delete the configuration
          if (mapIndex >= mAtlasMap.length) {
            deleteDataFile();
            break;
          }

          canvas.save();
          canvas.translate(entry.x, entry.y);
          canvas.drawBitmap(bitmap, 0.0f, 0.0f, null);
          canvas.restore();
          atlasMap[mapIndex++] = bitmap.refSkPixelRef();
          atlasMap[mapIndex++] = entry.x;
          atlasMap[mapIndex++] = entry.y;
        }
      }

      final long endRender = System.nanoTime();
      releaseCanvas(canvas, atlasBitmap);
      result = nUploadAtlas(buffer, atlasBitmap);
      atlasBitmap.recycle();
      final long endUpload = System.nanoTime();

      if (DEBUG_ATLAS) {
        float renderDuration = (endRender - startRender) / 1000.0f / 1000.0f;
        float uploadDuration = (endUpload - endRender) / 1000.0f / 1000.0f;
        Log.d(
            LOG_TAG,
            String.format(
                "Rendered atlas in %.2fms (%.2f+%.2fms)",
                renderDuration + uploadDuration, renderDuration, uploadDuration));
      }

      return result;
    }