mobile/android/base/gfx/NinePatchTileLayer.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/gfx/NinePatchTileLayer.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,132 @@
     1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +package org.mozilla.gecko.gfx;
    1.10 +
    1.11 +import android.graphics.RectF;
    1.12 +import android.opengl.GLES20;
    1.13 +
    1.14 +import java.nio.FloatBuffer;
    1.15 +
    1.16 +/**
    1.17 + * Encapsulates the logic needed to draw a nine-patch bitmap using OpenGL ES.
    1.18 + *
    1.19 + * For more information on nine-patch bitmaps, see the following document:
    1.20 + *   http://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch
    1.21 + */
    1.22 +public class NinePatchTileLayer extends TileLayer {
    1.23 +    private static final int PATCH_SIZE = 16;
    1.24 +    private static final int TEXTURE_SIZE = 64;
    1.25 +
    1.26 +    public NinePatchTileLayer(CairoImage image) {
    1.27 +        super(image, TileLayer.PaintMode.NORMAL);
    1.28 +    }
    1.29 +
    1.30 +    @Override
    1.31 +    public void draw(RenderContext context) {
    1.32 +        if (!initialized())
    1.33 +            return;
    1.34 +
    1.35 +        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
    1.36 +        GLES20.glEnable(GLES20.GL_BLEND);
    1.37 +
    1.38 +        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    1.39 +        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureID());
    1.40 +        drawPatches(context);
    1.41 +    }
    1.42 +
    1.43 +    private void drawPatches(RenderContext context) {
    1.44 +        /*
    1.45 +         * We divide the nine-patch bitmap up as follows:
    1.46 +         *
    1.47 +         *    +---+---+---+
    1.48 +         *    | 0 | 1 | 2 |
    1.49 +         *    +---+---+---+
    1.50 +         *    | 3 |   | 4 |
    1.51 +         *    +---+---+---+
    1.52 +         *    | 5 | 6 | 7 |
    1.53 +         *    +---+---+---+
    1.54 +         */
    1.55 +
    1.56 +        // page is the rect of the "missing" center spot in the picture above
    1.57 +        RectF page = context.pageRect;
    1.58 +
    1.59 +        drawPatch(context, 0, PATCH_SIZE * 3,                                              /* 0 */
    1.60 +                  page.left - PATCH_SIZE, page.top - PATCH_SIZE, PATCH_SIZE, PATCH_SIZE);
    1.61 +        drawPatch(context, PATCH_SIZE, PATCH_SIZE * 3,                                     /* 1 */
    1.62 +                  page.left, page.top - PATCH_SIZE, page.width(), PATCH_SIZE);
    1.63 +        drawPatch(context, PATCH_SIZE * 2, PATCH_SIZE * 3,                                 /* 2 */
    1.64 +                  page.right, page.top - PATCH_SIZE, PATCH_SIZE, PATCH_SIZE);
    1.65 +        drawPatch(context, 0, PATCH_SIZE * 2,                                              /* 3 */
    1.66 +                  page.left - PATCH_SIZE, page.top, PATCH_SIZE, page.height());
    1.67 +        drawPatch(context, PATCH_SIZE * 2, PATCH_SIZE * 2,                                 /* 4 */
    1.68 +                  page.right, page.top, PATCH_SIZE, page.height());
    1.69 +        drawPatch(context, 0, PATCH_SIZE,                                                  /* 5 */
    1.70 +                  page.left - PATCH_SIZE, page.bottom, PATCH_SIZE, PATCH_SIZE);
    1.71 +        drawPatch(context, PATCH_SIZE, PATCH_SIZE,                                         /* 6 */
    1.72 +                  page.left, page.bottom, page.width(), PATCH_SIZE);
    1.73 +        drawPatch(context, PATCH_SIZE * 2, PATCH_SIZE,                                     /* 7 */
    1.74 +                  page.right, page.bottom, PATCH_SIZE, PATCH_SIZE);
    1.75 +    }
    1.76 +
    1.77 +    private void drawPatch(RenderContext context, int textureX, int textureY,
    1.78 +                           float tileX, float tileY, float tileWidth, float tileHeight) {
    1.79 +        RectF viewport = context.viewport;
    1.80 +        float viewportHeight = viewport.height();
    1.81 +        float drawX = tileX - viewport.left - context.offset.x;
    1.82 +        float drawY = viewportHeight - (tileY + tileHeight - viewport.top) - context.offset.y;
    1.83 +
    1.84 +        float[] coords = {
    1.85 +            //x, y, z, texture_x, texture_y
    1.86 +            drawX/viewport.width(), drawY/viewport.height(), 0,
    1.87 +            textureX/(float)TEXTURE_SIZE, textureY/(float)TEXTURE_SIZE,
    1.88 +
    1.89 +            drawX/viewport.width(), (drawY+tileHeight)/viewport.height(), 0,
    1.90 +            textureX/(float)TEXTURE_SIZE, (textureY+PATCH_SIZE)/(float)TEXTURE_SIZE,
    1.91 +
    1.92 +            (drawX+tileWidth)/viewport.width(), drawY/viewport.height(), 0,
    1.93 +            (textureX+PATCH_SIZE)/(float)TEXTURE_SIZE, textureY/(float)TEXTURE_SIZE,
    1.94 +
    1.95 +            (drawX+tileWidth)/viewport.width(), (drawY+tileHeight)/viewport.height(), 0,
    1.96 +            (textureX+PATCH_SIZE)/(float)TEXTURE_SIZE, (textureY+PATCH_SIZE)/(float)TEXTURE_SIZE
    1.97 +
    1.98 +        };
    1.99 +
   1.100 +        // Get the buffer and handles from the context
   1.101 +        FloatBuffer coordBuffer = context.coordBuffer;
   1.102 +        int positionHandle = context.positionHandle;
   1.103 +        int textureHandle = context.textureHandle;
   1.104 +
   1.105 +        // Make sure we are at position zero in the buffer in case other draw methods did not clean
   1.106 +        // up after themselves
   1.107 +        coordBuffer.position(0);
   1.108 +        coordBuffer.put(coords);
   1.109 +
   1.110 +        // Unbind any the current array buffer so we can use client side buffers
   1.111 +        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
   1.112 +
   1.113 +        // Vertex coordinates are x,y,z starting at position 0 into the buffer.
   1.114 +        coordBuffer.position(0);
   1.115 +        GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20, coordBuffer);
   1.116 +
   1.117 +        // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
   1.118 +        coordBuffer.position(3);
   1.119 +        GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20, coordBuffer);
   1.120 +
   1.121 +        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
   1.122 +                               GLES20.GL_CLAMP_TO_EDGE);
   1.123 +        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
   1.124 +                               GLES20.GL_CLAMP_TO_EDGE);
   1.125 +
   1.126 +        // Use bilinear filtering for both magnification and minimization of the texture. This
   1.127 +        // applies only to the shadow layer so we do not incur a high overhead.
   1.128 +        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
   1.129 +                               GLES20.GL_LINEAR);
   1.130 +        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
   1.131 +                               GLES20.GL_LINEAR);
   1.132 +
   1.133 +        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
   1.134 +    }
   1.135 +}

mercurial