diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c
index 3abcef4a32daba37e2b0c253f654f11c692a94ab..4e651891de9fafaeca55cfd60dea1edb71bcd3ca 100644
--- a/src/hardware/hw_main.c
+++ b/src/hardware/hw_main.c
@@ -315,6 +315,7 @@ static FUINT HWR_SideLightLevel(side_t *side, UINT8 base_lightlevel)
 		((side->lightabsolute) ? 0 : base_lightlevel);
 }
 
+/* TODO: implement per-texture lighting
 static FUINT HWR_TopLightLevel(side_t *side, UINT8 base_lightlevel)
 {
 	return side->light_top +
@@ -332,6 +333,7 @@ static FUINT HWR_BottomLightLevel(side_t *side, UINT8 base_lightlevel)
 	return side->light_bottom +
 		((side->lightabsolute_bottom) ? 0 : HWR_SideLightLevel(side, base_lightlevel));
 }
+*/
 
 // ==========================================================================
 //                                   FLOOR/CEILING GENERATION FROM SUBSECTORS
diff --git a/src/lua_maplib.c b/src/lua_maplib.c
index 2afebadf4f38c09ac1e75648393e480e23c8055b..9985e5631201752eddf1ba2abc71aa7304da8f62 100644
--- a/src/lua_maplib.c
+++ b/src/lua_maplib.c
@@ -1454,16 +1454,16 @@ static int side_set(lua_State *L)
 		side->repeatcnt = luaL_checkinteger(L, 3);
 		break;
 	case side_light:
-		side->repeatcnt = luaL_checkinteger(L, 3);
+		side->light = luaL_checkinteger(L, 3);
 		break;
 	case side_light_top:
-		side->repeatcnt = luaL_checkinteger(L, 3);
+		side->light_top = luaL_checkinteger(L, 3);
 		break;
 	case side_light_mid:
-		side->repeatcnt = luaL_checkinteger(L, 3);
+		side->light_mid = luaL_checkinteger(L, 3);
 		break;
 	case side_light_bottom:
-		side->repeatcnt = luaL_checkinteger(L, 3);
+		side->light_bottom = luaL_checkinteger(L, 3);
 		break;
 	case side_lightabsolute:
 		side->lightabsolute = luaL_checkboolean(L, 3);
diff --git a/src/p_saveg.c b/src/p_saveg.c
index ab3552673b77ed86a3ee938741b44b738caae118..8e511e3505699f94933b79fc0ddf8148ee41a117 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1407,6 +1407,12 @@ static UINT32 GetSideDiff(const side_t *si, const side_t *spawnsi)
 		diff |= LD_SDBOTLIGHT;
 	if (si->lightabsolute != spawnsi->lightabsolute)
 		diff |= LD_SDLIGHTABS;
+	if (si->lightabsolute_top != spawnsi->lightabsolute_top)
+		diff |= LD_SDTOPLIGHTABS;
+	if (si->lightabsolute_mid != spawnsi->lightabsolute_mid)
+		diff |= LD_SDMIDLIGHTABS;
+	if (si->lightabsolute_bottom != spawnsi->lightabsolute_bottom)
+		diff |= LD_SDBOTLIGHTABS;
 	return diff;
 }
 
@@ -1452,8 +1458,20 @@ static void ArchiveSide(const side_t *si, UINT32 diff)
 		WRITEINT16(save_p, si->repeatcnt);
 	if (diff & LD_SDLIGHT)
 		WRITEINT16(save_p, si->light);
+	if (diff & LD_SDTOPLIGHT)
+		WRITEINT16(save_p, si->light_top);
+	if (diff & LD_SDMIDLIGHT)
+		WRITEINT16(save_p, si->light_mid);
+	if (diff & LD_SDBOTLIGHT)
+		WRITEINT16(save_p, si->light_bottom);
 	if (diff & LD_SDLIGHTABS)
-		WRITEINT16(save_p, si->lightabsolute);
+		WRITEUINT8(save_p, si->lightabsolute);
+	if (diff & LD_SDTOPLIGHTABS)
+		WRITEUINT8(save_p, si->lightabsolute_top);
+	if (diff & LD_SDMIDLIGHTABS)
+		WRITEUINT8(save_p, si->lightabsolute_mid);
+	if (diff & LD_SDBOTLIGHTABS)
+		WRITEUINT8(save_p, si->lightabsolute_bottom);
 }
 
 static void ArchiveLines(void)
@@ -1596,8 +1614,20 @@ static void UnArchiveSide(side_t *si)
 		si->repeatcnt = READINT16(save_p);
 	if (diff & LD_SDLIGHT)
 		si->light = READINT16(save_p);
+	if (diff & LD_SDTOPLIGHT)
+		si->light_top = READINT16(save_p);
+	if (diff & LD_SDMIDLIGHT)
+		si->light_mid = READINT16(save_p);
+	if (diff & LD_SDBOTLIGHT)
+		si->light_bottom = READINT16(save_p);
 	if (diff & LD_SDLIGHTABS)
-		si->lightabsolute = READINT16(save_p);
+		si->lightabsolute = READUINT8(save_p);
+	if (diff & LD_SDTOPLIGHTABS)
+		si->lightabsolute_top = READUINT8(save_p);
+	if (diff & LD_SDMIDLIGHTABS)
+		si->lightabsolute_mid = READUINT8(save_p);
+	if (diff & LD_SDBOTLIGHTABS)
+		si->lightabsolute_bottom = READUINT8(save_p);
 }
 
 static void UnArchiveLines(void)
diff --git a/src/p_setup.c b/src/p_setup.c
index 8819d11cbba19bf1fdaf77424c737a8e2c6d6d6b..b5ed485d8a7df9512ce24a4b78f61e950280b280 100644
--- a/src/p_setup.c
+++ b/src/p_setup.c
@@ -1982,8 +1982,20 @@ static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char
 		sides[i].repeatcnt = atol(val);
 	else if (fastcmp(param, "light"))
 		sides[i].light = atol(val);
+	else if (fastcmp(param, "light_top"))
+		sides[i].light_top = atol(val);
+	else if (fastcmp(param, "light_mid"))
+		sides[i].light_mid = atol(val);
+	else if (fastcmp(param, "light_bottom"))
+		sides[i].light_bottom = atol(val);
 	else if (fastcmp(param, "lightabsolute") && fastcmp("true", val))
 		sides[i].lightabsolute = true;
+	else if (fastcmp(param, "lightabsolute_top") && fastcmp("true", val))
+		sides[i].lightabsolute_top = true;
+	else if (fastcmp(param, "lightabsolute_mid") && fastcmp("true", val))
+		sides[i].lightabsolute_mid = true;
+	else if (fastcmp(param, "lightabsolute_bottom") && fastcmp("true", val))
+		sides[i].lightabsolute_bottom = true;
 }
 
 static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char *val)
@@ -2713,8 +2725,20 @@ static void P_WriteTextmap(void)
 			fprintf(f, "repeatcnt = %d;\n", wsides[i].repeatcnt);
 		if (wsides[i].light != 0)
 			fprintf(f, "light = %d;\n", wsides[i].light);
-		if (wsides[i].lightabsolute != 0)
-			fprintf(f, "lightabsolute = %d;\n", wsides[i].lightabsolute);
+		if (wsides[i].light_top != 0)
+			fprintf(f, "light_top = %d;\n", wsides[i].light_top);
+		if (wsides[i].light_mid != 0)
+			fprintf(f, "light_mid = %d;\n", wsides[i].light_mid);
+		if (wsides[i].light_bottom != 0)
+			fprintf(f, "light_bottom = %d;\n", wsides[i].light_bottom);
+		if (wsides[i].lightabsolute)
+			fprintf(f, "lightabsolute = true;\n");
+		if (wsides[i].lightabsolute_top)
+			fprintf(f, "lightabsolute_top = true;\n");
+		if (wsides[i].lightabsolute_mid)
+			fprintf(f, "lightabsolute_mid = true;\n");
+		if (wsides[i].lightabsolute_bottom)
+			fprintf(f, "lightabsolute_bottom = true;\n");
 		fprintf(f, "}\n");
 		fprintf(f, "\n");
 	}
@@ -3117,7 +3141,8 @@ static void P_LoadTextmap(void)
 		sd->bottomtexture = R_TextureNumForName("-");
 		sd->sector = NULL;
 		sd->repeatcnt = 0;
-		sd->light = sd->lightabsolute = 0;
+		sd->light = sd->light_top = sd->light_mid = sd->light_bottom = 0;
+		sd->lightabsolute = sd->lightabsolute_top = sd->lightabsolute_mid = sd->lightabsolute_bottom = false;
 
 		TextmapParse(sidedefBlocks.pos[i], i, ParseTextmapSidedefParameter);
 
diff --git a/src/r_segs.c b/src/r_segs.c
index ba6e0cc0d9fdc0ac8e0b9d0ff51c8e667dfc23b0..51487d24227b1c054ee0ad9c0258efeaacfe0baa 100644
--- a/src/r_segs.c
+++ b/src/r_segs.c
@@ -100,6 +100,7 @@ static INT16 R_SideLightLevel(side_t *side, UINT8 base_lightlevel)
 		((side->lightabsolute) ? 0 : base_lightlevel);
 }
 
+/* TODO: implement per-texture lighting
 static INT16 R_TopLightLevel(side_t *side, UINT8 base_lightlevel)
 {
 	return side->light_top +
@@ -117,6 +118,7 @@ static INT16 R_BottomLightLevel(side_t *side, UINT8 base_lightlevel)
 	return side->light_bottom +
 		((side->lightabsolute_bottom) ? 0 : R_SideLightLevel(side, base_lightlevel));
 }
+*/
 
 void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2)
 {