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