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 < 0 or > > 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