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 +}