jdk/src/share/classes/java/awt/RadialGradientPaintContext.java
author rkennke
Wed, 03 Feb 2010 10:02:33 +0100
changeset 4825 2398a67f1f58
parent 2 90ce3da70b43
child 5506 202f599c92aa
permissions -rw-r--r--
6896335: GraphicsEnvironment.getDefaultScreenDevice() throws UnsatisfiedLinkError in headless mode Summary: Use local ge variable instead of localEnv field in GE. Reviewed-by: igor, prr
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
2
90ce3da70b43 Initial load
duke
parents:
diff changeset
     1
/*
90ce3da70b43 Initial load
duke
parents:
diff changeset
     2
 * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
90ce3da70b43 Initial load
duke
parents:
diff changeset
     4
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
90ce3da70b43 Initial load
duke
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
90ce3da70b43 Initial load
duke
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Sun designates this
90ce3da70b43 Initial load
duke
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
90ce3da70b43 Initial load
duke
parents:
diff changeset
     9
 * by Sun in the LICENSE file that accompanied this code.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    10
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
90ce3da70b43 Initial load
duke
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
90ce3da70b43 Initial load
duke
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
90ce3da70b43 Initial load
duke
parents:
diff changeset
    15
 * accompanied this code).
90ce3da70b43 Initial load
duke
parents:
diff changeset
    16
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
90ce3da70b43 Initial load
duke
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    20
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    21
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
90ce3da70b43 Initial load
duke
parents:
diff changeset
    22
 * CA 95054 USA or visit www.sun.com if you need additional information or
90ce3da70b43 Initial load
duke
parents:
diff changeset
    23
 * have any questions.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    24
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    25
90ce3da70b43 Initial load
duke
parents:
diff changeset
    26
package java.awt;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    27
90ce3da70b43 Initial load
duke
parents:
diff changeset
    28
import java.awt.MultipleGradientPaint.CycleMethod;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    29
import java.awt.MultipleGradientPaint.ColorSpaceType;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    30
import java.awt.geom.AffineTransform;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    31
import java.awt.geom.Rectangle2D;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    32
import java.awt.image.ColorModel;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    33
90ce3da70b43 Initial load
duke
parents:
diff changeset
    34
/**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    35
 * Provides the actual implementation for the RadialGradientPaint.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    36
 * This is where the pixel processing is done.  A RadialGradienPaint
90ce3da70b43 Initial load
duke
parents:
diff changeset
    37
 * only supports circular gradients, but it should be possible to scale
90ce3da70b43 Initial load
duke
parents:
diff changeset
    38
 * the circle to look approximately elliptical, by means of a
90ce3da70b43 Initial load
duke
parents:
diff changeset
    39
 * gradient transform passed into the RadialGradientPaint constructor.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    40
 *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    41
 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
90ce3da70b43 Initial load
duke
parents:
diff changeset
    42
 */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    43
final class RadialGradientPaintContext extends MultipleGradientPaintContext {
90ce3da70b43 Initial load
duke
parents:
diff changeset
    44
90ce3da70b43 Initial load
duke
parents:
diff changeset
    45
    /** True when (focus == center).  */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    46
    private boolean isSimpleFocus = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    47
90ce3da70b43 Initial load
duke
parents:
diff changeset
    48
    /** True when (cycleMethod == NO_CYCLE). */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    49
    private boolean isNonCyclic = false;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    50
90ce3da70b43 Initial load
duke
parents:
diff changeset
    51
    /** Radius of the outermost circle defining the 100% gradient stop. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    52
    private float radius;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    53
90ce3da70b43 Initial load
duke
parents:
diff changeset
    54
    /** Variables representing center and focus points. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    55
    private float centerX, centerY, focusX, focusY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    56
90ce3da70b43 Initial load
duke
parents:
diff changeset
    57
    /** Radius of the gradient circle squared. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    58
    private float radiusSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    59
90ce3da70b43 Initial load
duke
parents:
diff changeset
    60
    /** Constant part of X, Y user space coordinates. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    61
    private float constA, constB;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    62
90ce3da70b43 Initial load
duke
parents:
diff changeset
    63
    /** Constant second order delta for simple loop. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    64
    private float gDeltaDelta;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    65
90ce3da70b43 Initial load
duke
parents:
diff changeset
    66
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    67
     * This value represents the solution when focusX == X.  It is called
90ce3da70b43 Initial load
duke
parents:
diff changeset
    68
     * trivial because it is easier to calculate than the general case.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    69
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    70
    private float trivial;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    71
90ce3da70b43 Initial load
duke
parents:
diff changeset
    72
    /** Amount for offset when clamping focus. */
90ce3da70b43 Initial load
duke
parents:
diff changeset
    73
    private static final float SCALEBACK = .99f;
90ce3da70b43 Initial load
duke
parents:
diff changeset
    74
90ce3da70b43 Initial load
duke
parents:
diff changeset
    75
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
    76
     * Constructor for RadialGradientPaintContext.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    77
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
    78
     * @param paint the {@code RadialGradientPaint} from which this context
90ce3da70b43 Initial load
duke
parents:
diff changeset
    79
     *              is created
90ce3da70b43 Initial load
duke
parents:
diff changeset
    80
     * @param cm the {@code ColorModel} that receives
90ce3da70b43 Initial load
duke
parents:
diff changeset
    81
     *           the {@code Paint} data (this is used only as a hint)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    82
     * @param deviceBounds the device space bounding box of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    83
     *                     graphics primitive being rendered
90ce3da70b43 Initial load
duke
parents:
diff changeset
    84
     * @param userBounds the user space bounding box of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    85
     *                   graphics primitive being rendered
90ce3da70b43 Initial load
duke
parents:
diff changeset
    86
     * @param t the {@code AffineTransform} from user
90ce3da70b43 Initial load
duke
parents:
diff changeset
    87
     *          space into device space (gradientTransform should be
90ce3da70b43 Initial load
duke
parents:
diff changeset
    88
     *          concatenated with this)
90ce3da70b43 Initial load
duke
parents:
diff changeset
    89
     * @param hints the hints that the context object uses to choose
90ce3da70b43 Initial load
duke
parents:
diff changeset
    90
     *              between rendering alternatives
90ce3da70b43 Initial load
duke
parents:
diff changeset
    91
     * @param cx the center X coordinate in user space of the circle defining
90ce3da70b43 Initial load
duke
parents:
diff changeset
    92
     *           the gradient.  The last color of the gradient is mapped to
90ce3da70b43 Initial load
duke
parents:
diff changeset
    93
     *           the perimeter of this circle.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    94
     * @param cy the center Y coordinate in user space of the circle defining
90ce3da70b43 Initial load
duke
parents:
diff changeset
    95
     *           the gradient.  The last color of the gradient is mapped to
90ce3da70b43 Initial load
duke
parents:
diff changeset
    96
     *           the perimeter of this circle.
90ce3da70b43 Initial load
duke
parents:
diff changeset
    97
     * @param r the radius of the circle defining the extents of the
90ce3da70b43 Initial load
duke
parents:
diff changeset
    98
     *          color gradient
90ce3da70b43 Initial load
duke
parents:
diff changeset
    99
     * @param fx the X coordinate in user space to which the first color
90ce3da70b43 Initial load
duke
parents:
diff changeset
   100
     *           is mapped
90ce3da70b43 Initial load
duke
parents:
diff changeset
   101
     * @param fy the Y coordinate in user space to which the first color
90ce3da70b43 Initial load
duke
parents:
diff changeset
   102
     *           is mapped
90ce3da70b43 Initial load
duke
parents:
diff changeset
   103
     * @param fractions the fractions specifying the gradient distribution
90ce3da70b43 Initial load
duke
parents:
diff changeset
   104
     * @param colors the gradient colors
90ce3da70b43 Initial load
duke
parents:
diff changeset
   105
     * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
90ce3da70b43 Initial load
duke
parents:
diff changeset
   106
     * @param colorSpace which colorspace to use for interpolation,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   107
     *                   either SRGB or LINEAR_RGB
90ce3da70b43 Initial load
duke
parents:
diff changeset
   108
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   109
    RadialGradientPaintContext(RadialGradientPaint paint,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   110
                               ColorModel cm,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   111
                               Rectangle deviceBounds,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   112
                               Rectangle2D userBounds,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   113
                               AffineTransform t,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   114
                               RenderingHints hints,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   115
                               float cx, float cy,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   116
                               float r,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   117
                               float fx, float fy,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   118
                               float[] fractions,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   119
                               Color[] colors,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   120
                               CycleMethod cycleMethod,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   121
                               ColorSpaceType colorSpace)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   122
    {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   123
        super(paint, cm, deviceBounds, userBounds, t, hints,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   124
              fractions, colors, cycleMethod, colorSpace);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   125
90ce3da70b43 Initial load
duke
parents:
diff changeset
   126
        // copy some parameters
90ce3da70b43 Initial load
duke
parents:
diff changeset
   127
        centerX = cx;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   128
        centerY = cy;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   129
        focusX = fx;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   130
        focusY = fy;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   131
        radius = r;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   132
90ce3da70b43 Initial load
duke
parents:
diff changeset
   133
        this.isSimpleFocus = (focusX == centerX) && (focusY == centerY);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   134
        this.isNonCyclic = (cycleMethod == CycleMethod.NO_CYCLE);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   135
90ce3da70b43 Initial load
duke
parents:
diff changeset
   136
        // for use in the quadractic equation
90ce3da70b43 Initial load
duke
parents:
diff changeset
   137
        radiusSq = radius * radius;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   138
90ce3da70b43 Initial load
duke
parents:
diff changeset
   139
        float dX = focusX - centerX;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   140
        float dY = focusY - centerY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   141
90ce3da70b43 Initial load
duke
parents:
diff changeset
   142
        double distSq = (dX * dX) + (dY * dY);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   143
90ce3da70b43 Initial load
duke
parents:
diff changeset
   144
        // test if distance from focus to center is greater than the radius
90ce3da70b43 Initial load
duke
parents:
diff changeset
   145
        if (distSq > radiusSq * SCALEBACK) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   146
            // clamp focus to radius
90ce3da70b43 Initial load
duke
parents:
diff changeset
   147
            float scalefactor = (float)Math.sqrt(radiusSq * SCALEBACK / distSq);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   148
            dX = dX * scalefactor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   149
            dY = dY * scalefactor;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   150
            focusX = centerX + dX;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   151
            focusY = centerY + dY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   152
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   153
90ce3da70b43 Initial load
duke
parents:
diff changeset
   154
        // calculate the solution to be used in the case where X == focusX
90ce3da70b43 Initial load
duke
parents:
diff changeset
   155
        // in cyclicCircularGradientFillRaster()
90ce3da70b43 Initial load
duke
parents:
diff changeset
   156
        trivial = (float)Math.sqrt(radiusSq - (dX * dX));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   157
90ce3da70b43 Initial load
duke
parents:
diff changeset
   158
        // constant parts of X, Y user space coordinates
90ce3da70b43 Initial load
duke
parents:
diff changeset
   159
        constA = a02 - centerX;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   160
        constB = a12 - centerY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   161
90ce3da70b43 Initial load
duke
parents:
diff changeset
   162
        // constant second order delta for simple loop
90ce3da70b43 Initial load
duke
parents:
diff changeset
   163
        gDeltaDelta = 2 * ( a00 *  a00 +  a10 *  a10) / radiusSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   164
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   165
90ce3da70b43 Initial load
duke
parents:
diff changeset
   166
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   167
     * Return a Raster containing the colors generated for the graphics
90ce3da70b43 Initial load
duke
parents:
diff changeset
   168
     * operation.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   169
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   170
     * @param x,y,w,h the area in device space for which colors are
90ce3da70b43 Initial load
duke
parents:
diff changeset
   171
     * generated.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   172
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   173
    protected void fillRaster(int pixels[], int off, int adjust,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   174
                              int x, int y, int w, int h)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   175
    {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   176
        if (isSimpleFocus && isNonCyclic && isSimpleLookup) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   177
            simpleNonCyclicFillRaster(pixels, off, adjust, x, y, w, h);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   178
        } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   179
            cyclicCircularGradientFillRaster(pixels, off, adjust, x, y, w, h);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   180
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   181
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   182
90ce3da70b43 Initial load
duke
parents:
diff changeset
   183
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   184
     * This code works in the simplest of cases, where the focus == center
90ce3da70b43 Initial load
duke
parents:
diff changeset
   185
     * point, the gradient is noncyclic, and the gradient lookup method is
90ce3da70b43 Initial load
duke
parents:
diff changeset
   186
     * fast (single array index, no conversion necessary).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   187
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   188
    private void simpleNonCyclicFillRaster(int pixels[], int off, int adjust,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   189
                                           int x, int y, int w, int h)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   190
    {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   191
        /* We calculate sqrt(X^2 + Y^2) relative to the radius
90ce3da70b43 Initial load
duke
parents:
diff changeset
   192
         * size to get the fraction for the color to use.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   193
         *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   194
         * Each step along the scanline adds (a00, a10) to (X, Y).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   195
         * If we precalculate:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   196
         *   gRel = X^2+Y^2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   197
         * for the start of the row, then for each step we need to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   198
         * calculate:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   199
         *   gRel' = (X+a00)^2 + (Y+a10)^2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   200
         *         = X^2 + 2*X*a00 + a00^2 + Y^2 + 2*Y*a10 + a10^2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   201
         *         = (X^2+Y^2) + 2*(X*a00+Y*a10) + (a00^2+a10^2)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   202
         *         = gRel + 2*(X*a00+Y*a10) + (a00^2+a10^2)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   203
         *         = gRel + 2*DP + SD
90ce3da70b43 Initial load
duke
parents:
diff changeset
   204
         * (where DP = dot product between X,Y and a00,a10
90ce3da70b43 Initial load
duke
parents:
diff changeset
   205
         *  and   SD = dot product square of the delta vector)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   206
         * For the step after that we get:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   207
         *   gRel'' = (X+2*a00)^2 + (Y+2*a10)^2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   208
         *          = X^2 + 4*X*a00 + 4*a00^2 + Y^2 + 4*Y*a10 + 4*a10^2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   209
         *          = (X^2+Y^2) + 4*(X*a00+Y*a10) + 4*(a00^2+a10^2)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   210
         *          = gRel  + 4*DP + 4*SD
90ce3da70b43 Initial load
duke
parents:
diff changeset
   211
         *          = gRel' + 2*DP + 3*SD
90ce3da70b43 Initial load
duke
parents:
diff changeset
   212
         * The increment changed by:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   213
         *     (gRel'' - gRel') - (gRel' - gRel)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   214
         *   = (2*DP + 3*SD) - (2*DP + SD)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   215
         *   = 2*SD
90ce3da70b43 Initial load
duke
parents:
diff changeset
   216
         * Note that this value depends only on the (inverse of the)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   217
         * transformation matrix and so is a constant for the loop.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   218
         * To make this all relative to the unit circle, we need to
90ce3da70b43 Initial load
duke
parents:
diff changeset
   219
         * divide all values as follows:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   220
         *   [XY] /= radius
90ce3da70b43 Initial load
duke
parents:
diff changeset
   221
         *   gRel /= radiusSq
90ce3da70b43 Initial load
duke
parents:
diff changeset
   222
         *   DP   /= radiusSq
90ce3da70b43 Initial load
duke
parents:
diff changeset
   223
         *   SD   /= radiusSq
90ce3da70b43 Initial load
duke
parents:
diff changeset
   224
         */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   225
        // coordinates of UL corner in "user space" relative to center
90ce3da70b43 Initial load
duke
parents:
diff changeset
   226
        float rowX = (a00*x) + (a01*y) + constA;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   227
        float rowY = (a10*x) + (a11*y) + constB;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   228
90ce3da70b43 Initial load
duke
parents:
diff changeset
   229
        // second order delta calculated in constructor
90ce3da70b43 Initial load
duke
parents:
diff changeset
   230
        float gDeltaDelta = this.gDeltaDelta;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   231
90ce3da70b43 Initial load
duke
parents:
diff changeset
   232
        // adjust is (scan-w) of pixels array, we need (scan)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   233
        adjust += w;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   234
90ce3da70b43 Initial load
duke
parents:
diff changeset
   235
        // rgb of the 1.0 color used when the distance exceeds gradient radius
90ce3da70b43 Initial load
duke
parents:
diff changeset
   236
        int rgbclip = gradient[fastGradientArraySize];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   237
90ce3da70b43 Initial load
duke
parents:
diff changeset
   238
        for (int j = 0; j < h; j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   239
            // these values depend on the coordinates of the start of the row
90ce3da70b43 Initial load
duke
parents:
diff changeset
   240
            float gRel   =      (rowX * rowX + rowY * rowY) / radiusSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   241
            float gDelta = (2 * ( a00 * rowX +  a10 * rowY) / radiusSq +
90ce3da70b43 Initial load
duke
parents:
diff changeset
   242
                            gDeltaDelta/2);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   243
90ce3da70b43 Initial load
duke
parents:
diff changeset
   244
            /* Use optimized loops for any cases where gRel >= 1.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   245
             * We do not need to calculate sqrt(gRel) for these
90ce3da70b43 Initial load
duke
parents:
diff changeset
   246
             * values since sqrt(N>=1) == (M>=1).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   247
             * Note that gRel follows a parabola which can only be < 1
90ce3da70b43 Initial load
duke
parents:
diff changeset
   248
             * for a small region around the center on each scanline. In
90ce3da70b43 Initial load
duke
parents:
diff changeset
   249
             * particular:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   250
             *   gDeltaDelta is always positive
90ce3da70b43 Initial load
duke
parents:
diff changeset
   251
             *   gDelta is <0 until it crosses the midpoint, then >0
90ce3da70b43 Initial load
duke
parents:
diff changeset
   252
             * To the left and right of that region, it will always be
90ce3da70b43 Initial load
duke
parents:
diff changeset
   253
             * >=1 out to infinity, so we can process the line in 3
90ce3da70b43 Initial load
duke
parents:
diff changeset
   254
             * regions:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   255
             *   out to the left  - quick fill until gRel < 1, updating gRel
90ce3da70b43 Initial load
duke
parents:
diff changeset
   256
             *   in the heart     - slow fraction=sqrt fill while gRel < 1
90ce3da70b43 Initial load
duke
parents:
diff changeset
   257
             *   out to the right - quick fill rest of scanline, ignore gRel
90ce3da70b43 Initial load
duke
parents:
diff changeset
   258
             */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   259
            int i = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   260
            // Quick fill for "out to the left"
90ce3da70b43 Initial load
duke
parents:
diff changeset
   261
            while (i < w && gRel >= 1.0f) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   262
                pixels[off + i] = rgbclip;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   263
                gRel += gDelta;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   264
                gDelta += gDeltaDelta;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   265
                i++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   266
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   267
            // Slow fill for "in the heart"
90ce3da70b43 Initial load
duke
parents:
diff changeset
   268
            while (i < w && gRel < 1.0f) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   269
                int gIndex;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   270
90ce3da70b43 Initial load
duke
parents:
diff changeset
   271
                if (gRel <= 0) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   272
                    gIndex = 0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   273
                } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   274
                    float fIndex = gRel * SQRT_LUT_SIZE;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   275
                    int iIndex = (int) (fIndex);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   276
                    float s0 = sqrtLut[iIndex];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   277
                    float s1 = sqrtLut[iIndex+1] - s0;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   278
                    fIndex = s0 + (fIndex - iIndex) * s1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   279
                    gIndex = (int) (fIndex * fastGradientArraySize);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   280
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   281
90ce3da70b43 Initial load
duke
parents:
diff changeset
   282
                // store the color at this point
90ce3da70b43 Initial load
duke
parents:
diff changeset
   283
                pixels[off + i] = gradient[gIndex];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   284
90ce3da70b43 Initial load
duke
parents:
diff changeset
   285
                // incremental calculation
90ce3da70b43 Initial load
duke
parents:
diff changeset
   286
                gRel += gDelta;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   287
                gDelta += gDeltaDelta;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   288
                i++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   289
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   290
            // Quick fill to end of line for "out to the right"
90ce3da70b43 Initial load
duke
parents:
diff changeset
   291
            while (i < w) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   292
                pixels[off + i] = rgbclip;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   293
                i++;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   294
            }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   295
90ce3da70b43 Initial load
duke
parents:
diff changeset
   296
            off += adjust;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   297
            rowX += a01;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   298
            rowY += a11;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   299
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   300
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   301
90ce3da70b43 Initial load
duke
parents:
diff changeset
   302
    // SQRT_LUT_SIZE must be a power of 2 for the test above to work.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   303
    private static final int SQRT_LUT_SIZE = (1 << 11);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   304
    private static float sqrtLut[] = new float[SQRT_LUT_SIZE+1];
90ce3da70b43 Initial load
duke
parents:
diff changeset
   305
    static {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   306
        for (int i = 0; i < sqrtLut.length; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   307
            sqrtLut[i] = (float) Math.sqrt(i / ((float) SQRT_LUT_SIZE));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   308
        }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   309
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   310
90ce3da70b43 Initial load
duke
parents:
diff changeset
   311
    /**
90ce3da70b43 Initial load
duke
parents:
diff changeset
   312
     * Fill the raster, cycling the gradient colors when a point falls outside
90ce3da70b43 Initial load
duke
parents:
diff changeset
   313
     * of the perimeter of the 100% stop circle.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   314
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   315
     * This calculation first computes the intersection point of the line
90ce3da70b43 Initial load
duke
parents:
diff changeset
   316
     * from the focus through the current point in the raster, and the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   317
     * perimeter of the gradient circle.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   318
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   319
     * Then it determines the percentage distance of the current point along
90ce3da70b43 Initial load
duke
parents:
diff changeset
   320
     * that line (focus is 0%, perimeter is 100%).
90ce3da70b43 Initial load
duke
parents:
diff changeset
   321
     *
90ce3da70b43 Initial load
duke
parents:
diff changeset
   322
     * Equation of a circle centered at (a,b) with radius r:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   323
     *     (x-a)^2 + (y-b)^2 = r^2
90ce3da70b43 Initial load
duke
parents:
diff changeset
   324
     * Equation of a line with slope m and y-intercept b:
90ce3da70b43 Initial load
duke
parents:
diff changeset
   325
     *     y = mx + b
90ce3da70b43 Initial load
duke
parents:
diff changeset
   326
     * Replacing y in the circle equation and solving using the quadratic
90ce3da70b43 Initial load
duke
parents:
diff changeset
   327
     * formula produces the following set of equations.  Constant factors have
90ce3da70b43 Initial load
duke
parents:
diff changeset
   328
     * been extracted out of the inner loop.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   329
     */
90ce3da70b43 Initial load
duke
parents:
diff changeset
   330
    private void cyclicCircularGradientFillRaster(int pixels[], int off,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   331
                                                  int adjust,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   332
                                                  int x, int y,
90ce3da70b43 Initial load
duke
parents:
diff changeset
   333
                                                  int w, int h)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   334
    {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   335
        // constant part of the C factor of the quadratic equation
90ce3da70b43 Initial load
duke
parents:
diff changeset
   336
        final double constC =
90ce3da70b43 Initial load
duke
parents:
diff changeset
   337
            -radiusSq + (centerX * centerX) + (centerY * centerY);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   338
90ce3da70b43 Initial load
duke
parents:
diff changeset
   339
        // coefficients of the quadratic equation (Ax^2 + Bx + C = 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   340
        double A, B, C;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   341
90ce3da70b43 Initial load
duke
parents:
diff changeset
   342
        // slope and y-intercept of the focus-perimeter line
90ce3da70b43 Initial load
duke
parents:
diff changeset
   343
        double slope, yintcpt;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   344
90ce3da70b43 Initial load
duke
parents:
diff changeset
   345
        // intersection with circle X,Y coordinate
90ce3da70b43 Initial load
duke
parents:
diff changeset
   346
        double solutionX, solutionY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   347
90ce3da70b43 Initial load
duke
parents:
diff changeset
   348
        // constant parts of X, Y coordinates
90ce3da70b43 Initial load
duke
parents:
diff changeset
   349
        final float constX = (a00*x) + (a01*y) + a02;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   350
        final float constY = (a10*x) + (a11*y) + a12;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   351
90ce3da70b43 Initial load
duke
parents:
diff changeset
   352
        // constants in inner loop quadratic formula
90ce3da70b43 Initial load
duke
parents:
diff changeset
   353
        final float precalc2 =  2 * centerY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   354
        final float precalc3 = -2 * centerX;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   355
90ce3da70b43 Initial load
duke
parents:
diff changeset
   356
        // value between 0 and 1 specifying position in the gradient
90ce3da70b43 Initial load
duke
parents:
diff changeset
   357
        float g;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   358
90ce3da70b43 Initial load
duke
parents:
diff changeset
   359
        // determinant of quadratic formula (should always be > 0)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   360
        float det;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   361
90ce3da70b43 Initial load
duke
parents:
diff changeset
   362
        // sq distance from the current point to focus
90ce3da70b43 Initial load
duke
parents:
diff changeset
   363
        float currentToFocusSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   364
90ce3da70b43 Initial load
duke
parents:
diff changeset
   365
        // sq distance from the intersect point to focus
90ce3da70b43 Initial load
duke
parents:
diff changeset
   366
        float intersectToFocusSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   367
90ce3da70b43 Initial load
duke
parents:
diff changeset
   368
        // temp variables for change in X,Y squared
90ce3da70b43 Initial load
duke
parents:
diff changeset
   369
        float deltaXSq, deltaYSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   370
90ce3da70b43 Initial load
duke
parents:
diff changeset
   371
        // used to index pixels array
90ce3da70b43 Initial load
duke
parents:
diff changeset
   372
        int indexer = off;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   373
90ce3da70b43 Initial load
duke
parents:
diff changeset
   374
        // incremental index change for pixels array
90ce3da70b43 Initial load
duke
parents:
diff changeset
   375
        int pixInc = w+adjust;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   376
90ce3da70b43 Initial load
duke
parents:
diff changeset
   377
        // for every row
90ce3da70b43 Initial load
duke
parents:
diff changeset
   378
        for (int j = 0; j < h; j++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   379
90ce3da70b43 Initial load
duke
parents:
diff changeset
   380
            // user space point; these are constant from column to column
90ce3da70b43 Initial load
duke
parents:
diff changeset
   381
            float X = (a01*j) + constX;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   382
            float Y = (a11*j) + constY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   383
90ce3da70b43 Initial load
duke
parents:
diff changeset
   384
            // for every column (inner loop begins here)
90ce3da70b43 Initial load
duke
parents:
diff changeset
   385
            for (int i = 0; i < w; i++) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   386
90ce3da70b43 Initial load
duke
parents:
diff changeset
   387
                if (X == focusX) {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   388
                    // special case to avoid divide by zero
90ce3da70b43 Initial load
duke
parents:
diff changeset
   389
                    solutionX = focusX;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   390
                    solutionY = centerY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   391
                    solutionY += (Y > focusY) ? trivial : -trivial;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   392
                } else {
90ce3da70b43 Initial load
duke
parents:
diff changeset
   393
                    // slope and y-intercept of the focus-perimeter line
90ce3da70b43 Initial load
duke
parents:
diff changeset
   394
                    slope = (Y - focusY) / (X - focusX);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   395
                    yintcpt = Y - (slope * X);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   396
90ce3da70b43 Initial load
duke
parents:
diff changeset
   397
                    // use the quadratic formula to calculate the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   398
                    // intersection point
90ce3da70b43 Initial load
duke
parents:
diff changeset
   399
                    A = (slope * slope) + 1;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   400
                    B = precalc3 + (-2 * slope * (centerY - yintcpt));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   401
                    C = constC + (yintcpt* (yintcpt - precalc2));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   402
90ce3da70b43 Initial load
duke
parents:
diff changeset
   403
                    det = (float)Math.sqrt((B * B) - (4 * A * C));
90ce3da70b43 Initial load
duke
parents:
diff changeset
   404
                    solutionX = -B;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   405
90ce3da70b43 Initial load
duke
parents:
diff changeset
   406
                    // choose the positive or negative root depending
90ce3da70b43 Initial load
duke
parents:
diff changeset
   407
                    // on where the X coord lies with respect to the focus
90ce3da70b43 Initial load
duke
parents:
diff changeset
   408
                    solutionX += (X < focusX)? -det : det;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   409
                    solutionX = solutionX / (2 * A); // divisor
90ce3da70b43 Initial load
duke
parents:
diff changeset
   410
                    solutionY = (slope * solutionX) + yintcpt;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   411
                }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   412
90ce3da70b43 Initial load
duke
parents:
diff changeset
   413
                // Calculate the square of the distance from the current point
90ce3da70b43 Initial load
duke
parents:
diff changeset
   414
                // to the focus and the square of the distance from the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   415
                // intersection point to the focus. Want the squares so we can
90ce3da70b43 Initial load
duke
parents:
diff changeset
   416
                // do 1 square root after division instead of 2 before.
90ce3da70b43 Initial load
duke
parents:
diff changeset
   417
90ce3da70b43 Initial load
duke
parents:
diff changeset
   418
                deltaXSq = X - focusX;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   419
                deltaXSq = deltaXSq * deltaXSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   420
90ce3da70b43 Initial load
duke
parents:
diff changeset
   421
                deltaYSq = Y - focusY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   422
                deltaYSq = deltaYSq * deltaYSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   423
90ce3da70b43 Initial load
duke
parents:
diff changeset
   424
                currentToFocusSq = deltaXSq + deltaYSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   425
90ce3da70b43 Initial load
duke
parents:
diff changeset
   426
                deltaXSq = (float)solutionX - focusX;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   427
                deltaXSq = deltaXSq * deltaXSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   428
90ce3da70b43 Initial load
duke
parents:
diff changeset
   429
                deltaYSq = (float)solutionY - focusY;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   430
                deltaYSq = deltaYSq * deltaYSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   431
90ce3da70b43 Initial load
duke
parents:
diff changeset
   432
                intersectToFocusSq = deltaXSq + deltaYSq;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   433
90ce3da70b43 Initial load
duke
parents:
diff changeset
   434
                // get the percentage (0-1) of the current point along the
90ce3da70b43 Initial load
duke
parents:
diff changeset
   435
                // focus-circumference line
90ce3da70b43 Initial load
duke
parents:
diff changeset
   436
                g = (float)Math.sqrt(currentToFocusSq / intersectToFocusSq);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   437
90ce3da70b43 Initial load
duke
parents:
diff changeset
   438
                // store the color at this point
90ce3da70b43 Initial load
duke
parents:
diff changeset
   439
                pixels[indexer + i] = indexIntoGradientsArrays(g);
90ce3da70b43 Initial load
duke
parents:
diff changeset
   440
90ce3da70b43 Initial load
duke
parents:
diff changeset
   441
                // incremental change in X, Y
90ce3da70b43 Initial load
duke
parents:
diff changeset
   442
                X += a00;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   443
                Y += a10;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   444
            } //end inner loop
90ce3da70b43 Initial load
duke
parents:
diff changeset
   445
90ce3da70b43 Initial load
duke
parents:
diff changeset
   446
            indexer += pixInc;
90ce3da70b43 Initial load
duke
parents:
diff changeset
   447
        } //end outer loop
90ce3da70b43 Initial load
duke
parents:
diff changeset
   448
    }
90ce3da70b43 Initial load
duke
parents:
diff changeset
   449
}