From nobody Mon Sep 17 00:00:00 2001 From: Stefan Dösinger Date: Sun Jun 11 17:58:05 2006 +0200 Subject: [PATCH] WineD3D: Fog fixes --- dlls/wined3d/device.c | 137 ++++++++++++++++++++++++++++++++++----------- dlls/wined3d/drawprim.c | 58 +++++++++++++++++++ include/wine/wined3d_gl.h | 11 ++++ 3 files changed, 172 insertions(+), 34 deletions(-) 3e6bc2ef9c7b54e09f46b3c01f9c1249afaf3c22 diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index a0b0522..8fb2d58 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -3767,7 +3767,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl case WINED3DRS_FOGENABLE : { - if (Value/* && This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] != D3DFOG_NONE*/) { + if (Value) { glEnable(GL_FOG); checkGLcall("glEnable GL_FOG"); } else { @@ -3798,45 +3798,116 @@ static HRESULT WINAPI IWineD3DDeviceImpl break; case WINED3DRS_FOGTABLEMODE : - { - glHint(GL_FOG_HINT, GL_NICEST); - switch (Value) { - case D3DFOG_NONE: { - if(This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == D3DFOG_NONE) { - glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); - } - /* Otherwise leave the vertex fog value */ - break; - } - case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; - case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); break; - case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); break; - default: - FIXME("Unsupported Value(%lu) for WINED3DRS_FOGTABLEMODE!\n", Value); - } - if (GL_SUPPORT(NV_FOG_DISTANCE)) { - glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV); - } - } - break; - case WINED3DRS_FOGVERTEXMODE : { - glHint(GL_FOG_HINT, GL_FASTEST); /* DX 7 sdk: "If both render states(vertex and table fog) are set to valid modes, the system will apply only pixel(=table) fog effects." */ if(This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) { - switch (Value) { - case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); break; - case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); break; - case D3DFOG_NONE: - case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); break; - default: - FIXME("Unsupported Value(%lu) for WINED3DRS_FOGTABLEMODE!\n", Value); + glHint(GL_FOG_HINT, GL_FASTEST); + checkGLcall("glHint(GL_FOG_HINT, GL_FASTEST)"); + switch (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]) { + /* Processed vertices have their fog factor stored in the specular value. Fall too the none case. + * If we are drawing untransformed vertices atm, d3ddevice_set_ortho will update the fog + */ + case D3DFOG_EXP: { + if(!This->last_was_rhw) { + glFogi(GL_FOG_MODE, GL_EXP); + checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH); + checkGLcall("glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH"); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]); + } + break; + } + } + case D3DFOG_EXP2: { + if(!This->last_was_rhw) { + glFogi(GL_FOG_MODE, GL_EXP2); + checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH); + checkGLcall("glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH"); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]); + } + break; + } + } + case D3DFOG_LINEAR: { + if(!This->last_was_rhw) { + glFogi(GL_FOG_MODE, GL_LINEAR); + checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH); + checkGLcall("glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH"); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]); + } + break; + } + } + case D3DFOG_NONE: { + /* Both are none? According to msdn the alpha channel of the specular + * color contains a fog factor. Set it in drawStridedSlow. + * Same happens with Vertexfog on transformed vertices + */ + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORD_SRC, GL_FOG_COORD); + checkGLcall("glFogi(GL_FOG_COORD_SRC, GL_FOG_COORD)\n"); + glFogi(GL_FOG_MODE, GL_LINEAR); + checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)"); + glFogf(GL_FOG_START, (float) 0xff); + checkGLcall("glFogfv GL_FOG_START"); + glFogf(GL_FOG_END, 0.0); + checkGLcall("glFogfv GL_FOG_END"); + } else { + /* Disable GL fog, handle this in software in drawStridedSlow */ + glDisable(GL_FOG); + checkGLcall("glDisable(GL_FOG)"); + } + break; + } + default: FIXME("Unexpected WINED3DRS_FOGVERTEXMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE]); } - if (GL_SUPPORT(NV_FOG_DISTANCE)) { - glFogi(GL_FOG_DISTANCE_MODE_NV, This->stateBlock->renderState[WINED3DRS_RANGEFOGENABLE] ? GL_EYE_RADIAL_NV : GL_EYE_PLANE_ABSOLUTE_NV); + } else { + glHint(GL_FOG_HINT, GL_NICEST); + checkGLcall("glHint(GL_FOG_HINT, GL_NICEST)"); + switch (This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]) { + case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); + checkGLcall("glFogi(GL_FOG_MODE, GL_EXP"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH); + checkGLcall("glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH"); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]); + } + break; + case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); + checkGLcall("glFogi(GL_FOG_MODE, GL_EXP2"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH); + checkGLcall("glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH"); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]); + } + break; + case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); + checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR"); + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH); + checkGLcall("glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH"); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]); + } + break; + case D3DFOG_NONE: /* Won't happen */ + default: FIXME("Unexpected WINED3DRS_FOGTABLEMODE %ld\n", This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]); } } + if (GL_SUPPORT(NV_FOG_DISTANCE)) { + glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_PLANE_ABSOLUTE_NV); + } } break; diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 0164339..6989c10 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -218,8 +218,30 @@ void d3ddevice_set_ortho(IWineD3DDeviceI glMultMatrixf(invymat); checkGLcall("glMultMatrixf(invymat)"); } - } + /* Vertex fog on transformed vertices? Use the calculated fog factor stored in the specular color */ + if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) { + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORD_SRC, GL_FOG_COORD); + checkGLcall("glFogi(GL_FOG_COORD_SRC, GL_FOG_COORD)"); + glFogi(GL_FOG_MODE, GL_LINEAR); + checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)"); + /* The dx fog range in this case is fixed to 0 - 255, + * but in GL it still depends on the fog start and end (according to the ext) + * Use this to turn around the fog as it's needed. That prevents some + * calculations during drawing :-) + */ + glFogf(GL_FOG_START, (float) 0xff); + checkGLcall("glFogfv GL_FOG_END"); + glFogf(GL_FOG_END, 0.0); + checkGLcall("glFogfv GL_FOG_START"); + } else { + /* Disable GL fog, handle this in software in drawStridedSlow */ + glDisable(GL_FOG); + checkGLcall("glDisable(GL_FOG)"); + } + } + } } /* Setup views - Transformed & lit if RHW, else untransformed. Only unlit if Normals are supplied @@ -240,6 +262,7 @@ static BOOL primitiveInitState(IWineD3DD if (!useVS && vtx_transformed) { d3ddevice_set_ortho(This); + } else { /* Untransformed, so relies on the view and projection matrices */ @@ -311,6 +334,23 @@ static BOOL primitiveInitState(IWineD3DD This->proj_valid = FALSE; } This->last_was_rhw = FALSE; + + /* Restore fogging */ + if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] != D3DFOG_NONE) { + if(GL_SUPPORT(EXT_FOG_COORD)) { + glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH); + checkGLcall("glFogi(GL_FOG_COORD_SRC, GL_FRAGMENT_DEPTH)\n"); + /* Reapply the fog range */ + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGSTART, This->stateBlock->renderState[WINED3DRS_FOGSTART]); + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGEND, This->stateBlock->renderState[WINED3DRS_FOGEND]); + /* Restore the fog mode */ + IWineD3DDevice_SetRenderState(iface, WINED3DRS_FOGTABLEMODE, This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE]); + } else { + /* Enable GL_FOG again because we disabled it above */ + glEnable(GL_FOG); + checkGLcall("glEnable(GL_FOG)"); + } + } } return isLightingOn; } @@ -1495,6 +1535,22 @@ static void drawStridedSlow(IWineD3DDevi /* Specular ------------------------------- */ if (sd->u.s.specular.lpData != NULL) { + /* special case where the fog density is stored in the diffuse alpha channel */ + if(This->stateBlock->renderState[WINED3DRS_FOGENABLE] && + (This->stateBlock->renderState[WINED3DRS_FOGVERTEXMODE] == D3DFOG_NONE || sd->u.s.position.dwType == D3DDECLTYPE_FLOAT4 )&& + This->stateBlock->renderState[WINED3DRS_FOGTABLEMODE] == D3DFOG_NONE) { + if(GL_SUPPORT(EXT_FOG_COORD)) { + GL_EXTCALL(glFogCoordfEXT(specularColor >> 24)); + } else { + BOOL warned = FALSE; + if(!warned) { + /* TODO: Use the fog table code from old ddraw */ + FIXME("Implement fog for transformed vertices in software\n"); + warned = TRUE; + } + } + } + VTRACE(("glSecondaryColor4ub: r,g,b=%lu,%lu,%lu\n", D3DCOLOR_B_R(specularColor), D3DCOLOR_B_G(specularColor), diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h index 50717fc..a865760 100644 --- a/include/wine/wined3d_gl.h +++ b/include/wine/wined3d_gl.h @@ -646,6 +646,12 @@ typedef GLvoid* (APIENTRY * PGLFNMAPBUFF typedef GLboolean (APIENTRY * PGLFNUNMAPBUFFERARBPROC) (GLenum target); typedef void (APIENTRY * PGLFNGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint *params); typedef void (APIENTRY * PGLFNGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid* *params); +/* GL_EXT_fog_coord */ +typedef void (APIENTRY * PGLFNGLFOGCOORDFEXTPROC) (GLfloat intesity); +typedef void (APIENTRY * PGLFNGLFOGCOORDFVEXTPROC) (GLfloat intesity); +typedef void (APIENTRY * PGLFNGLFOGCOORDDEXTPROC) (GLfloat intesity); +typedef void (APIENTRY * PGLFNGLFOGCOORDDVEXTPROC) (GLfloat intesity); +typedef void (APIENTRY * PGLFNGLFOGCOORDPOINTEREXTPROC) (GLenum type, GLsizei stride, GLvoid *data); /* GL_ARB_shader_objects (GLSL) */ #ifndef GL_ARB_shader_objects #define GL_ARB_shader_objects 1 @@ -1424,6 +1430,11 @@ typedef enum _GL_SupportedExt { USE_GL_FUNC(PGLFNGETBUFFERPOINTERVARBPROC, glGetBufferPointervARB); \ /** EXT Extensions **/ \ /* GL_EXT_fog_coord */ \ + USE_GL_FUNC(PGLFNGLFOGCOORDFEXTPROC, glFogCoordfEXT); \ + USE_GL_FUNC(PGLFNGLFOGCOORDFVEXTPROC, glFogCoordfvEXT); \ + USE_GL_FUNC(PGLFNGLFOGCOORDDEXTPROC, glFogCoorddEXT); \ + USE_GL_FUNC(PGLFNGLFOGCOORDDVEXTPROC, glFogCoordvEXT); \ + USE_GL_FUNC(PGLFNGLFOGCOORDPOINTEREXTPROC, glFogCoordPointerEXT); \ /* GL_EXT_framebuffer_object */ \ USE_GL_FUNC(PGLFNGLISRENDERBUFFEREXTPROC, glIsRenderbufferEXT); \ USE_GL_FUNC(PGLFNGLBINDRENDERBUFFEREXTPROC, glBindRenderbufferEXT); \ -- 1.2.4