2
|
1 |
/*
|
5506
|
2 |
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
|
2
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
5506
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
2
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
5506
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
2
|
10 |
*
|
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
15 |
* accompanied this code).
|
|
16 |
*
|
|
17 |
* You should have received a copy of the GNU General Public License version
|
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20 |
*
|
5506
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
22 |
* or visit www.oracle.com if you need additional information or have any
|
|
23 |
* questions.
|
2
|
24 |
*/
|
|
25 |
|
|
26 |
#ifndef HEADLESS
|
|
27 |
|
|
28 |
#include <jlong.h>
|
|
29 |
#include <string.h>
|
|
30 |
|
|
31 |
#include "sun_java2d_SunGraphics2D.h"
|
|
32 |
#include "sun_java2d_pipe_BufferedPaints.h"
|
|
33 |
|
|
34 |
#include "OGLPaints.h"
|
|
35 |
#include "OGLContext.h"
|
|
36 |
#include "OGLRenderQueue.h"
|
|
37 |
#include "OGLSurfaceData.h"
|
|
38 |
|
|
39 |
void
|
|
40 |
OGLPaints_ResetPaint(OGLContext *oglc)
|
|
41 |
{
|
|
42 |
jubyte ea;
|
|
43 |
|
|
44 |
J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_ResetPaint");
|
|
45 |
|
|
46 |
RETURN_IF_NULL(oglc);
|
|
47 |
J2dTraceLn1(J2D_TRACE_VERBOSE, " state=%d", oglc->paintState);
|
|
48 |
RESET_PREVIOUS_OP();
|
|
49 |
|
|
50 |
if (oglc->useMask) {
|
|
51 |
// switch to texture unit 1, where paint state is currently enabled
|
|
52 |
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
|
|
53 |
}
|
|
54 |
|
|
55 |
switch (oglc->paintState) {
|
|
56 |
case sun_java2d_SunGraphics2D_PAINT_GRADIENT:
|
|
57 |
j2d_glDisable(GL_TEXTURE_1D);
|
|
58 |
j2d_glDisable(GL_TEXTURE_GEN_S);
|
|
59 |
break;
|
|
60 |
|
|
61 |
case sun_java2d_SunGraphics2D_PAINT_TEXTURE:
|
|
62 |
// Note: The texture object used in SetTexturePaint() will
|
|
63 |
// still be bound at this point, so it is safe to call the following.
|
|
64 |
OGLSD_RESET_TEXTURE_WRAP(GL_TEXTURE_2D);
|
|
65 |
j2d_glDisable(GL_TEXTURE_2D);
|
|
66 |
j2d_glDisable(GL_TEXTURE_GEN_S);
|
|
67 |
j2d_glDisable(GL_TEXTURE_GEN_T);
|
|
68 |
break;
|
|
69 |
|
|
70 |
case sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT:
|
|
71 |
case sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT:
|
|
72 |
j2d_glUseProgramObjectARB(0);
|
|
73 |
j2d_glDisable(GL_TEXTURE_1D);
|
|
74 |
break;
|
|
75 |
|
|
76 |
case sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR:
|
|
77 |
default:
|
|
78 |
break;
|
|
79 |
}
|
|
80 |
|
|
81 |
if (oglc->useMask) {
|
|
82 |
// restore control to texture unit 0
|
|
83 |
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
|
|
84 |
}
|
|
85 |
|
|
86 |
// set each component of the current color state to the extra alpha
|
|
87 |
// value, which will effectively apply the extra alpha to each fragment
|
|
88 |
// in paint/texturing operations
|
|
89 |
ea = (jubyte)(oglc->extraAlpha * 0xff + 0.5f);
|
|
90 |
j2d_glColor4ub(ea, ea, ea, ea);
|
|
91 |
oglc->pixel = (ea << 24) | (ea << 16) | (ea << 8) | (ea << 0);
|
|
92 |
oglc->r = ea;
|
|
93 |
oglc->g = ea;
|
|
94 |
oglc->b = ea;
|
|
95 |
oglc->a = ea;
|
|
96 |
oglc->useMask = JNI_FALSE;
|
|
97 |
oglc->paintState = -1;
|
|
98 |
}
|
|
99 |
|
|
100 |
void
|
|
101 |
OGLPaints_SetColor(OGLContext *oglc, jint pixel)
|
|
102 |
{
|
|
103 |
jubyte r, g, b, a;
|
|
104 |
|
|
105 |
J2dTraceLn1(J2D_TRACE_INFO, "OGLPaints_SetColor: pixel=%08x", pixel);
|
|
106 |
|
|
107 |
RETURN_IF_NULL(oglc);
|
|
108 |
|
|
109 |
// glColor*() is allowed within glBegin()/glEnd() pairs, so
|
|
110 |
// no need to reset the current op state here unless the paint
|
|
111 |
// state really needs to be changed
|
|
112 |
if (oglc->paintState > sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR) {
|
|
113 |
OGLPaints_ResetPaint(oglc);
|
|
114 |
}
|
|
115 |
|
|
116 |
// store the raw (unmodified) pixel value, which may be used for
|
|
117 |
// special operations later
|
|
118 |
oglc->pixel = pixel;
|
|
119 |
|
|
120 |
if (oglc->compState != sun_java2d_SunGraphics2D_COMP_XOR) {
|
|
121 |
r = (jubyte)(pixel >> 16);
|
|
122 |
g = (jubyte)(pixel >> 8);
|
|
123 |
b = (jubyte)(pixel >> 0);
|
|
124 |
a = (jubyte)(pixel >> 24);
|
|
125 |
|
|
126 |
J2dTraceLn4(J2D_TRACE_VERBOSE,
|
|
127 |
" updating color: r=%02x g=%02x b=%02x a=%02x",
|
|
128 |
r, g, b, a);
|
|
129 |
} else {
|
|
130 |
pixel ^= oglc->xorPixel;
|
|
131 |
|
|
132 |
r = (jubyte)(pixel >> 16);
|
|
133 |
g = (jubyte)(pixel >> 8);
|
|
134 |
b = (jubyte)(pixel >> 0);
|
|
135 |
a = 0xff;
|
|
136 |
|
|
137 |
J2dTraceLn4(J2D_TRACE_VERBOSE,
|
|
138 |
" updating xor color: r=%02x g=%02x b=%02x xorpixel=%08x",
|
|
139 |
r, g, b, oglc->xorPixel);
|
|
140 |
}
|
|
141 |
|
|
142 |
j2d_glColor4ub(r, g, b, a);
|
|
143 |
oglc->r = r;
|
|
144 |
oglc->g = g;
|
|
145 |
oglc->b = b;
|
|
146 |
oglc->a = a;
|
|
147 |
oglc->useMask = JNI_FALSE;
|
|
148 |
oglc->paintState = sun_java2d_SunGraphics2D_PAINT_ALPHACOLOR;
|
|
149 |
}
|
|
150 |
|
|
151 |
/************************* GradientPaint support ****************************/
|
|
152 |
|
|
153 |
static GLuint gradientTexID = 0;
|
|
154 |
|
|
155 |
static void
|
56230
|
156 |
OGLPaints_InitGradientTexture(void)
|
2
|
157 |
{
|
|
158 |
GLclampf priority = 1.0f;
|
|
159 |
|
|
160 |
J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitGradientTexture");
|
|
161 |
|
|
162 |
j2d_glGenTextures(1, &gradientTexID);
|
|
163 |
j2d_glBindTexture(GL_TEXTURE_1D, gradientTexID);
|
|
164 |
j2d_glPrioritizeTextures(1, &gradientTexID, &priority);
|
|
165 |
j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
166 |
j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
167 |
j2d_glTexImage1D(GL_TEXTURE_1D, 0,
|
|
168 |
GL_RGBA8, 2, 0,
|
|
169 |
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
|
170 |
}
|
|
171 |
|
|
172 |
void
|
|
173 |
OGLPaints_SetGradientPaint(OGLContext *oglc,
|
|
174 |
jboolean useMask, jboolean cyclic,
|
|
175 |
jdouble p0, jdouble p1, jdouble p3,
|
|
176 |
jint pixel1, jint pixel2)
|
|
177 |
{
|
|
178 |
GLdouble texParams[4];
|
|
179 |
GLuint pixels[2];
|
|
180 |
|
|
181 |
J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetGradientPaint");
|
|
182 |
|
|
183 |
RETURN_IF_NULL(oglc);
|
|
184 |
OGLPaints_ResetPaint(oglc);
|
|
185 |
|
|
186 |
texParams[0] = p0;
|
|
187 |
texParams[1] = p1;
|
|
188 |
texParams[2] = 0.0;
|
|
189 |
texParams[3] = p3;
|
|
190 |
|
|
191 |
pixels[0] = pixel1;
|
|
192 |
pixels[1] = pixel2;
|
|
193 |
|
|
194 |
if (useMask) {
|
|
195 |
// set up the paint on texture unit 1 (instead of the usual unit 0)
|
|
196 |
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
|
|
197 |
j2d_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
198 |
} else {
|
|
199 |
// texture unit 0 is already active; we can use the helper macro here
|
|
200 |
OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
|
|
201 |
}
|
|
202 |
|
|
203 |
if (gradientTexID == 0) {
|
|
204 |
OGLPaints_InitGradientTexture();
|
|
205 |
}
|
|
206 |
|
|
207 |
j2d_glEnable(GL_TEXTURE_1D);
|
|
208 |
j2d_glEnable(GL_TEXTURE_GEN_S);
|
|
209 |
j2d_glBindTexture(GL_TEXTURE_1D, gradientTexID);
|
|
210 |
j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S,
|
|
211 |
cyclic ? GL_REPEAT : GL_CLAMP_TO_EDGE);
|
|
212 |
j2d_glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
213 |
j2d_glTexGendv(GL_S, GL_OBJECT_PLANE, texParams);
|
|
214 |
|
|
215 |
j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
|
|
216 |
0, 2, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
|
|
217 |
|
|
218 |
if (useMask) {
|
|
219 |
// restore control to texture unit 0
|
|
220 |
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
|
|
221 |
}
|
|
222 |
|
|
223 |
// oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
|
|
224 |
oglc->useMask = useMask;
|
|
225 |
oglc->paintState = sun_java2d_SunGraphics2D_PAINT_GRADIENT;
|
|
226 |
}
|
|
227 |
|
|
228 |
/************************** TexturePaint support ****************************/
|
|
229 |
|
|
230 |
void
|
|
231 |
OGLPaints_SetTexturePaint(OGLContext *oglc,
|
|
232 |
jboolean useMask,
|
|
233 |
jlong pSrcOps, jboolean filter,
|
|
234 |
jdouble xp0, jdouble xp1, jdouble xp3,
|
|
235 |
jdouble yp0, jdouble yp1, jdouble yp3)
|
|
236 |
{
|
|
237 |
OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
|
|
238 |
GLdouble xParams[4];
|
|
239 |
GLdouble yParams[4];
|
|
240 |
GLint hint = (filter ? GL_LINEAR : GL_NEAREST);
|
|
241 |
|
|
242 |
J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetTexturePaint");
|
|
243 |
|
|
244 |
RETURN_IF_NULL(srcOps);
|
|
245 |
RETURN_IF_NULL(oglc);
|
|
246 |
OGLPaints_ResetPaint(oglc);
|
|
247 |
|
|
248 |
xParams[0] = xp0;
|
|
249 |
xParams[1] = xp1;
|
|
250 |
xParams[2] = 0.0;
|
|
251 |
xParams[3] = xp3;
|
|
252 |
|
|
253 |
yParams[0] = yp0;
|
|
254 |
yParams[1] = yp1;
|
|
255 |
yParams[2] = 0.0;
|
|
256 |
yParams[3] = yp3;
|
|
257 |
|
|
258 |
/*
|
|
259 |
* Note that we explicitly use GL_TEXTURE_2D below rather than using
|
|
260 |
* srcOps->textureTarget. This is because the texture wrap mode employed
|
|
261 |
* here (GL_REPEAT) is not available for GL_TEXTURE_RECTANGLE_ARB targets.
|
|
262 |
* The setup code in OGLPaints.Texture.isPaintValid() and in
|
|
263 |
* OGLSurfaceData.initTexture() ensures that we only get here for
|
|
264 |
* GL_TEXTURE_2D targets.
|
|
265 |
*/
|
|
266 |
|
|
267 |
if (useMask) {
|
|
268 |
// set up the paint on texture unit 1 (instead of the usual unit 0)
|
|
269 |
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
|
|
270 |
j2d_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
271 |
} else {
|
|
272 |
// texture unit 0 is already active; we can use the helper macro here
|
|
273 |
OGLC_UPDATE_TEXTURE_FUNCTION(oglc, GL_MODULATE);
|
|
274 |
}
|
|
275 |
|
|
276 |
j2d_glEnable(GL_TEXTURE_2D);
|
|
277 |
j2d_glEnable(GL_TEXTURE_GEN_S);
|
|
278 |
j2d_glEnable(GL_TEXTURE_GEN_T);
|
|
279 |
j2d_glBindTexture(GL_TEXTURE_2D, srcOps->textureID);
|
|
280 |
OGLSD_UPDATE_TEXTURE_FILTER(srcOps, hint);
|
|
281 |
OGLSD_UPDATE_TEXTURE_WRAP(GL_TEXTURE_2D, GL_REPEAT);
|
|
282 |
j2d_glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
283 |
j2d_glTexGendv(GL_S, GL_OBJECT_PLANE, xParams);
|
|
284 |
j2d_glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
285 |
j2d_glTexGendv(GL_T, GL_OBJECT_PLANE, yParams);
|
|
286 |
|
|
287 |
if (useMask) {
|
|
288 |
// restore control to texture unit 0
|
|
289 |
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
|
|
290 |
}
|
|
291 |
|
|
292 |
// oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
|
|
293 |
oglc->useMask = useMask;
|
|
294 |
oglc->paintState = sun_java2d_SunGraphics2D_PAINT_TEXTURE;
|
|
295 |
}
|
|
296 |
|
|
297 |
/****************** Shared MultipleGradientPaint support ********************/
|
|
298 |
|
|
299 |
/**
|
|
300 |
* These constants are identical to those defined in the
|
|
301 |
* MultipleGradientPaint.CycleMethod enum; they are copied here for
|
|
302 |
* convenience (ideally we would pull them directly from the Java level,
|
|
303 |
* but that entails more hassle than it is worth).
|
|
304 |
*/
|
|
305 |
#define CYCLE_NONE 0
|
|
306 |
#define CYCLE_REFLECT 1
|
|
307 |
#define CYCLE_REPEAT 2
|
|
308 |
|
|
309 |
/**
|
|
310 |
* The following constants are flags that can be bitwise-or'ed together
|
|
311 |
* to control how the MultipleGradientPaint shader source code is generated:
|
|
312 |
*
|
|
313 |
* MULTI_CYCLE_METHOD
|
|
314 |
* Placeholder for the CycleMethod enum constant.
|
|
315 |
*
|
|
316 |
* MULTI_LARGE
|
|
317 |
* If set, use the (slower) shader that supports a larger number of
|
|
318 |
* gradient colors; otherwise, use the optimized codepath. See
|
|
319 |
* the MAX_FRACTIONS_SMALL/LARGE constants below for more details.
|
|
320 |
*
|
|
321 |
* MULTI_USE_MASK
|
|
322 |
* If set, apply the alpha mask value from texture unit 0 to the
|
|
323 |
* final color result (only used in the MaskFill case).
|
|
324 |
*
|
|
325 |
* MULTI_LINEAR_RGB
|
|
326 |
* If set, convert the linear RGB result back into the sRGB color space.
|
|
327 |
*/
|
|
328 |
#define MULTI_CYCLE_METHOD (3 << 0)
|
|
329 |
#define MULTI_LARGE (1 << 2)
|
|
330 |
#define MULTI_USE_MASK (1 << 3)
|
|
331 |
#define MULTI_LINEAR_RGB (1 << 4)
|
|
332 |
|
|
333 |
/**
|
|
334 |
* This value determines the size of the array of programs for each
|
|
335 |
* MultipleGradientPaint type. This value reflects the maximum value that
|
|
336 |
* can be represented by performing a bitwise-or of all the MULTI_*
|
|
337 |
* constants defined above.
|
|
338 |
*/
|
|
339 |
#define MAX_PROGRAMS 32
|
|
340 |
|
|
341 |
/** Evaluates to true if the given bit is set on the local flags variable. */
|
|
342 |
#define IS_SET(flagbit) \
|
|
343 |
(((flags) & (flagbit)) != 0)
|
|
344 |
|
|
345 |
/** Composes the given parameters as flags into the given flags variable.*/
|
|
346 |
#define COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear) \
|
|
347 |
do { \
|
|
348 |
flags |= ((cycleMethod) & MULTI_CYCLE_METHOD); \
|
|
349 |
if (large) flags |= MULTI_LARGE; \
|
|
350 |
if (useMask) flags |= MULTI_USE_MASK; \
|
|
351 |
if (linear) flags |= MULTI_LINEAR_RGB; \
|
|
352 |
} while (0)
|
|
353 |
|
|
354 |
/** Extracts the CycleMethod enum value from the given flags variable. */
|
|
355 |
#define EXTRACT_CYCLE_METHOD(flags) \
|
|
356 |
((flags) & MULTI_CYCLE_METHOD)
|
|
357 |
|
|
358 |
/**
|
|
359 |
* The maximum number of gradient "stops" supported by the fragment shader
|
|
360 |
* and related code. When the MULTI_LARGE flag is set, we will use
|
|
361 |
* MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having
|
|
362 |
* two separate values, we can have one highly optimized shader (SMALL) that
|
|
363 |
* supports only a few fractions/colors, and then another, less optimal
|
|
364 |
* shader that supports more stops.
|
|
365 |
*/
|
|
366 |
#define MAX_FRACTIONS sun_java2d_pipe_BufferedPaints_MULTI_MAX_FRACTIONS
|
|
367 |
#define MAX_FRACTIONS_LARGE MAX_FRACTIONS
|
|
368 |
#define MAX_FRACTIONS_SMALL 4
|
|
369 |
|
|
370 |
/**
|
|
371 |
* The maximum number of gradient colors supported by all of the gradient
|
|
372 |
* fragment shaders. Note that this value must be a power of two, as it
|
|
373 |
* determines the size of the 1D texture created below. It also must be
|
|
374 |
* greater than or equal to MAX_FRACTIONS (there is no strict requirement
|
|
375 |
* that the two values be equal).
|
|
376 |
*/
|
|
377 |
#define MAX_COLORS 16
|
|
378 |
|
|
379 |
/**
|
|
380 |
* The handle to the gradient color table texture object used by the shaders.
|
|
381 |
*/
|
|
382 |
static GLuint multiGradientTexID = 0;
|
|
383 |
|
|
384 |
/**
|
|
385 |
* This is essentially a template of the shader source code that can be used
|
|
386 |
* for either LinearGradientPaint or RadialGradientPaint. It includes the
|
|
387 |
* structure and some variables that are common to each; the remaining
|
|
388 |
* code snippets (for CycleMethod, ColorSpaceType, and mask modulation)
|
|
389 |
* are filled in prior to compiling the shader at runtime depending on the
|
|
390 |
* paint parameters. See OGLPaints_CreateMultiGradProgram() for more details.
|
|
391 |
*/
|
|
392 |
static const char *multiGradientShaderSource =
|
|
393 |
// gradient texture size (in texels)
|
|
394 |
"const int TEXTURE_SIZE = %d;"
|
|
395 |
// maximum number of fractions/colors supported by this shader
|
|
396 |
"const int MAX_FRACTIONS = %d;"
|
|
397 |
// size of a single texel
|
|
398 |
"const float FULL_TEXEL = (1.0 / float(TEXTURE_SIZE));"
|
|
399 |
// size of half of a single texel
|
|
400 |
"const float HALF_TEXEL = (FULL_TEXEL / 2.0);"
|
|
401 |
// texture containing the gradient colors
|
|
402 |
"uniform sampler1D colors;"
|
|
403 |
// array of gradient stops/fractions
|
|
404 |
"uniform float fractions[MAX_FRACTIONS];"
|
|
405 |
// array of scale factors (one for each interval)
|
|
406 |
"uniform float scaleFactors[MAX_FRACTIONS-1];"
|
|
407 |
// (placeholder for mask variable)
|
|
408 |
"%s"
|
|
409 |
// (placeholder for Linear/RadialGP-specific variables)
|
|
410 |
"%s"
|
|
411 |
""
|
|
412 |
"void main(void)"
|
|
413 |
"{"
|
|
414 |
" float dist;"
|
|
415 |
// (placeholder for Linear/RadialGradientPaint-specific code)
|
|
416 |
" %s"
|
|
417 |
""
|
|
418 |
" float tc;"
|
|
419 |
// (placeholder for CycleMethod-specific code)
|
|
420 |
" %s"
|
|
421 |
""
|
|
422 |
// calculate interpolated color
|
|
423 |
" vec4 result = texture1D(colors, tc);"
|
|
424 |
""
|
|
425 |
// (placeholder for ColorSpace conversion code)
|
|
426 |
" %s"
|
|
427 |
""
|
|
428 |
// (placeholder for mask modulation code)
|
|
429 |
" %s"
|
|
430 |
""
|
|
431 |
// modulate with gl_Color in order to apply extra alpha
|
|
432 |
" gl_FragColor = result * gl_Color;"
|
|
433 |
"}";
|
|
434 |
|
|
435 |
/**
|
|
436 |
* This code takes a "dist" value as input (as calculated earlier by the
|
|
437 |
* LGP/RGP-specific code) in the range [0,1] and produces a texture
|
|
438 |
* coordinate value "tc" that represents the position of the chosen color
|
|
439 |
* in the one-dimensional gradient texture (also in the range [0,1]).
|
|
440 |
*
|
|
441 |
* One naive way to implement this would be to iterate through the fractions
|
|
442 |
* to figure out in which interval "dist" falls, and then compute the
|
|
443 |
* relative distance between the two nearest stops. This approach would
|
|
444 |
* require an "if" check on every iteration, and it is best to avoid
|
|
445 |
* conditionals in fragment shaders for performance reasons. Also, one might
|
|
446 |
* be tempted to use a break statement to jump out of the loop once the
|
|
447 |
* interval was found, but break statements (and non-constant loop bounds)
|
|
448 |
* are not natively available on most graphics hardware today, so that is
|
|
449 |
* a non-starter.
|
|
450 |
*
|
|
451 |
* The more optimal approach used here avoids these issues entirely by using
|
|
452 |
* an accumulation function that is equivalent to the process described above.
|
|
453 |
* The scaleFactors array is pre-initialized at enable time as follows:
|
|
454 |
* scaleFactors[i] = 1.0 / (fractions[i+1] - fractions[i]);
|
|
455 |
*
|
|
456 |
* For each iteration, we subtract fractions[i] from dist and then multiply
|
|
457 |
* that value by scaleFactors[i]. If we are within the target interval,
|
|
458 |
* this value will be a fraction in the range [0,1] indicating the relative
|
|
459 |
* distance between fraction[i] and fraction[i+1]. If we are below the
|
|
460 |
* target interval, this value will be negative, so we clamp it to zero
|
|
461 |
* to avoid accumulating any value. If we are above the target interval,
|
|
462 |
* the value will be greater than one, so we clamp it to one. Upon exiting
|
|
463 |
* the loop, we will have accumulated zero or more 1.0's and a single
|
|
464 |
* fractional value. This accumulated value tells us the position of the
|
|
465 |
* fragment color in the one-dimensional gradient texture, i.e., the
|
|
466 |
* texcoord called "tc".
|
|
467 |
*/
|
|
468 |
static const char *texCoordCalcCode =
|
|
469 |
"int i;"
|
|
470 |
"float relFraction = 0.0;"
|
|
471 |
"for (i = 0; i < MAX_FRACTIONS-1; i++) {"
|
|
472 |
" relFraction +="
|
|
473 |
" clamp((dist - fractions[i]) * scaleFactors[i], 0.0, 1.0);"
|
|
474 |
"}"
|
|
475 |
// we offset by half a texel so that we find the linearly interpolated
|
|
476 |
// color between the two texel centers of interest
|
|
477 |
"tc = HALF_TEXEL + (FULL_TEXEL * relFraction);";
|
|
478 |
|
|
479 |
/** Code for NO_CYCLE that gets plugged into the CycleMethod placeholder. */
|
|
480 |
static const char *noCycleCode =
|
|
481 |
"if (dist <= 0.0) {"
|
|
482 |
" tc = 0.0;"
|
|
483 |
"} else if (dist >= 1.0) {"
|
|
484 |
" tc = 1.0;"
|
|
485 |
"} else {"
|
|
486 |
// (placeholder for texcoord calculation)
|
|
487 |
" %s"
|
|
488 |
"}";
|
|
489 |
|
|
490 |
/** Code for REFLECT that gets plugged into the CycleMethod placeholder. */
|
|
491 |
static const char *reflectCode =
|
|
492 |
"dist = 1.0 - (abs(fract(dist * 0.5) - 0.5) * 2.0);"
|
|
493 |
// (placeholder for texcoord calculation)
|
|
494 |
"%s";
|
|
495 |
|
|
496 |
/** Code for REPEAT that gets plugged into the CycleMethod placeholder. */
|
|
497 |
static const char *repeatCode =
|
|
498 |
"dist = fract(dist);"
|
|
499 |
// (placeholder for texcoord calculation)
|
|
500 |
"%s";
|
|
501 |
|
|
502 |
static void
|
56230
|
503 |
OGLPaints_InitMultiGradientTexture(void)
|
2
|
504 |
{
|
|
505 |
GLclampf priority = 1.0f;
|
|
506 |
|
|
507 |
J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_InitMultiGradientTexture");
|
|
508 |
|
|
509 |
j2d_glGenTextures(1, &multiGradientTexID);
|
|
510 |
j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID);
|
|
511 |
j2d_glPrioritizeTextures(1, &multiGradientTexID, &priority);
|
|
512 |
j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
513 |
j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
514 |
j2d_glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
515 |
j2d_glTexImage1D(GL_TEXTURE_1D, 0,
|
|
516 |
GL_RGBA8, MAX_COLORS, 0,
|
|
517 |
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
|
518 |
}
|
|
519 |
|
|
520 |
/**
|
|
521 |
* Compiles and links the MultipleGradientPaint shader program. If
|
|
522 |
* successful, this function returns a handle to the newly created
|
|
523 |
* shader program; otherwise returns 0.
|
|
524 |
*/
|
|
525 |
static GLhandleARB
|
|
526 |
OGLPaints_CreateMultiGradProgram(jint flags,
|
|
527 |
char *paintVars, char *distCode)
|
|
528 |
{
|
|
529 |
GLhandleARB multiGradProgram;
|
|
530 |
GLint loc;
|
|
531 |
char *maskVars = "";
|
|
532 |
char *maskCode = "";
|
|
533 |
char *colorSpaceCode = "";
|
|
534 |
char cycleCode[1500];
|
|
535 |
char finalSource[3000];
|
|
536 |
jint cycleMethod = EXTRACT_CYCLE_METHOD(flags);
|
|
537 |
jint maxFractions = IS_SET(MULTI_LARGE) ?
|
|
538 |
MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;
|
|
539 |
|
|
540 |
J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_CreateMultiGradProgram");
|
|
541 |
|
|
542 |
if (IS_SET(MULTI_USE_MASK)) {
|
|
543 |
/*
|
|
544 |
* This code modulates the calculated result color with the
|
|
545 |
* corresponding alpha value from the alpha mask texture active
|
|
546 |
* on texture unit 0. Only needed when useMask is true (i.e., only
|
|
547 |
* for MaskFill operations).
|
|
548 |
*/
|
|
549 |
maskVars = "uniform sampler2D mask;";
|
|
550 |
maskCode = "result *= texture2D(mask, gl_TexCoord[0].st);";
|
|
551 |
} else {
|
|
552 |
/*
|
|
553 |
* REMIND: This is really wacky, but the gradient shaders will
|
|
554 |
* produce completely incorrect results on ATI hardware (at least
|
|
555 |
* on first-gen (R300-based) boards) if the shader program does not
|
|
556 |
* try to access texture coordinates by using a gl_TexCoord[*]
|
|
557 |
* variable. This problem really should be addressed by ATI, but
|
|
558 |
* in the meantime it seems we can workaround the issue by inserting
|
|
559 |
* a benign operation that accesses gl_TexCoord[0]. Note that we
|
|
560 |
* only need to do this for ATI boards and only in the !useMask case,
|
|
561 |
* because the useMask case already does access gl_TexCoord[1] and
|
|
562 |
* is therefore not affected by this driver bug.
|
|
563 |
*/
|
|
564 |
const char *vendor = (const char *)j2d_glGetString(GL_VENDOR);
|
|
565 |
if (vendor != NULL && strncmp(vendor, "ATI", 3) == 0) {
|
|
566 |
maskCode = "dist = gl_TexCoord[0].s;";
|
|
567 |
}
|
|
568 |
}
|
|
569 |
|
|
570 |
if (IS_SET(MULTI_LINEAR_RGB)) {
|
|
571 |
/*
|
|
572 |
* This code converts a single pixel in linear RGB space back
|
|
573 |
* into sRGB (note: this code was adapted from the
|
|
574 |
* MultipleGradientPaintContext.convertLinearRGBtoSRGB() method).
|
|
575 |
*/
|
|
576 |
colorSpaceCode =
|
|
577 |
"result.rgb = 1.055 * pow(result.rgb, vec3(0.416667)) - 0.055;";
|
|
578 |
}
|
|
579 |
|
|
580 |
if (cycleMethod == CYCLE_NONE) {
|
|
581 |
sprintf(cycleCode, noCycleCode, texCoordCalcCode);
|
|
582 |
} else if (cycleMethod == CYCLE_REFLECT) {
|
|
583 |
sprintf(cycleCode, reflectCode, texCoordCalcCode);
|
|
584 |
} else { // (cycleMethod == CYCLE_REPEAT)
|
|
585 |
sprintf(cycleCode, repeatCode, texCoordCalcCode);
|
|
586 |
}
|
|
587 |
|
|
588 |
// compose the final source code string from the various pieces
|
|
589 |
sprintf(finalSource, multiGradientShaderSource,
|
|
590 |
MAX_COLORS, maxFractions,
|
|
591 |
maskVars, paintVars, distCode,
|
|
592 |
cycleCode, colorSpaceCode, maskCode);
|
|
593 |
|
|
594 |
multiGradProgram = OGLContext_CreateFragmentProgram(finalSource);
|
|
595 |
if (multiGradProgram == 0) {
|
|
596 |
J2dRlsTraceLn(J2D_TRACE_ERROR,
|
|
597 |
"OGLPaints_CreateMultiGradProgram: error creating program");
|
|
598 |
return 0;
|
|
599 |
}
|
|
600 |
|
|
601 |
// "use" the program object temporarily so that we can set the uniforms
|
|
602 |
j2d_glUseProgramObjectARB(multiGradProgram);
|
|
603 |
|
|
604 |
// set the "uniform" texture unit bindings
|
|
605 |
if (IS_SET(MULTI_USE_MASK)) {
|
|
606 |
loc = j2d_glGetUniformLocationARB(multiGradProgram, "mask");
|
|
607 |
j2d_glUniform1iARB(loc, 0); // texture unit 0
|
|
608 |
loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");
|
|
609 |
j2d_glUniform1iARB(loc, 1); // texture unit 1
|
|
610 |
} else {
|
|
611 |
loc = j2d_glGetUniformLocationARB(multiGradProgram, "colors");
|
|
612 |
j2d_glUniform1iARB(loc, 0); // texture unit 0
|
|
613 |
}
|
|
614 |
|
|
615 |
// "unuse" the program object; it will be re-bound later as needed
|
|
616 |
j2d_glUseProgramObjectARB(0);
|
|
617 |
|
|
618 |
if (multiGradientTexID == 0) {
|
|
619 |
OGLPaints_InitMultiGradientTexture();
|
|
620 |
}
|
|
621 |
|
|
622 |
return multiGradProgram;
|
|
623 |
}
|
|
624 |
|
|
625 |
/**
|
|
626 |
* Called from the OGLPaints_SetLinear/RadialGradientPaint() methods
|
|
627 |
* in order to setup the fraction/color values that are common to both.
|
|
628 |
*/
|
|
629 |
static void
|
|
630 |
OGLPaints_SetMultiGradientPaint(GLhandleARB multiGradProgram,
|
|
631 |
jint numStops,
|
|
632 |
void *pFractions, void *pPixels)
|
|
633 |
{
|
|
634 |
jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ?
|
|
635 |
MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;
|
|
636 |
GLfloat scaleFactors[MAX_FRACTIONS-1];
|
|
637 |
GLfloat *fractions = (GLfloat *)pFractions;
|
|
638 |
GLint *pixels = (GLint *)pPixels;
|
|
639 |
GLint loc;
|
|
640 |
int i;
|
|
641 |
|
|
642 |
// enable the MultipleGradientPaint shader
|
|
643 |
j2d_glUseProgramObjectARB(multiGradProgram);
|
|
644 |
|
|
645 |
// update the "uniform" fraction values
|
|
646 |
loc = j2d_glGetUniformLocationARB(multiGradProgram, "fractions");
|
|
647 |
if (numStops < maxFractions) {
|
|
648 |
// fill the remainder of the fractions array with all zeros to
|
|
649 |
// prevent using garbage values from previous paints
|
|
650 |
GLfloat allZeros[MAX_FRACTIONS];
|
|
651 |
memset(allZeros, 0, sizeof(GLfloat)*MAX_FRACTIONS);
|
|
652 |
j2d_glUniform1fvARB(loc, maxFractions, allZeros);
|
|
653 |
}
|
|
654 |
j2d_glUniform1fvARB(loc, numStops, fractions);
|
|
655 |
|
|
656 |
// update the "uniform" scale values
|
|
657 |
loc = j2d_glGetUniformLocationARB(multiGradProgram, "scaleFactors");
|
|
658 |
for (i = 0; i < numStops-1; i++) {
|
|
659 |
// calculate a scale factor for each interval
|
|
660 |
scaleFactors[i] = 1.0f / (fractions[i+1] - fractions[i]);
|
|
661 |
}
|
|
662 |
for (; i < maxFractions-1; i++) {
|
|
663 |
// fill remaining scale factors with zero
|
|
664 |
scaleFactors[i] = 0.0f;
|
|
665 |
}
|
|
666 |
j2d_glUniform1fvARB(loc, maxFractions-1, scaleFactors);
|
|
667 |
|
|
668 |
// update the texture containing the gradient colors
|
|
669 |
j2d_glEnable(GL_TEXTURE_1D);
|
|
670 |
j2d_glBindTexture(GL_TEXTURE_1D, multiGradientTexID);
|
|
671 |
j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
|
|
672 |
0, numStops,
|
|
673 |
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
674 |
pixels);
|
|
675 |
if (numStops < MAX_COLORS) {
|
|
676 |
// when we don't have enough colors to fill the entire color gradient,
|
|
677 |
// we have to replicate the last color in the right-most texel for
|
|
678 |
// the NO_CYCLE case where the texcoord is sometimes forced to 1.0
|
|
679 |
j2d_glTexSubImage1D(GL_TEXTURE_1D, 0,
|
|
680 |
MAX_COLORS-1, 1,
|
|
681 |
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
|
682 |
pixels+(numStops-1));
|
|
683 |
}
|
|
684 |
}
|
|
685 |
|
|
686 |
/********************** LinearGradientPaint support *************************/
|
|
687 |
|
|
688 |
/**
|
|
689 |
* The handles to the LinearGradientPaint fragment program objects. The
|
|
690 |
* index to the array should be a bitwise-or'ing of the MULTI_* flags defined
|
|
691 |
* above. Note that most applications will likely need to initialize one
|
|
692 |
* or two of these elements, so the array is usually sparsely populated.
|
|
693 |
*/
|
|
694 |
static GLhandleARB linearGradPrograms[MAX_PROGRAMS];
|
|
695 |
|
|
696 |
/**
|
|
697 |
* Compiles and links the LinearGradientPaint shader program. If successful,
|
|
698 |
* this function returns a handle to the newly created shader program;
|
|
699 |
* otherwise returns 0.
|
|
700 |
*/
|
|
701 |
static GLhandleARB
|
|
702 |
OGLPaints_CreateLinearGradProgram(jint flags)
|
|
703 |
{
|
|
704 |
char *paintVars;
|
|
705 |
char *distCode;
|
|
706 |
|
|
707 |
J2dTraceLn1(J2D_TRACE_INFO,
|
|
708 |
"OGLPaints_CreateLinearGradProgram",
|
|
709 |
flags);
|
|
710 |
|
|
711 |
/*
|
|
712 |
* To simplify the code and to make it easier to upload a number of
|
|
713 |
* uniform values at once, we pack a bunch of scalar (float) values
|
|
714 |
* into vec3 values below. Here's how the values are related:
|
|
715 |
*
|
|
716 |
* params.x = p0
|
|
717 |
* params.y = p1
|
|
718 |
* params.z = p3
|
|
719 |
*
|
|
720 |
* yoff = dstOps->yOffset + dstOps->height
|
|
721 |
*/
|
|
722 |
paintVars =
|
|
723 |
"uniform vec3 params;"
|
|
724 |
"uniform float yoff;";
|
|
725 |
distCode =
|
|
726 |
// note that gl_FragCoord is in window space relative to the
|
|
727 |
// lower-left corner, so we have to flip the y-coordinate here
|
|
728 |
"vec3 fragCoord = vec3(gl_FragCoord.x, yoff-gl_FragCoord.y, 1.0);"
|
|
729 |
"dist = dot(params, fragCoord);";
|
|
730 |
|
|
731 |
return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
|
|
732 |
}
|
|
733 |
|
|
734 |
void
|
|
735 |
OGLPaints_SetLinearGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,
|
|
736 |
jboolean useMask, jboolean linear,
|
|
737 |
jint cycleMethod, jint numStops,
|
|
738 |
jfloat p0, jfloat p1, jfloat p3,
|
|
739 |
void *fractions, void *pixels)
|
|
740 |
{
|
|
741 |
GLhandleARB linearGradProgram;
|
|
742 |
GLint loc;
|
|
743 |
jboolean large = (numStops > MAX_FRACTIONS_SMALL);
|
|
744 |
jint flags = 0;
|
|
745 |
|
|
746 |
J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetLinearGradientPaint");
|
|
747 |
|
|
748 |
RETURN_IF_NULL(oglc);
|
|
749 |
RETURN_IF_NULL(dstOps);
|
|
750 |
OGLPaints_ResetPaint(oglc);
|
|
751 |
|
|
752 |
COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
|
|
753 |
|
|
754 |
if (useMask) {
|
|
755 |
// set up the paint on texture unit 1 (instead of the usual unit 0)
|
|
756 |
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
|
|
757 |
}
|
|
758 |
// no need to set GL_MODULATE here (it is ignored when shader is enabled)
|
|
759 |
|
|
760 |
// locate/initialize the shader program for the given flags
|
|
761 |
if (linearGradPrograms[flags] == 0) {
|
|
762 |
linearGradPrograms[flags] = OGLPaints_CreateLinearGradProgram(flags);
|
|
763 |
if (linearGradPrograms[flags] == 0) {
|
|
764 |
// shouldn't happen, but just in case...
|
|
765 |
return;
|
|
766 |
}
|
|
767 |
}
|
|
768 |
linearGradProgram = linearGradPrograms[flags];
|
|
769 |
|
|
770 |
// update the common "uniform" values (fractions and colors)
|
|
771 |
OGLPaints_SetMultiGradientPaint(linearGradProgram,
|
|
772 |
numStops, fractions, pixels);
|
|
773 |
|
|
774 |
// update the other "uniform" values
|
|
775 |
loc = j2d_glGetUniformLocationARB(linearGradProgram, "params");
|
|
776 |
j2d_glUniform3fARB(loc, p0, p1, p3);
|
|
777 |
loc = j2d_glGetUniformLocationARB(linearGradProgram, "yoff");
|
|
778 |
j2d_glUniform1fARB(loc, (GLfloat)(dstOps->yOffset + dstOps->height));
|
|
779 |
|
|
780 |
if (useMask) {
|
|
781 |
// restore control to texture unit 0
|
|
782 |
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
|
|
783 |
}
|
|
784 |
|
|
785 |
// oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
|
|
786 |
oglc->useMask = useMask;
|
|
787 |
oglc->paintState = sun_java2d_SunGraphics2D_PAINT_LIN_GRADIENT;
|
|
788 |
}
|
|
789 |
|
|
790 |
/********************** RadialGradientPaint support *************************/
|
|
791 |
|
|
792 |
/**
|
|
793 |
* The handles to the RadialGradientPaint fragment program objects. The
|
|
794 |
* index to the array should be a bitwise-or'ing of the MULTI_* flags defined
|
|
795 |
* above. Note that most applications will likely need to initialize one
|
|
796 |
* or two of these elements, so the array is usually sparsely populated.
|
|
797 |
*/
|
|
798 |
static GLhandleARB radialGradPrograms[MAX_PROGRAMS];
|
|
799 |
|
|
800 |
/**
|
|
801 |
* Compiles and links the RadialGradientPaint shader program. If successful,
|
|
802 |
* this function returns a handle to the newly created shader program;
|
|
803 |
* otherwise returns 0.
|
|
804 |
*/
|
|
805 |
static GLhandleARB
|
|
806 |
OGLPaints_CreateRadialGradProgram(jint flags)
|
|
807 |
{
|
|
808 |
char *paintVars;
|
|
809 |
char *distCode;
|
|
810 |
|
|
811 |
J2dTraceLn1(J2D_TRACE_INFO,
|
|
812 |
"OGLPaints_CreateRadialGradProgram",
|
|
813 |
flags);
|
|
814 |
|
|
815 |
/*
|
|
816 |
* To simplify the code and to make it easier to upload a number of
|
|
817 |
* uniform values at once, we pack a bunch of scalar (float) values
|
|
818 |
* into vec3 and vec4 values below. Here's how the values are related:
|
|
819 |
*
|
|
820 |
* m0.x = m00
|
|
821 |
* m0.y = m01
|
|
822 |
* m0.z = m02
|
|
823 |
*
|
|
824 |
* m1.x = m10
|
|
825 |
* m1.y = m11
|
|
826 |
* m1.z = m12
|
|
827 |
*
|
|
828 |
* precalc.x = focusX
|
|
829 |
* precalc.y = yoff = dstOps->yOffset + dstOps->height
|
|
830 |
* precalc.z = 1.0 - (focusX * focusX)
|
|
831 |
* precalc.w = 1.0 / precalc.z
|
|
832 |
*/
|
|
833 |
paintVars =
|
|
834 |
"uniform vec3 m0;"
|
|
835 |
"uniform vec3 m1;"
|
|
836 |
"uniform vec4 precalc;";
|
|
837 |
|
|
838 |
/*
|
|
839 |
* The following code is derived from Daniel Rice's whitepaper on
|
|
840 |
* radial gradient performance (attached to the bug report for 6521533).
|
|
841 |
* Refer to that document as well as the setup code in the Java-level
|
|
842 |
* BufferedPaints.setRadialGradientPaint() method for more details.
|
|
843 |
*/
|
|
844 |
distCode =
|
|
845 |
// note that gl_FragCoord is in window space relative to the
|
|
846 |
// lower-left corner, so we have to flip the y-coordinate here
|
|
847 |
"vec3 fragCoord ="
|
|
848 |
" vec3(gl_FragCoord.x, precalc.y - gl_FragCoord.y, 1.0);"
|
|
849 |
"float x = dot(fragCoord, m0);"
|
|
850 |
"float y = dot(fragCoord, m1);"
|
|
851 |
"float xfx = x - precalc.x;"
|
|
852 |
"dist = (precalc.x*xfx + sqrt(xfx*xfx + y*y*precalc.z))*precalc.w;";
|
|
853 |
|
|
854 |
return OGLPaints_CreateMultiGradProgram(flags, paintVars, distCode);
|
|
855 |
}
|
|
856 |
|
|
857 |
void
|
|
858 |
OGLPaints_SetRadialGradientPaint(OGLContext *oglc, OGLSDOps *dstOps,
|
|
859 |
jboolean useMask, jboolean linear,
|
|
860 |
jint cycleMethod, jint numStops,
|
|
861 |
jfloat m00, jfloat m01, jfloat m02,
|
|
862 |
jfloat m10, jfloat m11, jfloat m12,
|
|
863 |
jfloat focusX,
|
|
864 |
void *fractions, void *pixels)
|
|
865 |
{
|
|
866 |
GLhandleARB radialGradProgram;
|
|
867 |
GLint loc;
|
|
868 |
GLfloat yoff, denom, inv_denom;
|
|
869 |
jboolean large = (numStops > MAX_FRACTIONS_SMALL);
|
|
870 |
jint flags = 0;
|
|
871 |
|
|
872 |
J2dTraceLn(J2D_TRACE_INFO, "OGLPaints_SetRadialGradientPaint");
|
|
873 |
|
|
874 |
RETURN_IF_NULL(oglc);
|
|
875 |
RETURN_IF_NULL(dstOps);
|
|
876 |
OGLPaints_ResetPaint(oglc);
|
|
877 |
|
|
878 |
COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
|
|
879 |
|
|
880 |
if (useMask) {
|
|
881 |
// set up the paint on texture unit 1 (instead of the usual unit 0)
|
|
882 |
j2d_glActiveTextureARB(GL_TEXTURE1_ARB);
|
|
883 |
}
|
|
884 |
// no need to set GL_MODULATE here (it is ignored when shader is enabled)
|
|
885 |
|
|
886 |
// locate/initialize the shader program for the given flags
|
|
887 |
if (radialGradPrograms[flags] == 0) {
|
|
888 |
radialGradPrograms[flags] = OGLPaints_CreateRadialGradProgram(flags);
|
|
889 |
if (radialGradPrograms[flags] == 0) {
|
|
890 |
// shouldn't happen, but just in case...
|
|
891 |
return;
|
|
892 |
}
|
|
893 |
}
|
|
894 |
radialGradProgram = radialGradPrograms[flags];
|
|
895 |
|
|
896 |
// update the common "uniform" values (fractions and colors)
|
|
897 |
OGLPaints_SetMultiGradientPaint(radialGradProgram,
|
|
898 |
numStops, fractions, pixels);
|
|
899 |
|
|
900 |
// update the other "uniform" values
|
|
901 |
loc = j2d_glGetUniformLocationARB(radialGradProgram, "m0");
|
|
902 |
j2d_glUniform3fARB(loc, m00, m01, m02);
|
|
903 |
loc = j2d_glGetUniformLocationARB(radialGradProgram, "m1");
|
|
904 |
j2d_glUniform3fARB(loc, m10, m11, m12);
|
|
905 |
|
|
906 |
// pack a few unrelated, precalculated values into a single vec4
|
|
907 |
yoff = (GLfloat)(dstOps->yOffset + dstOps->height);
|
|
908 |
denom = 1.0f - (focusX * focusX);
|
|
909 |
inv_denom = 1.0f / denom;
|
|
910 |
loc = j2d_glGetUniformLocationARB(radialGradProgram, "precalc");
|
|
911 |
j2d_glUniform4fARB(loc, focusX, yoff, denom, inv_denom);
|
|
912 |
|
|
913 |
if (useMask) {
|
|
914 |
// restore control to texture unit 0
|
|
915 |
j2d_glActiveTextureARB(GL_TEXTURE0_ARB);
|
|
916 |
}
|
|
917 |
|
|
918 |
// oglc->pixel has been set appropriately in OGLPaints_ResetPaint()
|
|
919 |
oglc->useMask = useMask;
|
|
920 |
oglc->paintState = sun_java2d_SunGraphics2D_PAINT_RAD_GRADIENT;
|
|
921 |
}
|
|
922 |
|
|
923 |
#endif /* !HEADLESS */
|