diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 8e5c46e39b390161d06511d1f7324632718fe0ba..a5fae4fadabe64315d802d5d9490f4707c5da3e8 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -292,6 +292,9 @@ static FUINT HWR_CalcWallLight(FUINT lightnum, seg_t *seg)
 	if (seg != NULL && P_ApplyLightOffset(lightnum))
 	{
 		finallight += seg->hwLightOffset;
+
+		if (finallight > 255) finallight = 255;
+		if (finallight < 0) finallight = 0;
 	}
 
 	return (FUINT)finallight;
@@ -303,7 +306,10 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, pslope_t *slope)
 
 	if (slope != NULL && P_ApplyLightOffset(lightnum))
 	{
-		finallight += slope->lightOffset;
+		finallight += slope->hwLightOffset;
+
+		if (finallight > 255) finallight = 255;
+		if (finallight < 0) finallight = 0;
 	}
 
 	return (FUINT)finallight;
diff --git a/src/p_setup.c b/src/p_setup.c
index 80a2e51443d9d3ff865a55de3ea3851c0f734982..d82bcf6b8ea01f0bf8ef399a89e368f9d9b89801 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -413,7 +413,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 i)
 	mapheaderinfo[num]->menuflags = 0;
 	mapheaderinfo[num]->mobj_scale = FRACUNIT;
 	mapheaderinfo[num]->default_waypoint_radius = 0;
-	mapheaderinfo[num]->light_contrast = 0;
+	mapheaderinfo[num]->light_contrast = 16;
 	mapheaderinfo[num]->use_light_angle = false;
 	mapheaderinfo[num]->light_angle = 0;
 #if 1 // equivalent to "FlickyList = DEMO"
@@ -2326,12 +2326,24 @@ static inline float P_SegLengthFloat(seg_t *seg)
 void P_UpdateSegLightOffset(seg_t *li)
 {
 	const UINT8 contrast = maplighting.contrast;
+	const fixed_t contrastFixed = ((fixed_t)contrast) * FRACUNIT;
+	fixed_t light = FRACUNIT;
 	fixed_t extralight = 0;
 
-	extralight = -((fixed_t)contrast*FRACUNIT) +
-		FixedDiv(AngleFixed(R_PointToAngle2(0, 0,
-		abs(li->v1->x - li->v2->x),
-		abs(li->v1->y - li->v2->y))), 90*FRACUNIT) * ((fixed_t)contrast * 2);
+	if (maplighting.directional == true)
+	{
+		angle_t liAngle = R_PointToAngle2(0, 0, (li->v1->x - li->v2->x), (li->v1->y - li->v2->y)) - ANGLE_90;
+
+		light = FixedMul(FINECOSINE(liAngle >> ANGLETOFINESHIFT), FINECOSINE(maplighting.angle >> ANGLETOFINESHIFT))
+			+ FixedMul(FINESINE(liAngle >> ANGLETOFINESHIFT), FINESINE(maplighting.angle >> ANGLETOFINESHIFT));
+		light = (light + FRACUNIT) / 2;
+	}
+	else
+	{
+		light = FixedDiv(R_PointToAngle2(0, 0, abs(li->v1->x - li->v2->x), abs(li->v1->y - li->v2->y)), ANGLE_90);
+	}
+
+	extralight = -contrastFixed + FixedMul(light, contrastFixed * 2);
 
 	// Between -2 and 2 for software, -16 and 16 for hardware
 	li->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT;
diff --git a/src/p_slopes.c b/src/p_slopes.c
index e7ca22c2a3f76bab2e3fa6adc53549c530d91a7e..3ed61b2834080c710a1924f46e631af83efce3c4 100644
--- a/src/p_slopes.c
+++ b/src/p_slopes.c
@@ -34,32 +34,49 @@ static void P_SetupAnchoredSlopes  (void);
 // Calculate light
 void P_UpdateSlopeLightOffset(pslope_t *slope)
 {
-	const boolean ceiling = (slope->normal.z < 0);
 	const UINT8 contrast = maplighting.contrast;
 
-	fixed_t contrastFixed = (contrast * FRACUNIT);
+	fixed_t contrastFixed = ((fixed_t)contrast) * FRACUNIT;
 	fixed_t zMul = FRACUNIT;
-	angle_t slopeDir = ANGLE_MAX;
+	fixed_t light = FRACUNIT;
 	fixed_t extralight = 0;
 
 	if (slope->normal.z == 0)
 	{
-		slope->lightOffset = 0;
+		slope->lightOffset = slope->hwLightOffset = 0;
 		return;
 	}
 
-	slopeDir = R_PointToAngle2(0, 0, abs(slope->normal.y), abs(slope->normal.x));
-	if (ceiling == true)
+	if (maplighting.directional == true)
 	{
-		slopeDir ^= ANGLE_180;
+		fixed_t dX = slope->d.x;
+		fixed_t dY = slope->d.y;
+
+		if (slope->zdelta < 0)
+		{
+			dX = -dX;
+			dY = -dY;
+		}
+
+		light = FixedMul(dX, FINECOSINE(maplighting.angle >> ANGLETOFINESHIFT))
+			+ FixedMul(dY, FINESINE(maplighting.angle >> ANGLETOFINESHIFT));
+		light = (light + FRACUNIT) / 2;
+	}
+	else
+	{
+		light = FixedDiv(R_PointToAngle2(0, 0, abs(slope->d.x), abs(slope->d.y)), ANGLE_90);
 	}
 
 	zMul = min(FRACUNIT, abs(slope->zdelta)*3/2); // *3/2, to make 60 degree slopes match walls.
 	contrastFixed = FixedMul(contrastFixed, zMul);
-	extralight = -contrastFixed + FixedMul(FixedDiv(AngleFixed(slopeDir), 90*FRACUNIT), (contrastFixed * 2));
 
-	// -16 and 16 for both software & hardware
-	slope->lightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT;
+	extralight = -contrastFixed + FixedMul(light, contrastFixed * 2);
+
+	// Between -2 and 2 for software, -16 and 16 for hardware
+	slope->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT;
+#ifdef HWRENDER
+	slope->hwLightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT;
+#endif
 }
 
 // Calculate line normal
diff --git a/src/r_defs.h b/src/r_defs.h
index c749c3252c5b727c38e0919803bbb2886c1a4845..8be91fc9b70694092e365e342ab6140126f67a30 100644
--- a/src/r_defs.h
+++ b/src/r_defs.h
@@ -253,7 +253,10 @@ typedef struct pslope_s
 	fixed_t highz;
 
 	// Light offsets (see seg_t)
-	INT16 lightOffset;
+	SINT8 lightOffset;
+#ifdef HWRENDER
+	INT16 hwLightOffset;
+#endif
 } pslope_t;
 
 typedef enum
diff --git a/src/r_plane.c b/src/r_plane.c
index 7f58a373f05885339bbcc640d64363460237a394..9d127c7622a7d1d1a15f72c46560781dc1f2ed91 100644
--- a/src/r_plane.c
+++ b/src/r_plane.c
@@ -388,8 +388,7 @@ visplane_t *R_FindPlane(fixed_t height, INT32 picnum, INT32 lightlevel,
 
 	if (slope != NULL && P_ApplyLightOffset(lightlevel))
 	{
-		// for software: crunchitize the light level offset, otherwise it's too bright.
-		lightlevel += (slope->lightOffset / 8) * 8;
+		lightlevel += slope->lightOffset * 8;
 	}
 
 	// This appears to fix the Nimbus Ruins sky bug.