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