1c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed/* 2c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Copyright (C) 2009 The Android Open Source Project 3c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * 4c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Licensed under the Apache License, Version 2.0 (the "License"); 5c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * you may not use this file except in compliance with the License. 6c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * You may obtain a copy of the License at 7c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * 8c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * http://www.apache.org/licenses/LICENSE-2.0 9c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * 10c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Unless required by applicable law or agreed to in writing, software 11c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * distributed under the License is distributed on an "AS IS" BASIS, 12c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * See the License for the specific language governing permissions and 14c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * limitations under the License. 15c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed */ 16c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 17c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reedpackage android.graphics.utils; 18c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 19c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reedimport android.graphics.Bitmap; 20c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reedimport android.graphics.BitmapShader; 21c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reedimport android.graphics.Canvas; 22c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reedimport android.graphics.Paint; 23c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reedimport android.graphics.Shader; 24c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reedimport android.graphics.Xfermode; 25c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 26c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed/** 27c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * @hide 28c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed */ 29c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reedpublic class BoundaryPatch { 30c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private Paint mPaint; 31c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private Bitmap mTexture; 32c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private int mRows; 33c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private int mCols; 34c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private float[] mCubicPoints; 35c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private boolean mDirty; 36c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed // these are the computed output of the native code 37c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private float[] mVerts; 38c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private short[] mIndices; 39c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 40c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed public BoundaryPatch() { 41c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mRows = mCols = 2; // default minimum 42c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mCubicPoints = new float[24]; 43c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mPaint = new Paint(); 44c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mPaint.setDither(true); 45c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mPaint.setFilterBitmap(true); 46c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mDirty = true; 47c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 48c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 49c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed /** 50c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Set the boundary to be 4 cubics. This takes a single array of floats, 51c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * and picks up the 12 pairs starting at offset, and treats them as 52c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * the x,y coordinates of the cubic control points. The points wrap around 53c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * a patch, as follows. For documentation purposes, pts[i] will mean the 54c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * x,y pair of floats, as if pts[] were an array of "points". 55c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * 56c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Top: pts[0..3] 57c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Right: pts[3..6] 58c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Bottom: pts[6..9] 59c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Right: pts[9..11], pts[0] 60c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * 61c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * The coordinates are copied from the input array, so subsequent changes 62c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * to pts[] will not be reflected in the boundary. 63c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * 64c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * @param pts The src array of x,y pairs for the boundary cubics 65c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * @param offset The index into pts of the first pair 66c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * @param rows The number of points across to approximate the boundary. 67c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Must be >= 2, though very large values may slow down drawing 68c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * @param cols The number of points down to approximate the boundary. 69c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Must be >= 2, though very large values may slow down drawing 70c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed */ 71c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed public void setCubicBoundary(float[] pts, int offset, int rows, int cols) { 72c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed if (rows < 2 || cols < 2) { 73c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed throw new RuntimeException("rows and cols must be >= 2"); 74c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 75c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed System.arraycopy(pts, offset, mCubicPoints, 0, 24); 76c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed if (mRows != rows || mCols != cols) { 77c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mRows = rows; 78c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mCols = cols; 79c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 80c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mDirty = true; 81c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 82c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 83c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed /** 84c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Reference a bitmap texture to be mapped onto the patch. 85c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed */ 86c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed public void setTexture(Bitmap texture) { 87c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed if (mTexture != texture) { 88c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed if (mTexture == null || 89c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mTexture.getWidth() != texture.getWidth() || 90c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mTexture.getHeight() != texture.getHeight()) { 91c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed // need to recompute texture coordinates 92c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mDirty = true; 93c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 94c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mTexture = texture; 95c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mPaint.setShader(new BitmapShader(texture, 96c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed Shader.TileMode.CLAMP, 97c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed Shader.TileMode.CLAMP)); 98c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 99c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 100c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 101c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed /** 102c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Return the paint flags for the patch 103c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed */ 104c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed public int getPaintFlags() { 105c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed return mPaint.getFlags(); 106c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 107c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 108c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed /** 109c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Set the paint flags for the patch 110c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed */ 111c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed public void setPaintFlags(int flags) { 112c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mPaint.setFlags(flags); 113c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 114c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 115c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed /** 116c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Set the xfermode for the patch 117c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed */ 118c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed public void setXfermode(Xfermode mode) { 119c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mPaint.setXfermode(mode); 120c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 121c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 122c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed /** 123c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Set the alpha for the patch 124c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed */ 125c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed public void setAlpha(int alpha) { 126c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mPaint.setAlpha(alpha); 127c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 128c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 129c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed /** 130c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * Draw the patch onto the canvas. 131c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * 132c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed * setCubicBoundary() and setTexture() must be called before drawing. 133c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed */ 134c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed public void draw(Canvas canvas) { 135c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed if (mDirty) { 136c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed buildCache(); 137c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mDirty = false; 138c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 139c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 140c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed // cut the count in half, since mVerts.length is really the length of 141c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed // the verts[] and tex[] arrays combined 142c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed // (tex[] are stored after verts[]) 143c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed int vertCount = mVerts.length >> 1; 144c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertCount, 145c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mVerts, 0, mVerts, vertCount, null, 0, 146c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mIndices, 0, mIndices.length, 147c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mPaint); 148c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 149c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 150c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private void buildCache() { 151c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed // we need mRows * mCols points, for verts and another set for textures 152c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed // so *2 for going from points -> floats, and *2 for verts and textures 153c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed int vertCount = mRows * mCols * 4; 154c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed if (mVerts == null || mVerts.length != vertCount) { 155c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mVerts = new float[vertCount]; 156c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 157c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 158c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed int indexCount = (mRows - 1) * (mCols - 1) * 6; 159c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed if (mIndices == null || mIndices.length != indexCount) { 160c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mIndices = new short[indexCount]; 161c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 162c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 163c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed nativeComputeCubicPatch(mCubicPoints, 164c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mTexture.getWidth(), mTexture.getHeight(), 165c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed mRows, mCols, mVerts, mIndices); 166c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed } 167c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 168c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed private static native 169c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed void nativeComputeCubicPatch(float[] cubicPoints, 170c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed int texW, int texH, int rows, int cols, 171c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed float[] verts, short[] indices); 172c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed} 173c04851fd0af87f44a7d7351e0c17442fa1d3fc28Mike Reed 174