aboutsummaryrefslogtreecommitdiff
path: root/src/windows/native/sun/java2d/d3d/D3DPaints.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/windows/native/sun/java2d/d3d/D3DPaints.cpp')
-rw-r--r--src/windows/native/sun/java2d/d3d/D3DPaints.cpp532
1 files changed, 532 insertions, 0 deletions
diff --git a/src/windows/native/sun/java2d/d3d/D3DPaints.cpp b/src/windows/native/sun/java2d/d3d/D3DPaints.cpp
new file mode 100644
index 000000000..f11049904
--- /dev/null
+++ b/src/windows/native/sun/java2d/d3d/D3DPaints.cpp
@@ -0,0 +1,532 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <jlong.h>
+#include <string.h>
+
+#include "sun_java2d_d3d_D3DPaints_MultiGradient.h"
+
+#include "D3DPaints.h"
+#include "D3DContext.h"
+#include "D3DRenderQueue.h"
+#include "D3DSurfaceData.h"
+
+HRESULT
+D3DPaints_ResetPaint(D3DContext *d3dc)
+{
+ jint pixel, paintState;
+ jubyte ea;
+ HRESULT res;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_ResetPaint");
+
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+
+ paintState = d3dc->GetPaintState();
+ J2dTraceLn1(J2D_TRACE_VERBOSE, " state=%d", paintState);
+
+ res = d3dc->UpdateState(STATE_OTHEROP);
+
+ // disable current complex paint state, if necessary
+ if (paintState > PAINT_ALPHACOLOR) {
+ IDirect3DDevice9 *pd3dDevice = d3dc->Get3DDevice();
+ DWORD sampler = d3dc->useMask ? 1 : 0;
+
+ d3dc->SetTexture(NULL, sampler);
+ pd3dDevice->SetSamplerState(sampler,
+ D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ pd3dDevice->SetSamplerState(sampler,
+ D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+ pd3dDevice->SetTextureStageState(sampler,
+ D3DTSS_TEXCOORDINDEX, sampler);
+ res = pd3dDevice->SetTextureStageState(sampler,
+ D3DTSS_TEXTURETRANSFORMFLAGS,
+ D3DTTFF_DISABLE);
+
+ if (paintState == PAINT_GRADIENT ||
+ paintState == PAINT_LIN_GRADIENT ||
+ paintState == PAINT_RAD_GRADIENT)
+ {
+ res = pd3dDevice->SetPixelShader(NULL);
+ }
+ }
+
+ // set each component of the current color state to the extra alpha
+ // value, which will effectively apply the extra alpha to each fragment
+ // in paint/texturing operations
+ ea = (jubyte)(d3dc->extraAlpha * 0xff + 0.5f);
+ pixel = (ea << 24) | (ea << 16) | (ea << 8) | (ea << 0);
+ d3dc->pVCacher->SetColor(pixel);
+ d3dc->useMask = JNI_FALSE;
+ d3dc->SetPaintState(-1);
+ return res;
+}
+
+HRESULT
+D3DPaints_SetColor(D3DContext *d3dc, jint pixel)
+{
+ HRESULT res = S_OK;
+
+ J2dTraceLn1(J2D_TRACE_INFO, "D3DPaints_SetColor: pixel=%08x", pixel);
+
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+
+ // no need to reset the current op state here unless the paint
+ // state really needs to be changed
+ if (d3dc->GetPaintState() > PAINT_ALPHACOLOR) {
+ res = D3DPaints_ResetPaint(d3dc);
+ }
+
+ d3dc->pVCacher->SetColor(pixel);
+ d3dc->useMask = JNI_FALSE;
+ d3dc->SetPaintState(PAINT_ALPHACOLOR);
+ return res;
+}
+
+/************************* GradientPaint support ****************************/
+
+HRESULT
+D3DPaints_SetGradientPaint(D3DContext *d3dc,
+ jboolean useMask, jboolean cyclic,
+ jdouble p0, jdouble p1, jdouble p3,
+ jint pixel1, jint pixel2)
+{
+ IDirect3DDevice9 *pd3dDevice;
+ HRESULT res;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetGradientPaint");
+
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+ D3DPaints_ResetPaint(d3dc);
+
+#if 0
+ /*
+ * REMIND: The following code represents the original fast gradient
+ * implementation. The problem is that it relies on LINEAR
+ * texture filtering, which does not provide sufficient
+ * precision on certain hardware (from ATI, notably), which
+ * will cause visible banding (e.g. 64 shades of gray between
+ * black and white, instead of the expected 256 shades. For
+ * correctness on such hardware, it is necessary to use a
+ * shader-based approach that does not suffer from these
+ * precision issues (see below). This original implementation
+ * is about 16x faster than software, whereas the shader-based
+ * implementation is only about 4x faster than software (still
+ * impressive). For simplicity, we will always use the
+ * shader-based version for now, but in the future we could
+ * consider using the fast path for certain hardware (that does
+ * not exhibit the problem) or provide a flag to allow developers
+ * to control which path we take (for those that are less
+ * concerned about quality). Therefore, I'll leave this code
+ * here (currently disabled) for future use.
+ */
+ D3DResource *pGradientTexRes;
+ IDirect3DTexture9 *pGradientTex;
+
+ // this will initialize the gradient texture, if necessary
+ res = d3dc->GetResourceManager()->GetGradientTexture(&pGradientTexRes);
+ RETURN_STATUS_IF_FAILED(res);
+
+ pGradientTex = pGradientTexRes->GetTexture();
+
+ // update the texture containing the gradient colors
+ {
+ D3DLOCKED_RECT lockedRect;
+ res = pGradientTex->LockRect(0, &lockedRect, NULL, D3DLOCK_NOSYSLOCK);
+ RETURN_STATUS_IF_FAILED(res);
+ jint *pPix = (jint*)lockedRect.pBits;
+ pPix[0] = pixel1;
+ pPix[1] = pixel2;
+ pGradientTex->UnlockRect(0);
+ }
+
+ DWORD sampler = useMask ? 1 : 0;
+ DWORD wrapMode = cyclic ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
+ d3dc->SetTexture(pGradientTex, sampler);
+ d3dc->UpdateTextureColorState(D3DTA_TEXTURE, sampler);
+
+ pd3dDevice = d3dc->Get3DDevice();
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSU, wrapMode);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSV, wrapMode);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+
+ D3DMATRIX mt;
+ ZeroMemory(&mt, sizeof(mt));
+ mt._11 = (float)p0;
+ mt._21 = (float)p1;
+ mt._31 = (float)0.0;
+ mt._41 = (float)p3;
+ mt._12 = 0.0f;
+ mt._22 = 1.0f;
+ mt._32 = 0.0f;
+ mt._42 = 0.0f;
+ pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);
+ pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,
+ D3DTSS_TCI_CAMERASPACEPOSITION);
+ res = pd3dDevice->SetTextureStageState(sampler,
+ D3DTSS_TEXTURETRANSFORMFLAGS,
+ D3DTTFF_COUNT2);
+#else
+ jfloat params[4];
+ jfloat color[4];
+ jint flags = 0;
+
+ if (cyclic) flags |= BASIC_GRAD_IS_CYCLIC;
+ if (useMask) flags |= BASIC_GRAD_USE_MASK;
+
+ // locate/enable the shader program for the given flags
+ res = d3dc->EnableBasicGradientProgram(flags);
+ RETURN_STATUS_IF_FAILED(res);
+
+ // update the "uniform" values
+ params[0] = (jfloat)p0;
+ params[1] = (jfloat)p1;
+ params[2] = (jfloat)p3;
+ params[3] = 0.0f; // unused
+ pd3dDevice = d3dc->Get3DDevice();
+ res = pd3dDevice->SetPixelShaderConstantF(0, params, 1);
+
+ color[0] = ((pixel1 >> 16) & 0xff) / 255.0f; // r
+ color[1] = ((pixel1 >> 8) & 0xff) / 255.0f; // g
+ color[2] = ((pixel1 >> 0) & 0xff) / 255.0f; // b
+ color[3] = ((pixel1 >> 24) & 0xff) / 255.0f; // a
+ res = pd3dDevice->SetPixelShaderConstantF(1, color, 1);
+
+ color[0] = ((pixel2 >> 16) & 0xff) / 255.0f; // r
+ color[1] = ((pixel2 >> 8) & 0xff) / 255.0f; // g
+ color[2] = ((pixel2 >> 0) & 0xff) / 255.0f; // b
+ color[3] = ((pixel2 >> 24) & 0xff) / 255.0f; // a
+ res = pd3dDevice->SetPixelShaderConstantF(2, color, 1);
+
+ // set up texture coordinate transform with identity matrix, which
+ // will have the effect of passing the current window-space coordinates
+ // through to the TEXCOORD0/1 register used by the basic gradient
+ // pixel shader
+ DWORD sampler = useMask ? 1 : 0;
+ D3DMATRIX mt;
+ ZeroMemory(&mt, sizeof(mt));
+ mt._11 = 1.0f;
+ mt._21 = 0.0f;
+ mt._31 = 0.0f;
+ mt._41 = 0.0f;
+ mt._12 = 0.0f;
+ mt._22 = 1.0f;
+ mt._32 = 0.0f;
+ mt._42 = 0.0f;
+ pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);
+ pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,
+ D3DTSS_TCI_CAMERASPACEPOSITION);
+ pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXTURETRANSFORMFLAGS,
+ D3DTTFF_COUNT2);
+#endif
+
+ // pixel state has been set appropriately in D3DPaints_ResetPaint()
+ d3dc->useMask = useMask;
+ d3dc->SetPaintState(PAINT_GRADIENT);
+ return res;
+}
+
+/************************** TexturePaint support ****************************/
+
+HRESULT
+D3DPaints_SetTexturePaint(D3DContext *d3dc,
+ jboolean useMask,
+ jlong pSrcOps, jboolean filter,
+ jdouble xp0, jdouble xp1, jdouble xp3,
+ jdouble yp0, jdouble yp1, jdouble yp3)
+{
+ D3DSDOps *srcOps = (D3DSDOps *)jlong_to_ptr(pSrcOps);
+ IDirect3DDevice9 *pd3dDevice;
+ HRESULT res;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetTexturePaint");
+
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+ RETURN_STATUS_IF_NULL(srcOps, E_FAIL);
+ RETURN_STATUS_IF_NULL(srcOps->pResource, E_FAIL);
+ D3DPaints_ResetPaint(d3dc);
+
+ DWORD sampler = useMask ? 1 : 0;
+ DWORD dwFilter = filter ? D3DTEXF_LINEAR : D3DTEXF_POINT;
+ res = d3dc->SetTexture(srcOps->pResource->GetTexture(), sampler);
+ d3dc->UpdateTextureColorState(D3DTA_TEXTURE, sampler);
+ pd3dDevice = d3dc->Get3DDevice();
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_MAGFILTER, dwFilter);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_MINFILTER, dwFilter);
+
+ D3DMATRIX mt;
+ ZeroMemory(&mt, sizeof(mt));
+
+ // offset by a half texel to correctly map texels to pixels
+ // m02 = tx * m00 + ty * m01 + m02;
+ // m12 = tx * m10 + ty * m11 + m12;
+ jdouble tx = (1 / (2.0f * srcOps->pResource->GetDesc()->Width));
+ jdouble ty = (1 / (2.0f * srcOps->pResource->GetDesc()->Height));
+ xp3 = tx * xp0 + ty * xp1 + xp3;
+ yp3 = tx * yp0 + ty * yp1 + yp3;
+
+ mt._11 = (float)xp0;
+ mt._21 = (float)xp1;
+ mt._31 = (float)0.0;
+ mt._41 = (float)xp3;
+ mt._12 = (float)yp0;
+ mt._22 = (float)yp1;
+ mt._32 = (float)0.0;
+ mt._42 = (float)yp3;
+ pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);
+ pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,
+ D3DTSS_TCI_CAMERASPACEPOSITION);
+ pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXTURETRANSFORMFLAGS,
+ D3DTTFF_COUNT2);
+
+ // pixel state has been set appropriately in D3DPaints_ResetPaint()
+ d3dc->useMask = useMask;
+ d3dc->SetPaintState(PAINT_TEXTURE);
+ return res;
+}
+
+/****************** Shared MultipleGradientPaint support ********************/
+
+/** Composes the given parameters as flags into the given flags variable.*/
+#define COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear) \
+ do { \
+ flags |= ((cycleMethod) & MULTI_GRAD_CYCLE_METHOD); \
+ if (large) flags |= MULTI_GRAD_LARGE; \
+ if (useMask) flags |= MULTI_GRAD_USE_MASK; \
+ if (linear) flags |= MULTI_GRAD_LINEAR_RGB; \
+ } while (0)
+
+/**
+ * The maximum number of gradient "stops" supported by the fragment shader
+ * and related code. When the MULTI_GRAD_LARGE flag is set, we will use
+ * MAX_FRACTIONS_LARGE; otherwise, we use MAX_FRACTIONS_SMALL. By having
+ * two separate values, we can have one highly optimized shader (SMALL) that
+ * supports only a few fractions/colors, and then another, less optimal
+ * shader that supports more stops.
+ */
+#define MAX_FRACTIONS \
+ sun_java2d_d3d_D3DPaints_MultiGradient_MULTI_MAX_FRACTIONS_D3D
+#define MAX_FRACTIONS_LARGE MAX_FRACTIONS
+#define MAX_FRACTIONS_SMALL 4
+
+/**
+ * Called from the D3DPaints_SetLinear/RadialGradientPaint() methods
+ * in order to setup the fraction/color values that are common to both.
+ */
+static HRESULT
+D3DPaints_SetMultiGradientPaint(D3DContext *d3dc,
+ jboolean useMask, jint numStops,
+ void *pFractions, void *pPixels)
+{
+ HRESULT res;
+ IDirect3DDevice9 *pd3dDevice;
+ IDirect3DTexture9 *pMultiGradientTex;
+ D3DResource *pMultiGradientTexRes;
+ jint maxFractions = (numStops > MAX_FRACTIONS_SMALL) ?
+ MAX_FRACTIONS_LARGE : MAX_FRACTIONS_SMALL;
+ jfloat stopVals[MAX_FRACTIONS * 4];
+ jfloat *fractions = (jfloat *)pFractions;
+ juint *pixels = (juint *)pPixels;
+ int i;
+ int fIndex = 0;
+
+ pd3dDevice = d3dc->Get3DDevice();
+
+ // update the "uniform" fractions and scale factors
+ for (i = 0; i < maxFractions; i++) {
+ stopVals[fIndex+0] = (i < numStops) ?
+ fractions[i] : 0.0f;
+ stopVals[fIndex+1] = (i < numStops-1) ?
+ 1.0f / (fractions[i+1] - fractions[i]) : 0.0f;
+ stopVals[fIndex+2] = 0.0f; // unused
+ stopVals[fIndex+3] = 0.0f; // unused
+ fIndex += 4;
+ }
+ pd3dDevice->SetPixelShaderConstantF(0, stopVals, maxFractions);
+
+ // this will initialize the multi-gradient texture, if necessary
+ res = d3dc->GetResourceManager()->
+ GetMultiGradientTexture(&pMultiGradientTexRes);
+ RETURN_STATUS_IF_FAILED(res);
+
+ pMultiGradientTex = pMultiGradientTexRes->GetTexture();
+
+ // update the texture containing the gradient colors
+ D3DLOCKED_RECT lockedRect;
+ res = pMultiGradientTex->LockRect(0, &lockedRect, NULL, D3DLOCK_NOSYSLOCK);
+ RETURN_STATUS_IF_FAILED(res);
+
+ juint *pPix = (juint*)lockedRect.pBits;
+ memcpy(pPix, pixels, numStops*sizeof(juint));
+ if (numStops < MAX_MULTI_GRADIENT_COLORS) {
+ // when we don't have enough colors to fill the entire
+ // color gradient, we have to replicate the last color
+ // in the right-most texel for the NO_CYCLE case where the
+ // texcoord is sometimes forced to 1.0
+ pPix[MAX_MULTI_GRADIENT_COLORS-1] = pixels[numStops-1];
+ }
+ pMultiGradientTex->UnlockRect(0);
+
+ // set the gradient texture and update relevant state
+ DWORD sampler = useMask ? 1 : 0;
+ res = d3dc->SetTexture(pMultiGradientTex, sampler);
+ d3dc->UpdateTextureColorState(D3DTA_TEXTURE, sampler);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
+ pd3dDevice->SetSamplerState(sampler, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
+
+ // set up texture coordinate transform with identity matrix, which
+ // will have the effect of passing the current window-space coordinates
+ // through to the TEXCOORD0/1 register used by the multi-stop
+ // gradient pixel shader
+ D3DMATRIX mt;
+ ZeroMemory(&mt, sizeof(mt));
+ mt._11 = 1.0f;
+ mt._21 = 0.0f;
+ mt._31 = 0.0f;
+ mt._41 = 0.0f;
+ mt._12 = 0.0f;
+ mt._22 = 1.0f;
+ mt._32 = 0.0f;
+ mt._42 = 0.0f;
+ pd3dDevice->SetTransform(useMask ? D3DTS_TEXTURE1 : D3DTS_TEXTURE0, &mt);
+ pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXCOORDINDEX,
+ D3DTSS_TCI_CAMERASPACEPOSITION);
+ pd3dDevice->SetTextureStageState(sampler, D3DTSS_TEXTURETRANSFORMFLAGS,
+ D3DTTFF_COUNT2);
+ return res;
+}
+
+/********************** LinearGradientPaint support *************************/
+
+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)
+{
+ HRESULT res;
+ IDirect3DDevice9 *pd3dDevice;
+ jfloat params[4];
+ jboolean large = (numStops > MAX_FRACTIONS_SMALL);
+ jint flags = 0;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetLinearGradientPaint");
+
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
+ D3DPaints_ResetPaint(d3dc);
+
+ COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
+
+ // locate/enable the shader program for the given flags
+ res = d3dc->EnableLinearGradientProgram(flags);
+ RETURN_STATUS_IF_FAILED(res);
+
+ // update the common "uniform" values (fractions and colors)
+ D3DPaints_SetMultiGradientPaint(d3dc, useMask,
+ numStops, fractions, pixels);
+
+ // update the other "uniform" values
+ params[0] = p0;
+ params[1] = p1;
+ params[2] = p3;
+ params[3] = 0.0f; // unused
+ pd3dDevice = d3dc->Get3DDevice();
+ res = pd3dDevice->SetPixelShaderConstantF(16, params, 1);
+
+ // pixel state has been set appropriately in D3DPaints_ResetPaint()
+ d3dc->useMask = useMask;
+ d3dc->SetPaintState(PAINT_LIN_GRADIENT);
+ return res;
+}
+
+/********************** RadialGradientPaint support *************************/
+
+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)
+{
+ HRESULT res;
+ IDirect3DDevice9 *pd3dDevice;
+ jfloat denom, inv_denom;
+ jfloat params[4];
+ jboolean large = (numStops > MAX_FRACTIONS_SMALL);
+ jint flags = 0;
+
+ J2dTraceLn(J2D_TRACE_INFO, "D3DPaints_SetRadialGradientPaint");
+
+ RETURN_STATUS_IF_NULL(d3dc, E_FAIL);
+ RETURN_STATUS_IF_NULL(dstOps, E_FAIL);
+ D3DPaints_ResetPaint(d3dc);
+
+ COMPOSE_FLAGS(flags, cycleMethod, large, useMask, linear);
+
+ // locate/enable the shader program for the given flags
+ res = d3dc->EnableRadialGradientProgram(flags);
+ RETURN_STATUS_IF_FAILED(res);
+
+ // update the common "uniform" values (fractions and colors)
+ D3DPaints_SetMultiGradientPaint(d3dc, useMask,
+ numStops, fractions, pixels);
+
+ // update the other "uniform" values
+ params[0] = m00;
+ params[1] = m01;
+ params[2] = m02;
+ params[3] = 0.0f; // unused
+ pd3dDevice = d3dc->Get3DDevice();
+ pd3dDevice->SetPixelShaderConstantF(16, params, 1);
+
+ params[0] = m10;
+ params[1] = m11;
+ params[2] = m12;
+ params[3] = 0.0f; // unused
+ pd3dDevice->SetPixelShaderConstantF(17, params, 1);
+
+ // pack a few unrelated, precalculated values into a single float4
+ denom = 1.0f - (focusX * focusX);
+ inv_denom = 1.0f / denom;
+ params[0] = focusX;
+ params[1] = denom;
+ params[2] = inv_denom;
+ params[3] = 0.0f; // unused
+ res = pd3dDevice->SetPixelShaderConstantF(18, params, 1);
+
+ // pixel state has been set appropriately in D3DPaints_ResetPaint()
+ d3dc->useMask = useMask;
+ d3dc->SetPaintState(PAINT_RAD_GRADIENT);
+ return res;
+}