Stefan Dösinger : wined3d: Light parameter fixes.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Feb 21 06:00:59 CST 2007


Module: wine
Branch: master
Commit: 76b7cac7af4a7da1505a831890397b2d9dc94ea8
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=76b7cac7af4a7da1505a831890397b2d9dc94ea8

Author: Stefan Dösinger <stefan at codeweavers.com>
Date:   Tue Feb 20 22:43:13 2007 +0100

wined3d: Light parameter fixes.

---

 dlls/ddraw/tests/d3d.c |   59 ++++++++++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/device.c  |   31 +++++++++++++++++++++++++
 dlls/wined3d/state.c   |   29 ++++++++++++++++-------
 3 files changed, 110 insertions(+), 9 deletions(-)

diff --git a/dlls/ddraw/tests/d3d.c b/dlls/ddraw/tests/d3d.c
index bb37f08..1125875 100644
--- a/dlls/ddraw/tests/d3d.c
+++ b/dlls/ddraw/tests/d3d.c
@@ -218,6 +218,65 @@ static void LightTest(void)
     /* Light 23 has not been set */
     rc = IDirect3DDevice7_GetLightEnable(lpD3DDevice, 23, &bEnabled );
     ok(rc==DDERR_INVALIDPARAMS, "GetLightEnable returned: %x\n", rc);
+
+    /* Set some lights with invalid parameters */
+    memset(&light, 0, sizeof(D3DLIGHT7));
+    light.dltType = 0;
+    U1(light.dcvDiffuse).r = 1.f;
+    U2(light.dcvDiffuse).g = 1.f;
+    U3(light.dcvDiffuse).b = 1.f;
+    U3(light.dvDirection).z = 1.f;
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 100, &light);
+    ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
+
+    memset(&light, 0, sizeof(D3DLIGHT7));
+    light.dltType = 12345;
+    U1(light.dcvDiffuse).r = 1.f;
+    U2(light.dcvDiffuse).g = 1.f;
+    U3(light.dcvDiffuse).b = 1.f;
+    U3(light.dvDirection).z = 1.f;
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 101, &light);
+    ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
+
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 102, NULL);
+    ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
+
+    memset(&light, 0, sizeof(D3DLIGHT7));
+    light.dltType = D3DLIGHT_SPOT;
+    U1(light.dcvDiffuse).r = 1.f;
+    U2(light.dcvDiffuse).g = 1.f;
+    U3(light.dcvDiffuse).b = 1.f;
+    U3(light.dvDirection).z = 1.f;
+
+    U3(light.dvAttenuation0) = -1.0 / 0.0; /* -INFINITY */
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
+    ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
+
+    U3(light.dvAttenuation0) = -1.0;
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
+    ok(rc==DDERR_INVALIDPARAMS, "SetLight returned: %x\n", rc);
+
+    U3(light.dvAttenuation0) = 0.0;
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
+    ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
+
+    U3(light.dvAttenuation0) = 1.0;
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
+    ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
+
+    U3(light.dvAttenuation0) = 1.0 / 0.0; /* +INFINITY */
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
+    ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
+
+    U3(light.dvAttenuation0) = 0.0 / 0.0; /* NaN */
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
+    ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
+
+    /* Directional light ignores attenuation */
+    light.dltType = D3DLIGHT_DIRECTIONAL;
+    U3(light.dvAttenuation0) = -1.0;
+    rc = IDirect3DDevice7_SetLight(lpD3DDevice, 103, &light);
+    ok(rc==D3D_OK, "SetLight returned: %x\n", rc);
 }
 
 static void ProcessVerticesTest(void)
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index af0e96a..05b4852 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -2199,6 +2199,37 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD I
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
     TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
 
+    /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
+     * the gl driver.
+     */
+    if(!pLight) {
+        WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+
+    switch(pLight->Type) {
+        case WINED3DLIGHT_POINT:
+        case WINED3DLIGHT_SPOT:
+        case WINED3DLIGHT_PARALLELPOINT:
+        case WINED3DLIGHT_GLSPOT:
+            /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
+             * most wanted
+             */
+            if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
+                WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
+                return WINED3DERR_INVALIDCALL;
+            }
+            break;
+
+        case WINED3DLIGHT_DIRECTIONAL:
+            /* Ignores attenuation */
+            break;
+
+        default:
+        WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
+        return WINED3DERR_INVALIDCALL;
+    }
+
     LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
         object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
         if(object->OriginalIndex == Index) break;
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 1a73b57..2b76dff 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -2981,21 +2981,16 @@ static void light(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContex
         glLightfv(GL_LIGHT0 + Index, GL_AMBIENT, colRGBA);
         checkGLcall("glLightfv");
 
-        /* Attenuation - Are these right? guessing... */
-        glLightf(GL_LIGHT0 + Index, GL_CONSTANT_ATTENUATION,  lightInfo->OriginalParms.Attenuation0);
-        checkGLcall("glLightf");
-        glLightf(GL_LIGHT0 + Index, GL_LINEAR_ATTENUATION,    lightInfo->OriginalParms.Attenuation1);
-        checkGLcall("glLightf");
-
         if ((lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range) >= FLT_MIN) {
             quad_att = 1.4/(lightInfo->OriginalParms.Range *lightInfo->OriginalParms.Range);
         } else {
             quad_att = 0; /*  0 or  MAX?  (0 seems to be ok) */
         }
 
-        if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
-        glLightf(GL_LIGHT0 + Index, GL_QUADRATIC_ATTENUATION, quad_att);
-        checkGLcall("glLightf");
+        /* Do not assign attenuation values for lights that do not use them. D3D apps are free to pass any junk,
+         * but gl drivers use them and may crash due to bad Attenuation values. Need for Speed most wanted sets
+         * Attenuation0 to NaN and crashes in the gl lib
+         */
 
         switch (lightInfo->OriginalParms.Type) {
             case WINED3DLIGHT_POINT:
@@ -3004,6 +2999,14 @@ static void light(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContex
                 checkGLcall("glLightfv");
                 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
                 checkGLcall("glLightf");
+                /* Attenuation - Are these right? guessing... */
+                glLightf(GL_LIGHT0 + Index, GL_CONSTANT_ATTENUATION,  lightInfo->OriginalParms.Attenuation0);
+                checkGLcall("glLightf");
+                glLightf(GL_LIGHT0 + Index, GL_LINEAR_ATTENUATION,    lightInfo->OriginalParms.Attenuation1);
+                checkGLcall("glLightf");
+                if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
+                glLightf(GL_LIGHT0 + Index, GL_QUADRATIC_ATTENUATION, quad_att);
+                checkGLcall("glLightf");
                 /* FIXME: Range */
                 break;
 
@@ -3018,6 +3021,14 @@ static void light(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContex
                 checkGLcall("glLightf");
                 glLightf(GL_LIGHT0 + Index, GL_SPOT_CUTOFF, lightInfo->cutoff);
                 checkGLcall("glLightf");
+                /* Attenuation - Are these right? guessing... */
+                glLightf(GL_LIGHT0 + Index, GL_CONSTANT_ATTENUATION,  lightInfo->OriginalParms.Attenuation0);
+                checkGLcall("glLightf");
+                glLightf(GL_LIGHT0 + Index, GL_LINEAR_ATTENUATION,    lightInfo->OriginalParms.Attenuation1);
+                checkGLcall("glLightf");
+                if (quad_att < lightInfo->OriginalParms.Attenuation2) quad_att = lightInfo->OriginalParms.Attenuation2;
+                glLightf(GL_LIGHT0 + Index, GL_QUADRATIC_ATTENUATION, quad_att);
+                checkGLcall("glLightf");
                 /* FIXME: Range */
                 break;
 




More information about the wine-cvs mailing list