1 /*
2 * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
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
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
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 *
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.
24 */
25
26 #include <jlong.h>
27 #include <string.h>
28
29 #include "sun_java2d_d3d_D3DPaints_MultiGradient.h"
30
31 #include "D3DPaints.h"
32 #include "D3DContext.h"
33 #include "D3DRenderQueue.h"
34 #include "D3DSurfaceData.h"
35
36 HRESULT
D3DPaints_ResetPaint(D3DContext * d3dc)37 D3DPaints_ResetPaint(D3DContext *d3dc)
38 {
39 jint pixel, paintState;
40 jubyte ea;
41 HRESULT res;
42
43 J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_ResetPaint");
44
45 RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
46
47 paintState = d3dc->GetPaintState();
48 J2dTraceLn1(J2D_TRACE_VERBOSE, " state=%d", paintState);
49
50 res = d3dc->UpdateState(STATE_OTHEROP);
51
52 // disable current complex paint state, if necessary
53 if (paintState > PAINT_ALPHACOLOR) {
54 IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
55 DWORD sampler = d3dc->useMask ? 1 : 0;
56
57 d3dc->SetTexture(NULL, sampler);
58 pd3dDevice->SetSamplerState(sampler,
59 D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
60 pd3dDevice->SetSamplerState(sampler,
61 D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
62 pd3dDevice->SetTextureStageState(sampler,
63 D3DTSS_TEXCOORDINDEX, sampler);
64 res = pd3dDevice->SetTextureStageState(sampler,
65 D3DTSS_TEXTURETRANSFORMFLAGS,
66 D3DTTFF_DISABLE);
67
68 if (paintState == PAINT_GRADIENT ||
69 paintState == PAINT_LIN_GRADIENT ||
70 paintState == PAINT_RAD_GRADIENT)
71 {
72 res = pd3dDevice->SetPixelShader(NULL);
73 }
74 }
75
76 // set each component of the current color state to the extra alpha
77 // value, which will effectively apply the extra alpha to each fragment
78 // in paint/texturing operations
79 ea = (jubyte)(d3dc->extraAlpha * 0xff + 0.5f);
80 pixel = (ea << 24) | (ea << 16) | (ea << 8) | (ea << 0);
81 d3dc->pVCacher->SetColor(pixel);
82 d3dc->useMask = JNI_FALSE;
83 d3dc->SetPaintState(-1);
84 return res;
85 }
86
87 HRESULT
D3DPaints_SetColor(D3DContext * d3dc,jint pixel)88 D3DPaints_SetColor(D3DContext *d3dc, jint pixel)
89 {
90 HRESULT res = S_OK;
91
92 J2dTraceLn1(J2D_TRACE_INFO, "D3DPaints_SetColor: pixel=%08x", pixel);
93
94 RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
95
96 // no need to reset the current op state here unless the paint
97 // state really needs to be changed
98 if (d3dc->GetPaintState() > PAINT_ALPHACOLOR) {
99 res = D3DPaints_ResetPaint(d3dc);
100 }
101
102 d3dc->pVCacher->SetColor(pixel);
103 d3dc->useMask = JNI_FALSE;
104 d3dc->SetPaintState(PAINT_ALPHACOLOR);
105 return res;
106 }
107
108 /************************* GradientPaint support ****************************/
109
110 HRESULT
D3DPaints_SetGradientPaint(D3DContext * d3dc,jboolean useMask,jboolean cyclic,jdouble p0,jdouble p1,jdouble p3,jint pixel1,jint pixel2)111 D3DPaints_SetGradientPaint(D3DContext *d3dc,
112 jboolean useMask, jboolean cyclic,
113 jdouble p0, jdouble p1, jdouble p3,
114 jint pixel1, jint pixel2)
115 {
116 IDirect3DDevice9 *pd3dDevice;
117 HRESULT res;
118
119 J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetGradientPaint");
120
121 RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
122 D3DPaints_ResetPaint(d3dc);
123
124 #if 0
125 /*
126 * REMIND: The following code represents the original fast gradient
127 * implementation. The problem is that it relies on LINEAR
128 * texture filtering, which does not provide sufficient
129 * precision on certain hardware (from ATI, notably), which
130 * will cause visible banding (e.g. 64 shades of gray between
131 * black and white, instead of the expected 256 shades. For
132 * correctness on such hardware, it is necessary to use a
133 * shader-based approach that does not suffer from these
134 * precision issues (see below). This original implementation
135 * is about 16x faster than software, whereas the shader-based
136 * implementation is only about 4x faster than software (still
137 * impressive). For simplicity, we will always use the
138 * shader-based version for now, but in the future we could
139 * consider using the fast path for certain hardware (that does
140 * not exhibit the problem) or provide a flag to allow developers
141 * to control which path we take (for those that are less
142 * concerned about quality). Therefore, I'll leave this code
143 * here (currently disabled) for future use.
144 */
145 D3DResource *pGradientTexRes;
146 IDirect3DTexture9 *pGradientTex;
147
148 // this will initialize the gradient texture, if necessary
149 res = d3dc->GetResourceManager()->GetGradientTexture(&pGradientTexRes);
150 RETURN_STATUS_IF_FAILED(res);
151
152 pGradientTex = pGradientTexRes->GetTexture();
153
154 // update the texture containing the gradient colors
155 {
156 D3DLOCKED_RECT lockedRect;
157 res = pGradientTex->LockRect(0, &lockedRect, NULL, D3DLOCK_NOSYSLOCK);
158 RETURN_STATUS_IF_FAILED(res);
159 jint *pPix = (jint*)lockedRect.pBits;
160 pPix[0] = pixel1;
161 pPix[1] = pixel2;
162 pGradientTex->UnlockRect(0);
163 }
164
165 DWORD sampler = useMask ? 1 : 0;
166 DWORD wrapMode = cyclic ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
167 d3dc->SetTexture(pGradientTex, sampler);
168 d3dc->UpdateTextureColorState(D3DTA_TEXTURE, sampler);
169
170 pd3dDevice = d3dc->Get3DDevice();
171 pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSU, wrapMode);
172 pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSV, wrapMode);
173 pd3dDevice->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
174 pd3dDevice->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
175
176 D3DMATRIX mt;
177 ZeroMemory(&mt, sizeof(mt));
178 mt._11 = (float)p0;
179 mt._21 = (float)p1;
180 mt._31 = (float)0.0;
181 mt._41 = (float)p3;
182 mt._12 = 0.0f;
183 mt._22 = 1.0f;
184 mt._32 = 0.0f;
185 mt._42 = 0.0f;
186 pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);
187 pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,
188 D3DTSS_TCI_CAMERASPACEPOSITION);
189 res = pd3dDevice->SetTextureStageState(sampler,
190 D3DTSS_TEXTURETRANSFORMFLAGS,
191 D3DTTFF_COUNT2);
192 #else
193 jfloat params[4];
194 jfloat color[4];
195 jint flags = 0;
196
197 if (cyclic) flags |= BASIC_GRAD_IS_CYCLIC;
198 if (useMask) flags |= BASIC_GRAD_USE_MASK;
199
200 // locate/enable the shader program for the given flags
201 res = d3dc->EnableBasicGradientProgram(flags);
202 RETURN_STATUS_IF_FAILED(res);
203
204 // update the "uniform" values
205 params[0] = (jfloat)p0;
206 params[1] = (jfloat)p1;
207 params[2] = (jfloat)p3;
208 params[3] = 0.0f; // unused
209 pd3dDevice = d3dc->Get3DDevice();
210 res = pd3dDevice->SetPixelShaderConstantF(0, params, 1);
211
212 color[0] = ((pixel1 >> 16) & 0xff) / 255.0f; // r
213 color[1] = ((pixel1 >> 8) & 0xff) / 255.0f; // g
214 color[2] = ((pixel1 >> 0) & 0xff) / 255.0f; // b
215 color[3] = ((pixel1 >> 24) & 0xff) / 255.0f; // a
216 res = pd3dDevice->SetPixelShaderConstantF(1, color, 1);
217
218 color[0] = ((pixel2 >> 16) & 0xff) / 255.0f; // r
219 color[1] = ((pixel2 >> 8) & 0xff) / 255.0f; // g
220 color[2] = ((pixel2 >> 0) & 0xff) / 255.0f; // b
221 color[3] = ((pixel2 >> 24) & 0xff) / 255.0f; // a
222 res = pd3dDevice->SetPixelShaderConstantF(2, color, 1);
223
224 // set up texture coordinate transform with identity matrix, which
225 // will have the effect of passing the current window-space coordinates
226 // through to the TEXCOORD0/1 register used by the basic gradient
227 // pixel shader
228 DWORD sampler = useMask ? 1 : 0;
229 D3DMATRIX mt;
230 ZeroMemory(&mt, sizeof(mt));
231 mt._11 = 1.0f;
232 mt._21 = 0.0f;
233 mt._31 = 0.0f;
234 mt._41 = 0.0f;
235 mt._12 = 0.0f;
236 mt._22 = 1.0f;
237 mt._32 = 0.0f;
238 mt._42 = 0.0f;
239 pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);
240 pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,
241 D3DTSS_TCI_CAMERASPACEPOSITION);
242 pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXTURETRANSFORMFLAGS,
243 D3DTTFF_COUNT2);
244 #endif
245
246 // pixel state has been set appropriately in D3DPaints_ResetPaint()
247 d3dc->useMask = useMask;
248 d3dc->SetPaintState(PAINT_GRADIENT);
249 return res;
250 }
251
252 /************************** TexturePaint support ****************************/
253
254 HRESULT
D3DPaints_SetTexturePaint(D3DContext * d3dc,jboolean useMask,jlong pSrcOps,jboolean filter,jdouble xp0,jdouble xp1,jdouble xp3,jdouble yp0,jdouble yp1,jdouble yp3)255 D3DPaints_SetTexturePaint(D3DContext *d3dc,
256 jboolean useMask,
257 jlong pSrcOps, jboolean filter,
258 jdouble xp0, jdouble xp1, jdouble xp3,
259 jdouble yp0, jdouble yp1, jdouble yp3)
260 {
261 D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps);
262 IDirect3DDevice9 *pd3dDevice;
263 HRESULT res;
264
265 J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetTexturePaint");
266
267 RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
268 RETURN_STATUS_IF_NULL(srcOps, E_FAIL);
269 RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);
270 D3DPaints_ResetPaint(d3dc);
271
272 DWORD sampler = useMask ? 1 : 0;
273 DWORD dwFilter = filter ? D3DTEXF_LINEAR : D3DTEXF_POINT;
274 res = d3dc->SetTexture(srcOps->pResource->GetTexture(), sampler);
275 d3dc->UpdateTextureColorState(D3DTA_TEXTURE, sampler);
276 pd3dDevice = d3dc->Get3DDevice();
277 pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
278 pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
279 pd3dDevice->SetSamplerState(sampler, D3DSAMP_MAGFILTER, dwFilter);
280 pd3dDevice->SetSamplerState(sampler, D3DSAMP_MINFILTER, dwFilter);
281
282 D3DMATRIX mt;
283 ZeroMemory(&mt, sizeof(mt));
284
285 // offset by a half texel to correctly map texels to pixels
286 // m02 = tx * m00 + ty * m01 + m02;
287 // m12 = tx * m10 + ty * m11 + m12;
288 jdouble tx = (1 / (2.0f * srcOps->pResource->GetDesc()->Width));
289 jdouble ty = (1 / (2.0f * srcOps->pResource->GetDesc()->Height));
290 xp3 = tx * xp0 + ty * xp1 + xp3;
291 yp3 = tx * yp0 + ty * yp1 + yp3;
292
293 mt._11 = (float)xp0;
294 mt._21 = (float)xp1;
295 mt._31 = (float)0.0;
296 mt._41 = (float)xp3;
297 mt._12 = (float)yp0;
298 mt._22 = (float)yp1;
299 mt._32 = (float)0.0;
300 mt._42 = (float)yp3;
301 pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);
302 pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,
303 D3DTSS_TCI_CAMERASPACEPOSITION);
304 pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXTURETRANSFORMFLAGS,
305 D3DTTFF_COUNT2);
306
307 // pixel state has been set appropriately in D3DPaints_ResetPaint()
308 d3dc->useMask = useMask;
309 d3dc->SetPaintState(PAINT_TEXTURE);
310 return res;
311 }
312
313 /****************** Shared MultipleGradientPaint support ********************/
314
315 /** Composes the given parameters as flags into the given flags variable.*/
316 #define COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear) \
317 do { \
318 flags |= ((cycleMethod) & MULTI_GRAD_CYCLE_METHOD); \
319 if (large) flags |= MULTI_GRAD_LARGE; \
320 if (useMask) flags |= MULTI_GRAD_USE_MASK; \
321 if (linear) flags |= MULTI_GRAD_LINEAR_RGB; \
322 } while (0)
323
324 /**
325 * The maximum number of gradient "stops" supported by the fragment shader
326 * and related code. When the MULTI_GRAD_LARGE flag is set, we will use
327 * MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having
328 * two separate values, we can have one highly optimized shader (SMALL) that
329 * supports only a few fractions/colors, and then another, less optimal
330 * shader that supports more stops.
331 */
332 #define MAX_FRACTIONS \
333 sun_java2d_d3d_D3DPaints_MultiGradient_MULTI_MAX_FRACTIONS_D3D
334 #define MAX_FRACTIONS_LARGE MAX_FRACTIONS
335 #define MAX_FRACTIONS_SMALL 4
336
337 /**
338 * Called from the D3DPaints_SetLinear/RadialGradientPaint() methods
339 * in order to setup the fraction/color values that are common to both.
340 */
341 static HRESULT
D3DPaints_SetMultiGradientPaint(D3DContext * d3dc,jboolean useMask,jint numStops,void * pFractions,void * pPixels)342 D3DPaints_SetMultiGradientPaint(D3DContext *d3dc,
343 jboolean useMask, jint numStops,
344 void *pFractions, void *pPixels)
345 {
346 HRESULT res;
347 IDirect3DDevice9 *pd3dDevice;
348 IDirect3DTexture9 *pMultiGradientTex;
349 D3DResource *pMultiGradientTexRes;
350 jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ?
351 MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;
352 jfloat stopVals[MAX_FRACTIONS * 4];
353 jfloat *fractions = (jfloat *)pFractions;
354 juint *pixels = (juint *)pPixels;
355 int i;
356 int fIndex = 0;
357
358 pd3dDevice = d3dc->Get3DDevice();
359
360 // update the "uniform" fractions and scale factors
361 for (i = 0; i < maxFractions; i++) {
362 stopVals[fIndex+0] = (i < numStops) ?
363 fractions[i] : 0.0f;
364 stopVals[fIndex+1] = (i < numStops-1) ?
365 1.0f / (fractions[i+1] - fractions[i]) : 0.0f;
366 stopVals[fIndex+2] = 0.0f; // unused
367 stopVals[fIndex+3] = 0.0f; // unused
368 fIndex += 4;
369 }
370 pd3dDevice->SetPixelShaderConstantF(0, stopVals, maxFractions);
371
372 // this will initialize the multi-gradient texture, if necessary
373 res = d3dc->GetResourceManager()->
374 GetMultiGradientTexture(&pMultiGradientTexRes);
375 RETURN_STATUS_IF_FAILED(res);
376
377 pMultiGradientTex = pMultiGradientTexRes->GetTexture();
378
379 // update the texture containing the gradient colors
380 D3DLOCKED_RECT lockedRect;
381 res = pMultiGradientTex->LockRect(0, &lockedRect, NULL, D3DLOCK_NOSYSLOCK);
382 RETURN_STATUS_IF_FAILED(res);
383
384 juint *pPix = (juint*)lockedRect.pBits;
385 memcpy(pPix, pixels, numStops*sizeof(juint));
386 if (numStops < MAX_MULTI_GRADIENT_COLORS) {
387 // when we don't have enough colors to fill the entire
388 // color gradient, we have to replicate the last color
389 // in the right-most texel for the NO_CYCLE case where the
390 // texcoord is sometimes forced to 1.0
391 pPix[MAX_MULTI_GRADIENT_COLORS-1] = pixels[numStops-1];
392 }
393 pMultiGradientTex->UnlockRect(0);
394
395 // set the gradient texture and update relevant state
396 DWORD sampler = useMask ? 1 : 0;
397 res = d3dc->SetTexture(pMultiGradientTex, sampler);
398 d3dc->UpdateTextureColorState(D3DTA_TEXTURE, sampler);
399 pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
400 pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
401 pd3dDevice->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
402 pd3dDevice->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
403
404 // set up texture coordinate transform with identity matrix, which
405 // will have the effect of passing the current window-space coordinates
406 // through to the TEXCOORD0/1 register used by the multi-stop
407 // gradient pixel shader
408 D3DMATRIX mt;
409 ZeroMemory(&mt, sizeof(mt));
410 mt._11 = 1.0f;
411 mt._21 = 0.0f;
412 mt._31 = 0.0f;
413 mt._41 = 0.0f;
414 mt._12 = 0.0f;
415 mt._22 = 1.0f;
416 mt._32 = 0.0f;
417 mt._42 = 0.0f;
418 pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);
419 pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,
420 D3DTSS_TCI_CAMERASPACEPOSITION);
421 pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXTURETRANSFORMFLAGS,
422 D3DTTFF_COUNT2);
423 return res;
424 }
425
426 /********************** LinearGradientPaint support *************************/
427
428 HRESULT
D3DPaints_SetLinearGradientPaint(D3DContext * d3dc,D3DSDOps * dstOps,jboolean useMask,jboolean linear,jint cycleMethod,jint numStops,jfloat p0,jfloat p1,jfloat p3,void * fractions,void * pixels)429 D3DPaints_SetLinearGradientPaint(D3DContext *d3dc, D3DSDOps *dstOps,
430 jboolean useMask, jboolean linear,
431 jint cycleMethod, jint numStops,
432 jfloat p0, jfloat p1, jfloat p3,
433 void *fractions, void *pixels)
434 {
435 HRESULT res;
436 IDirect3DDevice9 *pd3dDevice;
437 jfloat params[4];
438 jboolean large = (numStops > MAX_FRACTIONS_SMALL);
439 jint flags = 0;
440
441 J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetLinearGradientPaint");
442
443 RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
444 RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
445 D3DPaints_ResetPaint(d3dc);
446
447 COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
448
449 // locate/enable the shader program for the given flags
450 res = d3dc->EnableLinearGradientProgram(flags);
451 RETURN_STATUS_IF_FAILED(res);
452
453 // update the common "uniform" values (fractions and colors)
454 D3DPaints_SetMultiGradientPaint(d3dc, useMask,
455 numStops, fractions, pixels);
456
457 // update the other "uniform" values
458 params[0] = p0;
459 params[1] = p1;
460 params[2] = p3;
461 params[3] = 0.0f; // unused
462 pd3dDevice = d3dc->Get3DDevice();
463 res = pd3dDevice->SetPixelShaderConstantF(16, params, 1);
464
465 // pixel state has been set appropriately in D3DPaints_ResetPaint()
466 d3dc->useMask = useMask;
467 d3dc->SetPaintState(PAINT_LIN_GRADIENT);
468 return res;
469 }
470
471 /********************** RadialGradientPaint support *************************/
472
473 HRESULT
D3DPaints_SetRadialGradientPaint(D3DContext * d3dc,D3DSDOps * dstOps,jboolean useMask,jboolean linear,jint cycleMethod,jint numStops,jfloat m00,jfloat m01,jfloat m02,jfloat m10,jfloat m11,jfloat m12,jfloat focusX,void * fractions,void * pixels)474 D3DPaints_SetRadialGradientPaint(D3DContext *d3dc, D3DSDOps *dstOps,
475 jboolean useMask, jboolean linear,
476 jint cycleMethod, jint numStops,
477 jfloat m00, jfloat m01, jfloat m02,
478 jfloat m10, jfloat m11, jfloat m12,
479 jfloat focusX,
480 void *fractions, void *pixels)
481 {
482 HRESULT res;
483 IDirect3DDevice9 *pd3dDevice;
484 jfloat denom, inv_denom;
485 jfloat params[4];
486 jboolean large = (numStops > MAX_FRACTIONS_SMALL);
487 jint flags = 0;
488
489 J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetRadialGradientPaint");
490
491 RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
492 RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
493 D3DPaints_ResetPaint(d3dc);
494
495 COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
496
497 // locate/enable the shader program for the given flags
498 res = d3dc->EnableRadialGradientProgram(flags);
499 RETURN_STATUS_IF_FAILED(res);
500
501 // update the common "uniform" values (fractions and colors)
502 D3DPaints_SetMultiGradientPaint(d3dc, useMask,
503 numStops, fractions, pixels);
504
505 // update the other "uniform" values
506 params[0] = m00;
507 params[1] = m01;
508 params[2] = m02;
509 params[3] = 0.0f; // unused
510 pd3dDevice = d3dc->Get3DDevice();
511 pd3dDevice->SetPixelShaderConstantF(16, params, 1);
512
513 params[0] = m10;
514 params[1] = m11;
515 params[2] = m12;
516 params[3] = 0.0f; // unused
517 pd3dDevice->SetPixelShaderConstantF(17, params, 1);
518
519 // pack a few unrelated, precalculated values into a single float4
520 denom = 1.0f - (focusX * focusX);
521 inv_denom = 1.0f / denom;
522 params[0] = focusX;
523 params[1] = denom;
524 params[2] = inv_denom;
525 params[3] = 0.0f; // unused
526 res = pd3dDevice->SetPixelShaderConstantF(18, params, 1);
527
528 // pixel state has been set appropriately in D3DPaints_ResetPaint()
529 d3dc->useMask = useMask;
530 d3dc->SetPaintState(PAINT_RAD_GRADIENT);
531 return res;
532 }
533