Hi all, This adds fogging for transformed vertices... In this mode we need to handle the 'fogging' in software mode. I choose the 'fog table' way to prevent computing the fog formula on each vertex. I have no idea if this is really faster (ie if it is faster to do '(a * b + (1 - a) * c) / 0xFF' on each vertex or to get data from a 0x30000 array that may be out of the cache). Note for Christian : I know that Exp and Exp2 formulas seem not to be supported in DX6 (did not check DX7) but well, I preferred factorizing the code :-) Changelog: Added fogging for transformed vertices -- Lionel Ulmer - http://www.bbrox.org/
--- ../wine_base/dlls/ddraw/mesa_private.h Thu Jan 30 22:07:23 2003 +++ dlls/ddraw/mesa_private.h Sun Feb 2 00:53:52 2003 @@ -104,6 +104,11 @@ /* The last type of vertex drawn */ GL_TRANSFORM_STATE transform_state; + /* Used to handle fogging faster... */ + BYTE fog_table[3 * 0x10000]; /* 3 is for R, G and B + 0x10000 is 0xFF for the vertex color and + 0xFF for the fog intensity */ + Display *display; Drawable drawable; } IDirect3DDeviceGLImpl; --- ../wine_base/dlls/ddraw/d3ddevice/mesa.c Sat Feb 1 10:12:21 2003 +++ dlls/ddraw/d3ddevice/mesa.c Sun Feb 2 12:36:57 2003 @@ -689,6 +689,23 @@ return (d*Zproj - c) / (a - b*Zproj); } +static void build_fog_table(BYTE *fog_table, DWORD fog_color) { + int i; + + TRACE(" rebuilding fog table (%06lx)...\n", fog_color & 0x00FFFFFF); + + for (i = 0; i < 3; i++) { + BYTE fog_color_component = (fog_color >> (8 * i)) & 0xFF; + DWORD elt; + for (elt = 0; elt < 0x10000; elt++) { + /* We apply the fog transformation and cache the result */ + DWORD fog_intensity = elt & 0xFF; + DWORD vertex_color = (elt >> 8) & 0xFF; + fog_table[(i * 0x10000) + elt] = ((fog_intensity * vertex_color) + ((0xFF - fog_intensity) * fog_color_component)) / 0xFF; + } + } +} + static void draw_primitive_handle_GL_state(IDirect3DDeviceImpl *This, BOOLEAN vertex_transformed, BOOLEAN vertex_lit) { @@ -710,29 +727,44 @@ glThis->transform_state = GL_TRANSFORM_ORTHO; d3ddevice_set_ortho(This); } + + /* TODO: optimize this to not always reset all the fog stuff on all DrawPrimitive call + if no fogging state change occured */ if (This->state_block.render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) { - if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) { - switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) { - case D3DFOG_LINEAR: glFogi(GL_FOG_MODE,GL_LINEAR); break; - case D3DFOG_EXP: glFogi(GL_FOG_MODE,GL_EXP); break; - case D3DFOG_EXP2: glFogi(GL_FOG_MODE,GL_EXP2); break; - } - glFogf(GL_FOG_START,ZfromZproj(This,*(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1])); - glFogf(GL_FOG_END,ZfromZproj(This,*(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1])); - glEnable(GL_FOG); - } else if ( (This->state_block.render_state[D3DRENDERSTATE_FOGVERTEXMODE - 1] != D3DFOG_NONE) && - (vertex_lit == FALSE) && (vertex_transformed == FALSE) ) { - /* D3DFOG_EXP and D3DFOG_EXP2 are treated as D3DFOG_LINEAR */ - glFogi(GL_FOG_MODE,GL_LINEAR); - glFogf(GL_FOG_START,*(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]); - glFogf(GL_FOG_END,*(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]); - glEnable(GL_FOG); - } else - glDisable(GL_FOG); - } - else + if (vertex_transformed == TRUE) { + glDisable(GL_FOG); + /* Now check if our fog_table still corresponds to the current vertex color. + Element '0x..00' is always the fog color as it corresponds to maximum fog intensity */ + if ((glThis->fog_table[0 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 0) & 0xFF)) || + (glThis->fog_table[1 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 8) & 0xFF)) || + (glThis->fog_table[2 * 0x10000 + 0x0000] != ((This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1] >> 16) & 0xFF))) { + /* We need to rebuild our fog table.... */ + build_fog_table(glThis->fog_table, This->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]); + } + } else { + if (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1] != D3DFOG_NONE) { + switch (This->state_block.render_state[D3DRENDERSTATE_FOGTABLEMODE - 1]) { + case D3DFOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); break; + case D3DFOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); break; + case D3DFOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); break; + } + if (vertex_lit == FALSE) { + glFogf(GL_FOG_START, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1]); + glFogf(GL_FOG_END, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1]); + } else { + /* Special case of 'pixel fog' */ + glFogf(GL_FOG_START, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGSTART - 1])); + glFogf(GL_FOG_END, ZfromZproj(This, *(float*)&This->state_block.render_state[D3DRENDERSTATE_FOGEND - 1])); + } + glEnable(GL_FOG); + } else { + glDisable(GL_FOG); + } + } + } else { glDisable(GL_FOG); - + } + /* Handle the 'no-normal' case */ if ((vertex_lit == FALSE) && (This->state_block.render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE)) glEnable(GL_LIGHTING); @@ -950,15 +982,21 @@ /* No else here as we do not know how to handle 'specular' on its own in any case.. */ } -inline static void handle_diffuse_and_specular(STATEBLOCK *sb, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) { +inline static void handle_diffuse_and_specular(STATEBLOCK *sb, BYTE *fog_table, DWORD *color_d, DWORD *color_s, BOOLEAN lighted) { if (lighted == TRUE) { + DWORD color = *color_d; if (sb->render_state[D3DRENDERSTATE_FOGENABLE - 1] == TRUE) { - /* Special case where the specular value is used to do fogging. TODO */ + /* Special case where the specular value is used to do fogging */ + BYTE fog_intensity = *color_s >> 24; /* The alpha value of the specular component is the fog 'intensity' for this vertex */ + color &= 0xFF000000; /* Only keep the alpha component */ + color |= fog_table[((*color_d >> 0) & 0xFF) << 8 | fog_intensity] << 0; + color |= fog_table[((*color_d >> 8) & 0xFF) << 8 | fog_intensity] << 8; + color |= fog_table[((*color_d >> 16) & 0xFF) << 8 | fog_intensity] << 16; } if (sb->render_state[D3DRENDERSTATE_SPECULARENABLE - 1] == TRUE) { /* Standard specular value in transformed mode. TODO */ } - handle_diffuse_base(sb, color_d); + handle_diffuse_base(sb, &color); } else { if (sb->render_state[D3DRENDERSTATE_LIGHTING - 1] == TRUE) { handle_diffuse(sb, color_d, FALSE); @@ -989,7 +1027,8 @@ DWORD dwFlags) { BOOLEAN vertex_lighted = (d3dvtVertexType & D3DFVF_NORMAL) == 0; - + IDirect3DDeviceGLImpl* glThis = (IDirect3DDeviceGLImpl*) This; + if (TRACE_ON(ddraw)) { TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType); } @@ -1036,7 +1075,7 @@ D3DVALUE *position = (D3DVALUE *) (((char *) lpD3DDrawPrimStrideData->position.lpvData) + i * lpD3DDrawPrimStrideData->position.dwStride); - handle_diffuse_and_specular(&(This->state_block), color_d, color_s, TRUE); + handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, TRUE); handle_texture(tex_coord); handle_xyzrhw(position); @@ -1071,7 +1110,7 @@ (DWORD *) (((char *) lpD3DDrawPrimStrideData->diffuse.lpvData) + i * lpD3DDrawPrimStrideData->diffuse.dwStride); DWORD *color_s = (DWORD *) (((char *) lpD3DDrawPrimStrideData->specular.lpvData) + i * lpD3DDrawPrimStrideData->specular.dwStride); - handle_diffuse_and_specular(&(This->state_block), color_d, color_s, vertex_lighted); + handle_diffuse_and_specular(&(This->state_block), glThis->fog_table, color_d, color_s, vertex_lighted); } else { if (d3dvtVertexType & D3DFVF_SPECULAR) { DWORD *color_s = @@ -2294,5 +2333,8 @@ apply_render_state(object, &object->state_block); /* FIXME: do something similar for ligh_state and texture_stage_state */ + /* And fill the fog table with the default fog value */ + build_fog_table(gl_object->fog_table, object->state_block.render_state[D3DRENDERSTATE_FOGCOLOR - 1]); + return DD_OK; }