145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet/*
245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet * Copyright (C) 2010 The Android Open Source Project
345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet *
445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet * Licensed under the Apache License, Version 2.0 (the "License");
545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet * you may not use this file except in compliance with the License.
645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet * You may obtain a copy of the License at
745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet *
845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet *      http://www.apache.org/licenses/LICENSE-2.0
945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet *
1045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet * Unless required by applicable law or agreed to in writing, software
1145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet * distributed under the License is distributed on an "AS IS" BASIS,
1245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet * See the License for the specific language governing permissions and
1445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet * limitations under the License.
1545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet */
1645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
1745a7c285985976c23d818665694addbb25e02565Xavier Ducrohetpackage android.graphics;
1845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
19251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohetimport android.graphics.Shader.TileMode;
2045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
2145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet/**
22251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet * Base class for true Gradient shader delegate.
2345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet */
24251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohetpublic abstract class Gradient_Delegate extends Shader_Delegate {
2545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
2645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet    protected final int[] mColors;
2745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet    protected final float[] mPositions;
2845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
29d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    @Override
30d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    public boolean isSupported() {
31d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        // all gradient shaders are supported.
32d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        return true;
33d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    }
34d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
35d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    @Override
36d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    public String getSupportMessage() {
37d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        // all gradient shaders are supported, no need for a gradient support
38d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet        return null;
39d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet    }
40d348b6eaa98e23cb38d90906df109aaa2d20ea7fXavier Ducrohet
4145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet    /**
4245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * Creates the base shader and do some basic test on the parameters.
4345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     *
4445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * @param colors The colors to be distributed along the gradient line
4545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * @param positions May be null. The relative positions [0..1] of each
4645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     *            corresponding color in the colors array. If this is null, the
4745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     *            the colors are distributed evenly along the gradient line.
4845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     */
49251d2e99245095369b52d891a660b2ed270f02e0Xavier Ducrohet    protected Gradient_Delegate(int colors[], float positions[]) {
5045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        if (colors.length < 2) {
5145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            throw new IllegalArgumentException("needs >= 2 number of colors");
5245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
5345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        if (positions != null && colors.length != positions.length) {
5445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            throw new IllegalArgumentException("color and position arrays must be of equal length");
5545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
5645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
5745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        if (positions == null) {
5845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            float spacing = 1.f / (colors.length - 1);
5945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            positions = new float[colors.length];
6045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            positions[0] = 0.f;
6145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            positions[colors.length-1] = 1.f;
6245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            for (int i = 1; i < colors.length - 1 ; i++) {
6345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                positions[i] = spacing * i;
6445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            }
6545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
6645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
6745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        mColors = colors;
6845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        mPositions = positions;
6945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet    }
7045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
7145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet    /**
7245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * Base class for (Java) Gradient Paints. This handles computing the gradient colors based
7345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     * on the color and position lists, as well as the {@link TileMode}
7445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     *
7545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet     */
7645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet    protected abstract static class GradientPaint implements java.awt.Paint {
7745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private final static int GRADIENT_SIZE = 100;
7845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
7945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private final int[] mColors;
8045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private final float[] mPositions;
8145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private final TileMode mTileMode;
8245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private int[] mGradient;
8345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
8445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        protected GradientPaint(int[] colors, float[] positions, TileMode tileMode) {
8545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            mColors = colors;
8645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            mPositions = positions;
8745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            mTileMode = tileMode;
8845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
8945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
9046d43ccfd8cef75b4315828073c094cf1efb05ffXavier Ducrohet        @Override
9145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        public int getTransparency() {
9245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            return java.awt.Paint.TRANSLUCENT;
9345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
9445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
9545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        /**
9645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         * Pre-computes the colors for the gradient. This must be called once before any call
9745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         * to {@link #getGradientColor(float)}
9845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         */
9935ea7cd4c0c89122fda0b57af20061645082ffb9Xavier Ducrohet        protected void precomputeGradientColors() {
10045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            if (mGradient == null) {
10145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                // actually create an array with an extra size, so that we can really go
10245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                // from 0 to SIZE (100%), or currentPos in the loop below will never equal 1.0
10345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                mGradient = new int[GRADIENT_SIZE+1];
10445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
10545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                int prevPos = 0;
10645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                int nextPos = 1;
10745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                for (int i  = 0 ; i <= GRADIENT_SIZE ; i++) {
10845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                    // compute current position
10945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                    float currentPos = (float)i/GRADIENT_SIZE;
11045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                    while (currentPos > mPositions[nextPos]) {
11145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                        prevPos = nextPos++;
11245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                    }
11345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
11445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                    float percent = (currentPos - mPositions[prevPos]) /
11545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                            (mPositions[nextPos] - mPositions[prevPos]);
11645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
11745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                    mGradient[i] = computeColor(mColors[prevPos], mColors[nextPos], percent);
11845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                }
11945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            }
12045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
12145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
12245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        /**
12345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         * Returns the color based on the position in the gradient.
12445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         * <var>pos</var> can be anything, even &lt; 0 or &gt; > 1, as the gradient
12545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         * will use {@link TileMode} value to convert it into a [0,1] value.
12645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         */
12745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        protected int getGradientColor(float pos) {
12845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            if (pos < 0.f) {
1293330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                if (mTileMode != null) {
1303330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                    switch (mTileMode) {
1313330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                        case CLAMP:
1323330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            pos = 0.f;
1333330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            break;
1343330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                        case REPEAT:
135d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            // remove the integer part to stay in the [0,1] range.
136d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            // we also need to invert the value from [-1,0] to [0, 1]
137d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            pos = pos - (float)Math.floor(pos);
1383330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            break;
1393330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                        case MIRROR:
140d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            // this is the same as the positive side, just make the value positive
141d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            // first.
142d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            pos = Math.abs(pos);
143d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet
1443330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            // get the integer and the decimal part
145d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            int intPart = (int)Math.floor(pos);
1463330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            pos = pos - intPart;
147d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            // 0 -> 1 : normal order
148d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            // 1 -> 2: mirrored
1493330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            // etc..
150d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            // this means if the intpart is odd we invert
151d9c64369cf9be6568af2d79c35fb470cc261730dXavier Ducrohet                            if ((intPart % 2) == 1) {
1523330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                                pos = 1.f - pos;
1533330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            }
1543330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            break;
1553330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                    }
1563330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                } else {
1573330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                    pos = 0.0f;
15845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                }
15945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            } else if (pos > 1f) {
1603330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                if (mTileMode != null) {
1613330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                    switch (mTileMode) {
1623330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                        case CLAMP:
1633330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            pos = 1.f;
1643330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            break;
1653330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                        case REPEAT:
1663330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            // remove the integer part to stay in the [0,1] range
1673330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            pos = pos - (float)Math.floor(pos);
1683330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            break;
1693330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                        case MIRROR:
1703330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            // get the integer and the decimal part
1713330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            int intPart = (int)Math.floor(pos);
1723330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            pos = pos - intPart;
1733330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            // 0 -> 1 : normal order
1743330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            // 1 -> 2: mirrored
1753330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            // etc..
1763330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            // this means if the intpart is odd we invert
1773330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            if ((intPart % 2) == 1) {
1783330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                                pos = 1.f - pos;
1793330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            }
1803330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                            break;
1813330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                    }
1823330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                } else {
1833330927bdd2fedcbc8745f99d3f40929f47fdd31Xavier Ducrohet                    pos = 1.0f;
18445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet                }
18545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            }
18645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
18745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            int index = (int)((pos * GRADIENT_SIZE) + .5);
18845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
18945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            return mGradient[index];
19045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
19145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
19245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        /**
19345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         * Returns the color between c1, and c2, based on the percent of the distance
19445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         * between c1 and c2.
19545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         */
19645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private int computeColor(int c1, int c2, float percent) {
19745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            int a = computeChannel((c1 >> 24) & 0xFF, (c2 >> 24) & 0xFF, percent);
19845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            int r = computeChannel((c1 >> 16) & 0xFF, (c2 >> 16) & 0xFF, percent);
19945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            int g = computeChannel((c1 >>  8) & 0xFF, (c2 >>  8) & 0xFF, percent);
20045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            int b = computeChannel((c1      ) & 0xFF, (c2      ) & 0xFF, percent);
20145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            return a << 24 | r << 16 | g << 8 | b;
20245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
20345a7c285985976c23d818665694addbb25e02565Xavier Ducrohet
20445a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        /**
20545a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         * Returns the channel value between 2 values based on the percent of the distance between
20645a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         * the 2 values..
20745a7c285985976c23d818665694addbb25e02565Xavier Ducrohet         */
20845a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        private int computeChannel(int c1, int c2, float percent) {
20945a7c285985976c23d818665694addbb25e02565Xavier Ducrohet            return c1 + (int)((percent * (c2-c1)) + .5);
21045a7c285985976c23d818665694addbb25e02565Xavier Ducrohet        }
21145a7c285985976c23d818665694addbb25e02565Xavier Ducrohet    }
21245a7c285985976c23d818665694addbb25e02565Xavier Ducrohet}
213