diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 1f871c682..66889d923 100755 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -550,19 +550,28 @@ void main()\n\ \n\ if (polyEnableFog)\n\ {\n\ + float fogMixWeight = 0.0;\n\ int inFragDepthi = int( (inFragDepth * 32767.0) + 0.5 );\n\ - int diffi = inFragDepthi - FOG_OFFSET + (FOG_STEP - 1);\n\ \n\ - float interp = 1.0;\n\ - if ( (inFragDepth > FOG_DEPTH_COMPARE_0) && (inFragDepth < FOG_DEPTH_COMPARE_31) )\n\ + if (FOG_STEP == 0)\n\ {\n\ - interp = float( (diffi & FOG_WEIGHT_TRUNCATE_MASK) + FOG_OFFSET - inFragDepthi ) / float(FOG_STEP);\n\ + fogMixWeight = (inFragDepthi <= FOG_OFFSET) ? state.fogDensity[0].r : state.fogDensity[31].r;\n\ + }\n\ + else\n\ + {\n\ + int diffi = inFragDepthi - FOG_OFFSET + (FOG_STEP - 1);\n\ + \n\ + float interp = 1.0;\n\ + if ( (inFragDepth > FOG_DEPTH_COMPARE_0) && (inFragDepth < FOG_DEPTH_COMPARE_31) )\n\ + {\n\ + interp = float( (diffi & FOG_WEIGHT_TRUNCATE_MASK) + FOG_OFFSET - inFragDepthi ) / float(FOG_STEP);\n\ + }\n\ + \n\ + int idx = (diffi >> FOG_SHIFT_INV) - 1;\n\ + idx = (idx < 1) ? 0 : (idx > 31) ? 31 : idx;\n\ + \n\ + fogMixWeight = mix(state.fogDensity[idx].r, state.fogDensity[idx].g, interp);\n\ }\n\ - \n\ - int idx = (diffi >> FOG_SHIFT_INV) - 1;\n\ - idx = (idx < 1) ? 0 : (idx > 31) ? 31 : idx;\n\ - \n\ - float fogMixWeight = mix(state.fogDensity[idx].r, state.fogDensity[idx].g, interp);\n\ \n\ #if USE_DUAL_SOURCE_BLENDING\n\ outFogWeight = (state.enableFogAlphaOnly) ? vec4(vec3(0.0), fogMixWeight) : vec4(fogMixWeight);\n\ @@ -1549,8 +1558,8 @@ Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogPro const u32 fogOffset = fogProgramKey.offset; const u32 fogStep = (0x0400 >> fogProgramKey.shift); - const u32 fogShiftInv = 10 - fogProgramKey.shift; - const u32 fogWeightTruncateMask = ~(fogStep - 1); + const u32 fogShiftInv = 10 - fogProgramKey.shift; // Rolls over if fogStep is 0 (do not use in this case) + const u32 fogWeightTruncateMask = ~(fogStep - 1); // Rolls over if fogStep is 0 (do not use in this case) const GLfloat fogDepthCompare0 = std::min((GLfloat)(fogOffset + (fogStep * 1)) / 32767.0f, 1.0f); const GLfloat fogDepthCompare31 = std::min((GLfloat)(fogOffset + (fogStep * 32)) / 32767.0f, 1.0f); diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index 019b41063..73afd688d 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -3093,11 +3093,12 @@ void gfx3d_parseCurrentDISP3DCNT() gfx3d.state.enableEdgeMarking = (DISP3DCNT.EnableEdgeMarking != 0); gfx3d.state.enableFogAlphaOnly = (DISP3DCNT.FogOnlyAlpha != 0); gfx3d.state.enableFog = (DISP3DCNT.EnableFog != 0); - gfx3d.state.fogShift = (DISP3DCNT.FogShiftSHR <= 10) ? DISP3DCNT.FogShiftSHR : 11; // According to GBATEK, values higher than 10 force FogStep (0x400 >> FogShiftSHR) to become 0. So set FogShiftSHR to 11 in this case. - // TODO: Handle divide-by-zero cases of FogShiftSHR in SoftRasterizer and OpenGL. - // The fog weight is calculated using FogShiftSHR. However, if FogShiftSHR == 0, then this calculation can become a problem. - // We'll need to deal with the zero case at some point in the future. gfx3d.state.enableClearImage = (DISP3DCNT.RearPlaneMode != 0); + + // According to GBATEK, values greater than 10 force FogStep (0x400 >> FogShiftSHR) to become 0. + // So set FogShiftSHR to 11 in this case so that calculations using (0x400 >> FogShiftSHR) will + // equal 0. + gfx3d.state.fogShift = (DISP3DCNT.FogShiftSHR <= 10) ? DISP3DCNT.FogShiftSHR : 11; } void ParseReg_DISP3DCNT() diff --git a/desmume/src/rasterize.cpp b/desmume/src/rasterize.cpp index 69dda083b..54af31961 100644 --- a/desmume/src/rasterize.cpp +++ b/desmume/src/rasterize.cpp @@ -2114,9 +2114,25 @@ void SoftRasterizerRenderer::_UpdateEdgeMarkColorTable(const u16 *edgeMarkColorT void SoftRasterizerRenderer::_UpdateFogTable(const u8 *fogDensityTable) { - const s32 fogStep = 0x400 >> this->currentRenderState->fogShift; - const s32 fogShiftInv = 10 - this->currentRenderState->fogShift; const s32 fogOffset = min( max((s32)this->currentRenderState->fogOffset, 0), 32768 ); + const s32 fogStep = 0x400 >> this->currentRenderState->fogShift; + + if (fogStep <= 0) + { + const s32 iMin = min( max(fogOffset, 0), 32768); + const s32 iMax = min( max(fogOffset + 1, 0), 32768); + + // If the fog factor is 127, then treat it as 128. + u8 fogWeight = (fogDensityTable[0] >= 127) ? 128 : fogDensityTable[0]; + memset(this->_fogTable, fogWeight, iMin); + + fogWeight = (fogDensityTable[31] >= 127) ? 128 : fogDensityTable[31]; + memset(this->_fogTable+iMax, fogWeight, 32768-iMax); + + return; + } + + const s32 fogShiftInv = 10 - this->currentRenderState->fogShift; const s32 iMin = min( max((( 1 + 1) << fogShiftInv) + fogOffset + 1 - fogStep, 0), 32768); const s32 iMax = min( max(((32 + 1) << fogShiftInv) + fogOffset + 1 - fogStep, 0), 32768); assert(iMin <= iMax);