2362N/A * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 2362N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 2362N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 0N/A // switch to texture unit 1, where paint state is currently enabled 0N/A // Note: The texture object used in SetTexturePaint() will 0N/A // still be bound at this point, so it is safe to call the following. 0N/A // restore control to texture unit 0 0N/A // set each component of the current color state to the extra alpha 0N/A // value, which will effectively apply the extra alpha to each fragment 0N/A // glColor*() is allowed within glBegin()/glEnd() pairs, so 0N/A // no need to reset the current op state here unless the paint 0N/A // state really needs to be changed 0N/A // store the raw (unmodified) pixel value, which may be used for 0N/A // special operations later 0N/A " updating color: r=%02x g=%02x b=%02x a=%02x",
0N/A " updating xor color: r=%02x g=%02x b=%02x xorpixel=%08x",
0N/A/************************* GradientPaint support ****************************/ 0N/A // set up the paint on texture unit 1 (instead of the usual unit 0) 0N/A // texture unit 0 is already active; we can use the helper macro here 0N/A // restore control to texture unit 0 0N/A // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 0N/A/************************** TexturePaint support ****************************/ 0N/A * Note that we explicitly use GL_TEXTURE_2D below rather than using 0N/A * srcOps->textureTarget. This is because the texture wrap mode employed 0N/A * here (GL_REPEAT) is not available for GL_TEXTURE_RECTANGLE_ARB targets. 0N/A * The setup code in OGLPaints.Texture.isPaintValid() and in 0N/A * OGLSurfaceData.initTexture() ensures that we only get here for 0N/A * GL_TEXTURE_2D targets. 0N/A // set up the paint on texture unit 1 (instead of the usual unit 0) 0N/A // texture unit 0 is already active; we can use the helper macro here 0N/A // restore control to texture unit 0 0N/A // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 0N/A/****************** Shared MultipleGradientPaint support ********************/ 0N/A * These constants are identical to those defined in the 0N/A * MultipleGradientPaint.CycleMethod enum; they are copied here for 0N/A * convenience (ideally we would pull them directly from the Java level, 0N/A * but that entails more hassle than it is worth). 0N/A * The following constants are flags that can be bitwise-or'ed together 0N/A * to control how the MultipleGradientPaint shader source code is generated: 0N/A * MULTI_CYCLE_METHOD 0N/A * Placeholder for the CycleMethod enum constant. 0N/A * If set, use the (slower) shader that supports a larger number of 0N/A * gradient colors; otherwise, use the optimized codepath. See 0N/A * If set, apply the alpha mask value from texture unit 0 to the 0N/A * final color result (only used in the MaskFill case). 0N/A * If set, convert the linear RGB result back into the sRGB color space. 0N/A * This value determines the size of the array of programs for each 0N/A * MultipleGradientPaint type. This value reflects the maximum value that 0N/A * can be represented by performing a bitwise-or of all the MULTI_* 0N/A * constants defined above. 0N/A/** Evaluates to true if the given bit is set on the local flags variable. */ 0N/A/** Composes the given parameters as flags into the given flags variable.*/ 0N/A/** Extracts the CycleMethod enum value from the given flags variable. */ 0N/A * The maximum number of gradient "stops" supported by the fragment shader 0N/A * and related code. When the MULTI_LARGE flag is set, we will use 0N/A * MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having 0N/A * two separate values, we can have one highly optimized shader (SMALL) that 0N/A * shader that supports more stops. 0N/A * The maximum number of gradient colors supported by all of the gradient 0N/A * fragment shaders. Note that this value must be a power of two, as it 0N/A * determines the size of the 1D texture created below. It also must be 0N/A * greater than or equal to MAX_FRACTIONS (there is no strict requirement 0N/A * that the two values be equal). 0N/A * The handle to the gradient color table texture object used by the shaders. 0N/A * This is essentially a template of the shader source code that can be used 0N/A * for either LinearGradientPaint or RadialGradientPaint. It includes the 0N/A * structure and some variables that are common to each; the remaining 0N/A * code snippets (for CycleMethod, ColorSpaceType, and mask modulation) 0N/A * are filled in prior to compiling the shader at runtime depending on the 0N/A * paint parameters. See OGLPaints_CreateMultiGradProgram() for more details. 0N/A // gradient texture size (in texels) 0N/A "const int TEXTURE_SIZE = %d;" 0N/A "const int MAX_FRACTIONS = %d;" 0N/A // size of a single texel 0N/A "const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));" 0N/A // size of half of a single texel 0N/A "const float HALF_TEXEL = (FULL_TEXEL / 2.0);" 0N/A // texture containing the gradient colors 0N/A "uniform sampler1D colors;" 0N/A "uniform float fractions[MAX_FRACTIONS];" 0N/A // array of scale factors (one for each interval) 0N/A "uniform float scaleFactors[MAX_FRACTIONS-1];" 0N/A // (placeholder for mask variable) 0N/A // (placeholder for CycleMethod-specific code) 0N/A // calculate interpolated color 0N/A " vec4 result = texture1D(colors, tc);" 0N/A // (placeholder for ColorSpace conversion code) 0N/A // (placeholder for mask modulation code) 0N/A // modulate with gl_Color in order to apply extra alpha 0N/A " gl_FragColor = result * gl_Color;" 0N/A * This code takes a "dist" value as input (as calculated earlier by the 0N/A * coordinate value "tc" that represents the position of the chosen color 0N/A * in the one-dimensional gradient texture (also in the range [0,1]). 0N/A * One naive way to implement this would be to iterate through the fractions 0N/A * to figure out in which interval "dist" falls, and then compute the 0N/A * relative distance between the two nearest stops. This approach would 0N/A * require an "if" check on every iteration, and it is best to avoid 0N/A * conditionals in fragment shaders for performance reasons. Also, one might 0N/A * be tempted to use a break statement to jump out of the loop once the 0N/A * interval was found, but break statements (and non-constant loop bounds) 0N/A * are not natively available on most graphics hardware today, so that is 0N/A * The more optimal approach used here avoids these issues entirely by using 0N/A * an accumulation function that is equivalent to the process described above. 0N/A * The scaleFactors array is pre-initialized at enable time as follows: 0N/A * scaleFactors[i] = 1.0 / (fractions[i+1] - fractions[i]); 0N/A * For each iteration, we subtract fractions[i] from dist and then multiply 0N/A * that value by scaleFactors[i]. If we are within the target interval, 0N/A * this value will be a fraction in the range [0,1] indicating the relative 0N/A * distance between fraction[i] and fraction[i+1]. If we are below the 0N/A * target interval, this value will be negative, so we clamp it to zero 0N/A * to avoid accumulating any value. If we are above the target interval, 0N/A * the value will be greater than one, so we clamp it to one. Upon exiting 0N/A * the loop, we will have accumulated zero or more 1.0's and a single 0N/A * fractional value. This accumulated value tells us the position of the 0N/A * fragment color in the one-dimensional gradient texture, i.e., the 0N/A * texcoord called "tc". 0N/A "float relFraction = 0.0;" 0N/A "for (i = 0; i < MAX_FRACTIONS-1; i++) {" 0N/A " clamp((dist - fractions[i]) * scaleFactors[i], 0.0, 1.0);" 0N/A // we offset by half a texel so that we find the linearly interpolated 0N/A // color between the two texel centers of interest 0N/A "tc = HALF_TEXEL + (FULL_TEXEL * relFraction);";
0N/A/** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */ 0N/A "if (dist <= 0.0) {" 0N/A "} else if (dist >= 1.0) {" 0N/A // (placeholder for texcoord calculation) 0N/A/** Code for REFLECT that gets plugged into the CycleMethod placeholder. */ 0N/A "dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);" 0N/A // (placeholder for texcoord calculation) 0N/A/** Code for REPEAT that gets plugged into the CycleMethod placeholder. */ 0N/A "dist = fract(dist);" 0N/A // (placeholder for texcoord calculation) 0N/A * Compiles and links the MultipleGradientPaint shader program. If 0N/A * successful, this function returns a handle to the newly created 0N/A * shader program; otherwise returns 0. 0N/A * This code modulates the calculated result color with the 0N/A * corresponding alpha value from the alpha mask texture active 0N/A * on texture unit 0. Only needed when useMask is true (i.e., only 0N/A * for MaskFill operations). 0N/A maskCode =
"result *= texture2D(mask, gl_TexCoord[0].st);";
0N/A * REMIND: This is really wacky, but the gradient shaders will 0N/A * produce completely incorrect results on ATI hardware (at least 0N/A * on first-gen (R300-based) boards) if the shader program does not 0N/A * try to access texture coordinates by using a gl_TexCoord[*] 0N/A * variable. This problem really should be addressed by ATI, but 0N/A * in the meantime it seems we can workaround the issue by inserting 0N/A * a benign operation that accesses gl_TexCoord[0]. Note that we 0N/A * only need to do this for ATI boards and only in the !useMask case, 0N/A * because the useMask case already does access gl_TexCoord[1] and 0N/A * is therefore not affected by this driver bug. 0N/A * This code converts a single pixel in linear RGB space back 0N/A * into sRGB (note: this code was adapted from the 0N/A "result.rgb = 1.055 * pow(result.rgb, vec3(0.416667)) - 0.055;";
0N/A }
else {
// (cycleMethod == CYCLE_REPEAT) 0N/A // compose the final source code string from the various pieces 0N/A "OGLPaints_CreateMultiGradProgram: error creating program");
0N/A // "use" the program object temporarily so that we can set the uniforms 0N/A // set the "uniform" texture unit bindings 0N/A // "unuse" the program object; it will be re-bound later as needed 0N/A // enable the MultipleGradientPaint shader 0N/A // update the "uniform" fraction values 0N/A // fill the remainder of the fractions array with all zeros to 0N/A // prevent using garbage values from previous paints 0N/A // update the "uniform" scale values 0N/A // calculate a scale factor for each interval 0N/A // fill remaining scale factors with zero 0N/A // update the texture containing the gradient colors 0N/A // when we don't have enough colors to fill the entire color gradient, 0N/A // we have to replicate the last color in the right-most texel for 0N/A // the NO_CYCLE case where the texcoord is sometimes forced to 1.0 0N/A/********************** LinearGradientPaint support *************************/ 0N/A * The handles to the LinearGradientPaint fragment program objects. The 0N/A * index to the array should be a bitwise-or'ing of the MULTI_* flags defined 0N/A * above. Note that most applications will likely need to initialize one 0N/A * or two of these elements, so the array is usually sparsely populated. 0N/A * Compiles and links the LinearGradientPaint shader program. If successful, 0N/A * this function returns a handle to the newly created shader program; 0N/A * otherwise returns 0. 0N/A "OGLPaints_CreateLinearGradProgram",
0N/A * To simplify the code and to make it easier to upload a number of 0N/A * uniform values at once, we pack a bunch of scalar (float) values 0N/A * into vec3 values below. Here's how the values are related: 0N/A * yoff = dstOps->yOffset + dstOps->height 0N/A "uniform vec3 params;" 0N/A "uniform float yoff;";
0N/A // note that gl_FragCoord is in window space relative to the 0N/A // lower-left corner, so we have to flip the y-coordinate here 0N/A "vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);" 0N/A "dist = dot(params, fragCoord);";
0N/A // set up the paint on texture unit 1 (instead of the usual unit 0) 0N/A // no need to set GL_MODULATE here (it is ignored when shader is enabled) 0N/A // shouldn't happen, but just in case... 0N/A // update the common "uniform" values (fractions and colors) 0N/A // update the other "uniform" values 0N/A // restore control to texture unit 0 0N/A // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 0N/A/********************** RadialGradientPaint support *************************/ 0N/A * The handles to the RadialGradientPaint fragment program objects. The 0N/A * index to the array should be a bitwise-or'ing of the MULTI_* flags defined 0N/A * above. Note that most applications will likely need to initialize one 0N/A * or two of these elements, so the array is usually sparsely populated. 0N/A * Compiles and links the RadialGradientPaint shader program. If successful, 0N/A * this function returns a handle to the newly created shader program; 0N/A * otherwise returns 0. 0N/A "OGLPaints_CreateRadialGradProgram",
0N/A * To simplify the code and to make it easier to upload a number of 0N/A * uniform values at once, we pack a bunch of scalar (float) values 0N/A * into vec3 and vec4 values below. Here's how the values are related: 0N/A * precalc.x = focusX 0N/A * precalc.y = yoff = dstOps->yOffset + dstOps->height 0N/A * precalc.z = 1.0 - (focusX * focusX) 0N/A * precalc.w = 1.0 / precalc.z 0N/A "uniform vec4 precalc;";
0N/A * The following code is derived from Daniel Rice's whitepaper on 0N/A * radial gradient performance (attached to the bug report for 6521533). 0N/A * Refer to that document as well as the setup code in the Java-level 0N/A // note that gl_FragCoord is in window space relative to the 0N/A // lower-left corner, so we have to flip the y-coordinate here 0N/A " vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);" 0N/A "float x = dot(fragCoord, m0);" 0N/A "float y = dot(fragCoord, m1);" 0N/A "float xfx = x - precalc.x;" 0N/A "dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;";
0N/A // set up the paint on texture unit 1 (instead of the usual unit 0) 0N/A // no need to set GL_MODULATE here (it is ignored when shader is enabled) 0N/A // shouldn't happen, but just in case... 0N/A // update the common "uniform" values (fractions and colors) 0N/A // update the other "uniform" values 0N/A // pack a few unrelated, precalculated values into a single vec4 0N/A // restore control to texture unit 0 0N/A // oglc->pixel has been set appropriately in OGLPaints_ResetPaint() 0N/A#
endif /* !HEADLESS */