summaryrefslogtreecommitdiff
path: root/src/code/z_rcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/code/z_rcp.c')
-rw-r--r--src/code/z_rcp.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/src/code/z_rcp.c b/src/code/z_rcp.c
index 135ffa887..657bd9e56 100644
--- a/src/code/z_rcp.c
+++ b/src/code/z_rcp.c
@@ -854,28 +854,50 @@ Gfx gEmptyDL[] = {
gsSPEndDisplayList(),
};
+/**
+ * Set fog color and range.
+ *
+ * At or prior to fog near, geometry is unaffected by fog. At or beyond fog far, geometry is fully fogged.
+ * Between near and far, rendered geometry will be blended between the unfogged color and the supplied fog color.
+ *
+ * Fog far should be in the range 0 to 1000 and greater than or equal to fog near. If fog near is negative everything
+ * will be fully fogged. If fog near is 1000 or greater there is no fog.
+ */
Gfx* Gfx_SetFog(Gfx* gfx, s32 r, s32 g, s32 b, s32 a, s32 near, s32 far) {
+ // Avoid 0 divisor in gSPFogPosition below
if (far == near) {
far++;
}
-
ASSERT(near != far, "n != f", "../z_rcp.c", 1155);
+ // Set the fog color, far away geometry will be rendered as this solid color.
gDPSetFogColor(gfx++, r, g, b, a);
if (near >= 1000) {
+ // Set a constant shade alpha of 0 for no fog
gSPFogFactor(gfx++, 0, 0);
- } else if (near >= 997) {
- gSPFogFactor(gfx++, 0x7FFF, 0x8100);
+ } else if (near > 996) {
+ // Avoid an overflow when near and far are close (see bug below), by effectively clamping near to ~996.
+ // This is almost SPFogPosition(996.0937f, 1000)
+ gSPFogFactor(gfx++, 0x7FFF, -0x7F00);
} else if (near < 0) {
+ // Set a constant shade alpha of 255 for fully fogged
gSPFogFactor(gfx++, 0, 255);
} else {
+ // Normal range. Shade alpha is 0 at z <= near and 255 at z >= far, linearly interpolated in between.
+ //! @bug If far - near < 4, the computed `fm` fog factor coefficient will overflow.
+ //! For example: 128000 / (983 - 980) > 32767
+ //! This is handled above in the case of near > 996, but the general case is not accounted for.
gSPFogPosition(gfx++, near, far);
}
-
return gfx;
}
+/**
+ * Like Gfx_SetFog but issues a pipesync before changing fog color.
+ *
+ * @see Gfx_SetFog
+ */
Gfx* Gfx_SetFogWithSync(Gfx* gfx, s32 r, s32 g, s32 b, s32 a, s32 near, s32 far) {
if (far == near) {
far++;
@@ -898,6 +920,11 @@ Gfx* Gfx_SetFogWithSync(Gfx* gfx, s32 r, s32 g, s32 b, s32 a, s32 near, s32 far)
return gfx;
}
+/**
+ * Wrapper for Gfx_SetFog
+ *
+ * @see Gfx_SetFog
+ */
Gfx* Gfx_SetFog2(Gfx* gfx, s32 r, s32 g, s32 b, s32 a, s32 near, s32 far) {
return Gfx_SetFog(gfx, r, g, b, a, near, far);
}