From 9dd42be15f72b5128be823e6aeb0adafa3915486 Mon Sep 17 00:00:00 2001
From: Braden Obrzut <admin@maniacsvault.net>
Date: Sun, 16 Oct 2016 16:22:21 -0400
Subject: [PATCH 1/8] - Fixed: Demo playback on Windows XP since we don't patch
 fstat for v140_xp bug.

---
 src/m_misc.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/m_misc.cpp b/src/m_misc.cpp
index 824fe0533..c49b342ce 100644
--- a/src/m_misc.cpp
+++ b/src/m_misc.cpp
@@ -123,7 +123,8 @@ int M_ReadFile (char const *name, BYTE **buffer)
 	handle = open (name, O_RDONLY | O_BINARY, 0666);
 	if (handle == -1)
 		I_Error ("Couldn't read file %s", name);
-	if (fstat (handle,&fileinfo) == -1)
+	// [BL] Use stat instead of fstat for v140_xp hack
+	if (stat (name,&fileinfo) == -1)
 		I_Error ("Couldn't read file %s", name);
 	length = fileinfo.st_size;
 	buf = new BYTE[length];
@@ -149,7 +150,8 @@ int M_ReadFileMalloc (char const *name, BYTE **buffer)
 	handle = open (name, O_RDONLY | O_BINARY, 0666);
 	if (handle == -1)
 		I_Error ("Couldn't read file %s", name);
-	if (fstat (handle,&fileinfo) == -1)
+	// [BL] Use stat instead of fstat for v140_xp hack
+	if (stat (name,&fileinfo) == -1)
 		I_Error ("Couldn't read file %s", name);
 	length = fileinfo.st_size;
 	buf = (BYTE*)M_Malloc(length);

From 741c9edf421a757d5a8d003964b0ca4f8815262b Mon Sep 17 00:00:00 2001
From: Braden Obrzut <admin@maniacsvault.net>
Date: Mon, 17 Oct 2016 00:19:08 -0400
Subject: [PATCH 2/8] - Clear out GCC 6.2 warnings (interestingly they now
 check for misleading indentation which found a good case in
 fragglescript/t_func.cpp even though I believe it was harmless)

---
 src/fragglescript/t_func.cpp         | 2 +-
 src/p_acs.cpp                        | 4 ++--
 src/p_ceiling.cpp                    | 2 +-
 src/p_saveg.cpp                      | 8 ++++----
 src/resourcefiles/file_zip.cpp       | 3 ++-
 src/serializer.cpp                   | 4 ++--
 src/serializer.h                     | 2 +-
 src/sound/music_hmi_midiout.cpp      | 4 ++--
 src/sound/music_smf_midiout.cpp      | 6 +++---
 src/sound/music_xmi_midiout.cpp      | 6 +++---
 src/thingdef/thingdef_expression.cpp | 6 +++---
 11 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp
index a02ec947f..cc096ed60 100644
--- a/src/fragglescript/t_func.cpp
+++ b/src/fragglescript/t_func.cpp
@@ -497,7 +497,7 @@ DFsSection *FParser::looping_section()
 					if(!best || (current->start_index > best->start_index))
 						best = current;     // save it
 				}
-				current = current->next;
+			current = current->next;
 		}
 	}
 	
diff --git a/src/p_acs.cpp b/src/p_acs.cpp
index 71ef65f22..fcbff904a 100644
--- a/src/p_acs.cpp
+++ b/src/p_acs.cpp
@@ -1616,7 +1616,7 @@ void FBehavior::StaticSerializeModuleStates (FSerializer &arc)
 	{
 		if (arc.isReading())
 		{
-			int modnum = arc.ArraySize();
+			auto modnum = arc.ArraySize();
 			if (modnum != StaticModules.Size())
 			{
 				I_Error("Level was saved with a different number of ACS modules. (Have %d, save has %d)", StaticModules.Size(), modnum);
@@ -2933,7 +2933,7 @@ void DACSThinker::Serialize(FSerializer &arc)
 		if (arc.BeginArray("runningscripts"))
 		{
 			auto cnt = arc.ArraySize();
-			for (int i = 0; i < cnt; i++)
+			for (unsigned i = 0; i < cnt; i++)
 			{
 				SavingRunningscript srs;
 				arc(nullptr, srs);
diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp
index e90dd2096..29b0c5095 100644
--- a/src/p_ceiling.cpp
+++ b/src/p_ceiling.cpp
@@ -184,7 +184,7 @@ void DCeiling::Tick ()
 				case DCeiling::ceilLowerAndCrush:
 					if (m_CrushMode == ECrushMode::crushSlowdown)
 						m_Speed = 1. / 8;
-						break;
+					break;
 
 				default:
 					break;
diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp
index 9bb9f82e8..46cdd767b 100644
--- a/src/p_saveg.cpp
+++ b/src/p_saveg.cpp
@@ -888,10 +888,10 @@ void G_SerializeLevel(FSerializer &arc, bool hubload)
 		// deep down in the deserializer or just a crash if the few insufficient safeguards were not triggered.
 		BYTE chk[16] = { 0 };
 		arc.Array("checksum", chk, 16);
-		if (arc.GetSize("linedefs") != numlines ||
-			arc.GetSize("sidedefs") != numsides ||
-			arc.GetSize("sectors") != numsectors ||
-			arc.GetSize("polyobjs") != po_NumPolyobjs ||
+		if (arc.GetSize("linedefs") != (unsigned)numlines ||
+			arc.GetSize("sidedefs") != (unsigned)numsides ||
+			arc.GetSize("sectors") != (unsigned)numsectors ||
+			arc.GetSize("polyobjs") != (unsigned)po_NumPolyobjs ||
 			memcmp(chk, level.md5, 16))
 		{
 			I_Error("Savegame is from a different level");
diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp
index 73193062c..8713fe554 100644
--- a/src/resourcefiles/file_zip.cpp
+++ b/src/resourcefiles/file_zip.cpp
@@ -392,7 +392,8 @@ int FZipLump::FillCache()
 int FZipLump::GetFileOffset()
 {
 	if (Method != METHOD_STORED) return -1;
-	if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); return Position;
+	if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress();
+	return Position;
 }
 
 //==========================================================================
diff --git a/src/serializer.cpp b/src/serializer.cpp
index 3a66a8397..49226ce80 100644
--- a/src/serializer.cpp
+++ b/src/serializer.cpp
@@ -381,7 +381,7 @@ void FSerializer::Close()
 //
 //==========================================================================
 
-int FSerializer::ArraySize()
+unsigned FSerializer::ArraySize()
 {
 	if (r != nullptr && r->mObjects.Last().mObject->IsArray())
 	{
@@ -709,7 +709,7 @@ FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *d
 		{
 			if (val->IsString())
 			{
-				int name = *reinterpret_cast<const int*>(val->GetString());
+				uint32_t name = *reinterpret_cast<const uint32_t*>(val->GetString());
 				for (auto hint = NumStdSprites; hint-- != 0; )
 				{
 					if (sprites[hint].dwName == name)
diff --git a/src/serializer.h b/src/serializer.h
index a3e1f531e..4797a4bce 100644
--- a/src/serializer.h
+++ b/src/serializer.h
@@ -60,7 +60,7 @@ public:
 	FWriter *w = nullptr;
 	FReader *r = nullptr;
 
-	int ArraySize();
+	unsigned ArraySize();
 	void WriteKey(const char *key);
 	void WriteObjects();
 
diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp
index 7d9d36926..691970765 100644
--- a/src/sound/music_hmi_midiout.cpp
+++ b/src/sound/music_hmi_midiout.cpp
@@ -145,8 +145,8 @@ HMISong::HMISong (FileReader &reader, EMidiDevice type, const char *args)
 	MusHeader = new BYTE[len];
 	SongLen = len;
 	NumTracks = 0;
-    if (reader.Read(MusHeader, len) != len)
-        return;
+	if (reader.Read(MusHeader, len) != len)
+		return;
 
 	// Do some validation of the MIDI file
 	if (memcmp(MusHeader, HMI_SONG_MAGIC, sizeof(HMI_SONG_MAGIC)) == 0)
diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp
index a045998a8..ae0c47e80 100644
--- a/src/sound/music_smf_midiout.cpp
+++ b/src/sound/music_smf_midiout.cpp
@@ -114,10 +114,10 @@ MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type, const char *args)
 		return;
 	}
 #endif
-    SongLen = reader.GetLength();
+	SongLen = reader.GetLength();
 	MusHeader = new BYTE[SongLen];
-    if (reader.Read(MusHeader, SongLen) != SongLen)
-        return;
+	if (reader.Read(MusHeader, SongLen) != SongLen)
+		return;
 
 	// Do some validation of the MIDI file
 	if (MusHeader[4] != 0 || MusHeader[5] != 0 || MusHeader[6] != 0 || MusHeader[7] != 6)
diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp
index b56e8f6f8..c9a2e9c46 100644
--- a/src/sound/music_xmi_midiout.cpp
+++ b/src/sound/music_xmi_midiout.cpp
@@ -117,10 +117,10 @@ XMISong::XMISong (FileReader &reader, EMidiDevice type, const char *args)
 		return;
 	}
 #endif
-    SongLen = reader.GetLength();
+	SongLen = reader.GetLength();
 	MusHeader = new BYTE[SongLen];
-    if (reader.Read(MusHeader, SongLen) != SongLen)
-        return;
+	if (reader.Read(MusHeader, SongLen) != SongLen)
+		return;
 
 	// Find all the songs in this file.
 	NumSongs = FindXMIDforms(MusHeader, SongLen, NULL);
diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp
index c2b2d25e6..7c55e5286 100644
--- a/src/thingdef/thingdef_expression.cpp
+++ b/src/thingdef/thingdef_expression.cpp
@@ -91,7 +91,7 @@ static const FLOP FxFlops[] =
 //
 //==========================================================================
 
-FCompileContext::FCompileContext(PClassActor *cls, PPrototype *ret) : Class(cls), ReturnProto(ret)
+FCompileContext::FCompileContext(PClassActor *cls, PPrototype *ret) : ReturnProto(ret), Class(cls)
 {
 }
 
@@ -959,7 +959,7 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build)
 //==========================================================================
 
 FxPreIncrDecr::FxPreIncrDecr(FxExpression *base, int token)
-: FxExpression(base->ScriptPosition), Base(base), Token(token)
+: FxExpression(base->ScriptPosition), Token(token), Base(base)
 {
 	AddressRequested = false;
 	AddressWritable = false;
@@ -1045,7 +1045,7 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build)
 //==========================================================================
 
 FxPostIncrDecr::FxPostIncrDecr(FxExpression *base, int token)
-: FxExpression(base->ScriptPosition), Base(base), Token(token)
+: FxExpression(base->ScriptPosition), Token(token), Base(base)
 {
 }
 

From b4bdb8fa7d2a0bc870270185106d2b3854249f31 Mon Sep 17 00:00:00 2001
From: Braden Obrzut <admin@maniacsvault.net>
Date: Mon, 17 Oct 2016 00:22:06 -0400
Subject: [PATCH 3/8] - Fixed: Assertion failure if a save was loaded without
 starting a new game (due to uninitialized RNG).

---
 src/m_random.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/m_random.cpp b/src/m_random.cpp
index e0a55d095..60ce12fd6 100644
--- a/src/m_random.cpp
+++ b/src/m_random.cpp
@@ -331,6 +331,10 @@ void FRandom::StaticReadRNGState(FSerializer &arc)
 	FRandom *rng;
 
 	arc("rngseed", rngseed);
+
+	// Call StaticClearRandom in order to ensure that SFMT is initialized
+	FRandom::StaticClearRandom ();
+
 	if (arc.BeginArray("rngs"))
 	{
 		int count = arc.ArraySize();

From d2a9f7ac6f47232c3370cce28806b23933d2b45b Mon Sep 17 00:00:00 2001
From: Marisa Heit <rheit@users.noreply.github.com>
Date: Mon, 17 Oct 2016 21:45:06 -0500
Subject: [PATCH 4/8] Fix Raise definition for DoomImp

---
 wadsrc/static/actors/doom/doomimp.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/wadsrc/static/actors/doom/doomimp.txt b/wadsrc/static/actors/doom/doomimp.txt
index a5725e724..008cc5229 100644
--- a/wadsrc/static/actors/doom/doomimp.txt
+++ b/wadsrc/static/actors/doom/doomimp.txt
@@ -52,7 +52,8 @@ ACTOR DoomImp
 		TROO U -1
 		Stop
 	Raise:
-		TROO MLKJI 8
+		TROO ML 8
+		TROO KJI 6
 		Goto See
 	}
 }

From 5de811257883b512f6c44c7d3997fedcc1297b88 Mon Sep 17 00:00:00 2001
From: Magnus Norddahl <dpjudas@users.noreply.github.com>
Date: Wed, 19 Oct 2016 23:52:09 +0200
Subject: [PATCH 5/8] Add support for capping sky with a solid color

---
 src/r_draw.cpp             | 241 +++++++++++++++++++++++++++++++++++++
 src/r_draw.h               |   7 ++
 src/r_plane.cpp            | 165 +++++++++++++++++++++++++
 src/textures/texture.cpp   |  73 +++++++++++
 src/textures/textures.h    |   6 +
 wadsrc/static/language.enu |   1 +
 wadsrc/static/menudef.txt  |   1 +
 7 files changed, 494 insertions(+)

diff --git a/src/r_draw.cpp b/src/r_draw.cpp
index 80b91ed2d..5f592223b 100644
--- a/src/r_draw.cpp
+++ b/src/r_draw.cpp
@@ -110,6 +110,8 @@ DWORD			vplce[4];
 DWORD			vince[4];
 BYTE*			palookupoffse[4];
 const BYTE*		bufplce[4];
+const BYTE*		bufplce2[4];
+uint32_t		bufheight[4];
 
 // just for profiling 
 int 			dccount;
@@ -2142,6 +2144,245 @@ void tmvline4_revsubclamp ()
 	} while (--count);
 }
 
+void R_DrawSingleSkyCol1(uint32_t solid_top, uint32_t solid_bottom)
+{
+	uint8_t *dest = dc_dest;
+	int count = dc_count;
+	int pitch = dc_pitch;
+	const uint8_t *source0 = bufplce[0];
+	int textureheight0 = bufheight[0];
+
+	int32_t frac = vplce[0];
+	int32_t fracstep = vince[0];
+
+	int start_fade = 2; // How fast it should fade out
+
+	int solid_top_r = RPART(solid_top);
+	int solid_top_g = GPART(solid_top);
+	int solid_top_b = BPART(solid_top);
+	int solid_bottom_r = RPART(solid_bottom);
+	int solid_bottom_g = GPART(solid_bottom);
+	int solid_bottom_b = BPART(solid_bottom);
+
+	for (int index = 0; index < count; index++)
+	{
+		uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS;
+		uint8_t fg = source0[sample_index];
+
+		int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0);
+		int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0);
+
+		if (alpha_top == 256 && alpha_bottom == 256)
+		{
+			*dest = fg;
+		}
+		else
+		{
+			int inv_alpha_top = 256 - alpha_top;
+			int inv_alpha_bottom = 256 - alpha_bottom;
+
+			const auto &c = GPalette.BaseColors[fg];
+			int c_red = c.r;
+			int c_green = c.g;
+			int c_blue = c.b;
+			c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8;
+			c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8;
+			c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8;
+			c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8;
+			c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8;
+			c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8;
+			*dest = RGB32k.RGB[(c_red >> 3)][(c_green >> 3)][(c_blue >> 3)];
+		}
+
+		frac += fracstep;
+		dest += pitch;
+	}
+}
+
+void R_DrawSingleSkyCol4(uint32_t solid_top, uint32_t solid_bottom)
+{
+	for (int col = 0; col < 4; col++)
+	{
+		uint8_t *dest = dc_dest + col;
+		int count = dc_count;
+		int pitch = dc_pitch;
+		const uint8_t *source0 = bufplce[col];
+		int textureheight0 = bufheight[0];
+
+		int32_t frac = vplce[col];
+		int32_t fracstep = vince[col];
+
+		int start_fade = 2; // How fast it should fade out
+
+		int solid_top_r = RPART(solid_top);
+		int solid_top_g = GPART(solid_top);
+		int solid_top_b = BPART(solid_top);
+		int solid_bottom_r = RPART(solid_bottom);
+		int solid_bottom_g = GPART(solid_bottom);
+		int solid_bottom_b = BPART(solid_bottom);
+
+		for (int index = 0; index < count; index++)
+		{
+			uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS;
+			uint8_t fg = source0[sample_index];
+
+			int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0);
+			int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0);
+
+			if (alpha_top == 256 && alpha_bottom == 256)
+			{
+				*dest = fg;
+			}
+			else
+			{
+				int inv_alpha_top = 256 - alpha_top;
+				int inv_alpha_bottom = 256 - alpha_bottom;
+
+				const auto &c = GPalette.BaseColors[fg];
+				int c_red = c.r;
+				int c_green = c.g;
+				int c_blue = c.b;
+				c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8;
+				c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8;
+				c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8;
+				c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8;
+				c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8;
+				c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8;
+				*dest = RGB32k.RGB[(c_red >> 3)][(c_green >> 3)][(c_blue >> 3)];
+			}
+
+			frac += fracstep;
+			dest += pitch;
+		}
+	}
+}
+
+void R_DrawDoubleSkyCol1(uint32_t solid_top, uint32_t solid_bottom)
+{
+	uint8_t *dest = dc_dest;
+	int count = dc_count;
+	int pitch = dc_pitch;
+	const uint8_t *source0 = bufplce[0];
+	const uint8_t *source1 = bufplce2[0];
+	int textureheight0 = bufheight[0];
+	uint32_t maxtextureheight1 = bufheight[1] - 1;
+
+	int32_t frac = vplce[0];
+	int32_t fracstep = vince[0];
+
+	int start_fade = 2; // How fast it should fade out
+
+	int solid_top_r = RPART(solid_top);
+	int solid_top_g = GPART(solid_top);
+	int solid_top_b = BPART(solid_top);
+	int solid_bottom_r = RPART(solid_bottom);
+	int solid_bottom_g = GPART(solid_bottom);
+	int solid_bottom_b = BPART(solid_bottom);
+
+	for (int index = 0; index < count; index++)
+	{
+		uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS;
+		uint8_t fg = source0[sample_index];
+		if (fg == 0)
+		{
+			uint32_t sample_index2 = MIN(sample_index, maxtextureheight1);
+			fg = source1[sample_index2];
+		}
+
+		int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0);
+		int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0);
+
+		if (alpha_top == 256 && alpha_bottom == 256)
+		{
+			*dest = fg;
+		}
+		else
+		{
+			int inv_alpha_top = 256 - alpha_top;
+			int inv_alpha_bottom = 256 - alpha_bottom;
+
+			const auto &c = GPalette.BaseColors[fg];
+			int c_red = c.r;
+			int c_green = c.g;
+			int c_blue = c.b;
+			c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8;
+			c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8;
+			c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8;
+			c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8;
+			c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8;
+			c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8;
+			*dest = RGB32k.RGB[(c_red >> 3)][(c_green >> 3)][(c_blue >> 3)];
+		}
+
+		frac += fracstep;
+		dest += pitch;
+	}
+}
+
+void R_DrawDoubleSkyCol4(uint32_t solid_top, uint32_t solid_bottom)
+{
+	for (int col = 0; col < 4; col++)
+	{
+		uint8_t *dest = dc_dest + col;
+		int count = dc_count;
+		int pitch = dc_pitch;
+		const uint8_t *source0 = bufplce[col];
+		const uint8_t *source1 = bufplce2[col];
+		int textureheight0 = bufheight[0];
+		uint32_t maxtextureheight1 = bufheight[1] - 1;
+
+		int32_t frac = vplce[col];
+		int32_t fracstep = vince[col];
+
+		int start_fade = 2; // How fast it should fade out
+
+		int solid_top_r = RPART(solid_top);
+		int solid_top_g = GPART(solid_top);
+		int solid_top_b = BPART(solid_top);
+		int solid_bottom_r = RPART(solid_bottom);
+		int solid_bottom_g = GPART(solid_bottom);
+		int solid_bottom_b = BPART(solid_bottom);
+
+		for (int index = 0; index < count; index++)
+		{
+			uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS;
+			uint8_t fg = source0[sample_index];
+			if (fg == 0)
+			{
+				uint32_t sample_index2 = MIN(sample_index, maxtextureheight1);
+				fg = source1[sample_index2];
+			}
+
+			int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0);
+			int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0);
+
+			if (alpha_top == 256 && alpha_bottom == 256)
+			{
+				*dest = fg;
+			}
+			else
+			{
+				int inv_alpha_top = 256 - alpha_top;
+				int inv_alpha_bottom = 256 - alpha_bottom;
+
+				const auto &c = GPalette.BaseColors[fg];
+				int c_red = c.r;
+				int c_green = c.g;
+				int c_blue = c.b;
+				c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8;
+				c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8;
+				c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8;
+				c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8;
+				c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8;
+				c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8;
+				*dest = RGB32k.RGB[(c_red >> 3)][(c_green >> 3)][(c_blue >> 3)];
+			}
+
+			frac += fracstep;
+			dest += pitch;
+		}
+	}
+}
 
 //==========================================================================
 //
diff --git a/src/r_draw.h b/src/r_draw.h
index cb2f68f33..c45700a21 100644
--- a/src/r_draw.h
+++ b/src/r_draw.h
@@ -51,6 +51,8 @@ extern "C" DWORD		vplce[4];
 extern "C" DWORD		vince[4];
 extern "C" BYTE*		palookupoffse[4];
 extern "C" const BYTE*	bufplce[4];
+extern "C" const BYTE*	bufplce2[4];
+extern "C" uint32_t		bufheight[4];
 
 // [RH] Temporary buffer for column drawing
 extern "C" BYTE			*dc_temp;
@@ -293,4 +295,9 @@ void maskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_
 // transmaskwallscan is like maskwallscan, but it can also blend to the background
 void transmaskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int col)=R_GetColumn);
 
+void R_DrawSingleSkyCol1(uint32_t solid_top, uint32_t solid_bottom);
+void R_DrawSingleSkyCol4(uint32_t solid_top, uint32_t solid_bottom);
+void R_DrawDoubleSkyCol1(uint32_t solid_top, uint32_t solid_bottom);
+void R_DrawDoubleSkyCol4(uint32_t solid_top, uint32_t solid_bottom);
+
 #endif
diff --git a/src/r_plane.cpp b/src/r_plane.cpp
index 07001bf1b..8c12b3ca2 100644
--- a/src/r_plane.cpp
+++ b/src/r_plane.cpp
@@ -63,6 +63,8 @@
 #pragma warning(disable:4244)
 #endif
 
+CVAR(Bool, r_capsky, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
+
 //EXTERN_CVAR (Int, tx)
 //EXTERN_CVAR (Int, ty)
 
@@ -898,8 +900,171 @@ static const BYTE *R_GetTwoSkyColumns (FTexture *fronttex, int x)
 	return composite;
 }
 
+static void R_DrawSkyColumnStripe(int start_x, int y1, int y2, int columns, double scale, double texturemid, double yrepeat)
+{
+	uint32_t height = frontskytex->GetHeight();
+
+	for (int i = 0; i < columns; i++)
+	{
+		double uv_stepd = skyiscale * yrepeat;
+		double v = (texturemid + uv_stepd * (y1 - CenterY + 0.5)) / height;
+		double v_step = uv_stepd / height;
+
+		uint32_t uv_pos = (uint32_t)(v * 0x01000000);
+		uint32_t uv_step = (uint32_t)(v_step * 0x01000000);
+
+		int x = start_x + i;
+		if (MirrorFlags & RF_XFLIP)
+			x = (viewwidth - x);
+
+		DWORD ang, angle1, angle2;
+
+		ang = (skyangle + xtoviewangle[x]) ^ skyflip;
+		angle1 = (DWORD)((UMulScale16(ang, frontcyl) + frontpos) >> FRACBITS);
+		angle2 = (DWORD)((UMulScale16(ang, backcyl) + backpos) >> FRACBITS);
+
+		bufplce[i] = (const BYTE *)frontskytex->GetColumn(angle1, nullptr);
+		bufplce2[i] = backskytex ? (const BYTE *)backskytex->GetColumn(angle2, nullptr) : nullptr;
+
+		vince[i] = uv_step;
+		vplce[i] = uv_pos;
+	}
+
+	bufheight[0] = height;
+	bufheight[1] = backskytex ? backskytex->GetHeight() : height;
+	dc_dest = (ylookup[y1] + start_x) + dc_destorg;
+	dc_count = y2 - y1;
+
+	uint32_t solid_top = frontskytex->GetSWSkyCapColor(false);
+	uint32_t solid_bottom = frontskytex->GetSWSkyCapColor(true);
+
+	if (columns == 4)
+		if (!backskytex)
+			R_DrawSingleSkyCol4(solid_top, solid_bottom);
+		else
+			R_DrawDoubleSkyCol4(solid_top, solid_bottom);
+	else
+		if (!backskytex)
+			R_DrawSingleSkyCol1(solid_top, solid_bottom);
+		else
+			R_DrawDoubleSkyCol1(solid_top, solid_bottom);
+}
+
+static void R_DrawSkyColumn(int start_x, int y1, int y2, int columns)
+{
+	if (1 << frontskytex->HeightBits == frontskytex->GetHeight())
+	{
+		double texturemid = skymid * frontskytex->Scale.Y + frontskytex->GetHeight();
+		R_DrawSkyColumnStripe(start_x, y1, y2, columns, frontskytex->Scale.Y, texturemid, frontskytex->Scale.Y);
+	}
+	else
+	{
+		double yrepeat = frontskytex->Scale.Y;
+		double scale = frontskytex->Scale.Y * skyscale;
+		double iscale = 1 / scale;
+		short drawheight = short(frontskytex->GetHeight() * scale);
+		double topfrac = fmod(skymid + iscale * (1 - CenterY), frontskytex->GetHeight());
+		if (topfrac < 0) topfrac += frontskytex->GetHeight();
+		double texturemid = topfrac - iscale * (1 - CenterY);
+		R_DrawSkyColumnStripe(start_x, y1, y2, columns, scale, texturemid, yrepeat);
+	}
+}
+
+static void R_DrawCapSky(visplane_t *pl)
+{
+	int x1 = pl->left;
+	int x2 = pl->right;
+	short *uwal = (short *)pl->top;
+	short *dwal = (short *)pl->bottom;
+
+	// Calculate where 4 column alignment begins and ends:
+	int aligned_x1 = clamp((x1 + 3) / 4 * 4, x1, x2);
+	int aligned_x2 = clamp(x2 / 4 * 4, x1, x2);
+
+	// First unaligned columns:
+	for (int x = x1; x < aligned_x1; x++)
+	{
+		int y1 = uwal[x];
+		int y2 = dwal[x];
+		if (y2 <= y1)
+			continue;
+
+		R_DrawSkyColumn(x, y1, y2, 1);
+	}
+
+	// The aligned columns
+	for (int x = aligned_x1; x < aligned_x2; x += 4)
+	{
+		// Find y1, y2, light and uv values for four columns:
+		int y1[4] = { uwal[x], uwal[x + 1], uwal[x + 2], uwal[x + 3] };
+		int y2[4] = { dwal[x], dwal[x + 1], dwal[x + 2], dwal[x + 3] };
+
+		// Figure out where we vertically can start and stop drawing 4 columns in one go
+		int middle_y1 = y1[0];
+		int middle_y2 = y2[0];
+		for (int i = 1; i < 4; i++)
+		{
+			middle_y1 = MAX(y1[i], middle_y1);
+			middle_y2 = MIN(y2[i], middle_y2);
+		}
+
+		// If we got an empty column in our set we cannot draw 4 columns in one go:
+		bool empty_column_in_set = false;
+		for (int i = 0; i < 4; i++)
+		{
+			if (y2[i] <= y1[i])
+				empty_column_in_set = true;
+		}
+		if (empty_column_in_set || middle_y2 <= middle_y1)
+		{
+			for (int i = 0; i < 4; i++)
+			{
+				if (y2[i] <= y1[i])
+					continue;
+
+				R_DrawSkyColumn(x + i, y1[i], y2[i], 1);
+			}
+			continue;
+		}
+
+		// Draw the first rows where not all 4 columns are active
+		for (int i = 0; i < 4; i++)
+		{
+			if (y1[i] < middle_y1)
+				R_DrawSkyColumn(x + i, y1[i], middle_y1, 1);
+		}
+
+		// Draw the area where all 4 columns are active
+		R_DrawSkyColumn(x, middle_y1, middle_y2, 4);
+
+		// Draw the last rows where not all 4 columns are active
+		for (int i = 0; i < 4; i++)
+		{
+			if (middle_y2 < y2[i])
+				R_DrawSkyColumn(x + i, middle_y2, y2[i], 1);
+		}
+	}
+
+	// The last unaligned columns:
+	for (int x = aligned_x2; x < x2; x++)
+	{
+		int y1 = uwal[x];
+		int y2 = dwal[x];
+		if (y2 <= y1)
+			continue;
+
+		R_DrawSkyColumn(x, y1, y2, 1);
+	}
+}
+
 static void R_DrawSky (visplane_t *pl)
 {
+	if (r_capsky)
+	{
+		R_DrawCapSky(pl);
+		return;
+	}
+
 	int x;
 	float swal;
 
diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp
index 7b90c295f..f3c9e19a1 100644
--- a/src/textures/texture.cpp
+++ b/src/textures/texture.cpp
@@ -45,6 +45,7 @@
 #include "v_video.h"
 #include "m_fixed.h"
 #include "textures/textures.h"
+#include "v_palette.h"
 
 typedef bool (*CheckFunc)(FileReader & file);
 typedef FTexture * (*CreateFunc)(FileReader & file, int lumpnum);
@@ -569,6 +570,78 @@ void FTexture::SetScaledSize(int fitwidth, int fitheight)
 	if (int(Scale.Y * fitheight) != Height) Scale.Y += (1 / 65536.);
 }
 
+//===========================================================================
+// 
+//	Gets the average color of a texture for use as a sky cap color
+//
+//===========================================================================
+
+namespace
+{
+	PalEntry averageColor(const DWORD *data, int size, int maxout)
+	{
+		int				i;
+		unsigned int	r, g, b;
+
+		// First clear them.
+		r = g = b = 0;
+		if (size == 0)
+		{
+			return PalEntry(255, 255, 255);
+		}
+		for (i = 0; i < size; i++)
+		{
+			r += BPART(data[i]);
+			g += GPART(data[i]);
+			b += RPART(data[i]);
+		}
+
+		r = r / size;
+		g = g / size;
+		b = b / size;
+
+		int maxv = MAX(MAX(r, g), b);
+
+		if (maxv && maxout)
+		{
+			r = Scale(r, maxout, maxv);
+			g = Scale(g, maxout, maxv);
+			b = Scale(b, maxout, maxv);
+		}
+		return PalEntry(255, r, g, b);
+	}
+}
+
+PalEntry FTexture::GetSWSkyCapColor(bool bottom)
+{
+	PalEntry col;
+	int w;
+	int h;
+
+	if (!bSWSkyColorDone)
+	{
+		bSWSkyColorDone = true;
+
+		FBitmap bitmap;
+		bitmap.Create(GetWidth(), GetHeight());
+		CopyTrueColorPixels(&bitmap, 0, 0);
+		int w = GetWidth();
+		int h = GetHeight();
+
+		const uint32_t *buffer = (const uint32_t *)bitmap.GetPixels();
+		if (buffer)
+		{
+			SWCeilingSkyColor = averageColor((DWORD *)buffer, w * MIN(30, h), 0);
+			if (h>30)
+			{
+				SWFloorSkyColor = averageColor(((DWORD *)buffer) + (h - 30)*w, w * 30, 0);
+			}
+			else SWFloorSkyColor = SWCeilingSkyColor;
+		}
+	}
+	return bottom ? SWFloorSkyColor : SWCeilingSkyColor;
+}
+
 
 FDummyTexture::FDummyTexture ()
 {
diff --git a/src/textures/textures.h b/src/textures/textures.h
index 298b169f2..9402417f7 100644
--- a/src/textures/textures.h
+++ b/src/textures/textures.h
@@ -239,6 +239,7 @@ public:
 	}
 
 	void SetScaledSize(int fitwidth, int fitheight);
+	PalEntry GetSWSkyCapColor(bool bottom);
 
 	virtual void HackHack (int newheight);	// called by FMultipatchTexture to discover corrupt patches.
 
@@ -259,6 +260,11 @@ protected:
 		Rotations = other->Rotations;
 	}
 
+private:
+	bool bSWSkyColorDone = false;
+	PalEntry SWFloorSkyColor;
+	PalEntry SWCeilingSkyColor;
+
 public:
 	static void FlipSquareBlock (BYTE *block, int x, int y);
 	static void FlipSquareBlockRemap (BYTE *block, int x, int y, const BYTE *remap);
diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu
index 50d14ab75..5a10527ac 100644
--- a/wadsrc/static/language.enu
+++ b/wadsrc/static/language.enu
@@ -1787,6 +1787,7 @@ DSPLYMNU_PICKUPFADE				= "Pickup Flash Intensity";
 DSPLYMNU_PALLETEHACK			= "DirectDraw palette hack"; // Not used
 DSPLYMNU_ATTACHEDSURFACES		= "Use attached surfaces"; // Not used
 DSPLYMNU_STRETCHSKY				= "Stretch short skies";
+DSPLYMNU_CAPSKY					= "Cap skies with solid color";
 DSPLYMNU_DRAWFUZZ				= "Use fuzz effect";
 DSPLYMNU_TRANSSOUL				= "Lost Soul translucency";
 DSPLYMNU_FAKECONTRAST			= "Use fake contrast";
diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt
index cd004bb0d..f7131be55 100644
--- a/wadsrc/static/menudef.txt
+++ b/wadsrc/static/menudef.txt
@@ -674,6 +674,7 @@ OptionMenu "VideoOptions"
 		//Option "$DSPLYMNU_ATTACHEDSURFACES", 	"vid_attachedsurfaces", "OnOff"
 	}
 	
+	Option "$DSPLYMNU_CAPSKY",					"r_capsky", "OnOff"
 	Option "$DSPLYMNU_STRETCHSKY",				"r_stretchsky", "OnOff"
 	Option "$DSPLYMNU_DRAWFUZZ",				"r_drawfuzz", "Fuzziness"
 	Slider "$DSPLYMNU_TRANSSOUL",				"transsouls", 0.25, 1.0, 0.05, 2

From 2fe545a4fdbaa0020517861d2d4de02f3e108a14 Mon Sep 17 00:00:00 2001
From: Magnus Norddahl <dpjudas@users.noreply.github.com>
Date: Thu, 20 Oct 2016 00:59:51 +0200
Subject: [PATCH 6/8] Merge r_stretchsky and r_capsky into r_skymode

---
 src/r_plane.cpp            |  4 ++--
 src/r_sky.cpp              |  5 +++--
 wadsrc/static/language.enu |  6 ++++--
 wadsrc/static/menudef.txt  | 10 ++++++++--
 4 files changed, 17 insertions(+), 8 deletions(-)

diff --git a/src/r_plane.cpp b/src/r_plane.cpp
index 8c12b3ca2..5ddf36f59 100644
--- a/src/r_plane.cpp
+++ b/src/r_plane.cpp
@@ -63,7 +63,7 @@
 #pragma warning(disable:4244)
 #endif
 
-CVAR(Bool, r_capsky, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
+EXTERN_CVAR(Int, r_skymode)
 
 //EXTERN_CVAR (Int, tx)
 //EXTERN_CVAR (Int, ty)
@@ -1059,7 +1059,7 @@ static void R_DrawCapSky(visplane_t *pl)
 
 static void R_DrawSky (visplane_t *pl)
 {
-	if (r_capsky)
+	if (r_skymode == 2)
 	{
 		R_DrawCapSky(pl);
 		return;
diff --git a/src/r_sky.cpp b/src/r_sky.cpp
index 9ea44db48..58caa09bd 100644
--- a/src/r_sky.cpp
+++ b/src/r_sky.cpp
@@ -49,7 +49,8 @@ fixed_t		sky1cyl,		sky2cyl;
 double		sky1pos,		sky2pos;
 
 // [RH] Stretch sky texture if not taller than 128 pixels?
-CUSTOM_CVAR (Bool, r_stretchsky, true, CVAR_ARCHIVE)
+// Also now controls capped skies. 0 = normal, 1 = stretched, 2 = capped
+CUSTOM_CVAR (Int, r_skymode, 2, CVAR_ARCHIVE)
 {
 	R_InitSkyMap ();
 }
@@ -99,7 +100,7 @@ void R_InitSkyMap ()
 	skytexturemid = 0;
 	if (skyheight >= 128 && skyheight < 200)
 	{
-		skystretch = (r_stretchsky
+		skystretch = (r_skymode == 1
 					  && skyheight >= 128
 					  && level.IsFreelookAllowed()
 					  && !(level.flags & LEVEL_FORCENOSKYSTRETCH)) ? 1 : 0;
diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu
index 5a10527ac..096d0832c 100644
--- a/wadsrc/static/language.enu
+++ b/wadsrc/static/language.enu
@@ -1786,8 +1786,7 @@ DSPLYMNU_BLOODFADE				= "Blood Flash Intensity";
 DSPLYMNU_PICKUPFADE				= "Pickup Flash Intensity";
 DSPLYMNU_PALLETEHACK			= "DirectDraw palette hack"; // Not used
 DSPLYMNU_ATTACHEDSURFACES		= "Use attached surfaces"; // Not used
-DSPLYMNU_STRETCHSKY				= "Stretch short skies";
-DSPLYMNU_CAPSKY					= "Cap skies with solid color";
+DSPLYMNU_SKYMODE				= "Sky render mode";
 DSPLYMNU_DRAWFUZZ				= "Use fuzz effect";
 DSPLYMNU_TRANSSOUL				= "Lost Soul translucency";
 DSPLYMNU_FAKECONTRAST			= "Use fake contrast";
@@ -2188,6 +2187,9 @@ OPTVAL_INVERTED				= "Inverted";
 OPTVAL_NOTINVERTED			= "Not Inverted";
 OPTVAL_ORIGINAL				= "Original";
 OPTVAL_OPTIMIZED			= "Optimized";
+OPTVAL_NORMAL				= "Normal";
+OPTVAL_STRETCH				= "Stretch";
+OPTVAL_CAPPED				= "Capped";
 OPTVAL_PARTICLES 			= "Particles";
 OPTVAL_SPRITES				= "Sprites";
 OPTVAL_SPRITESPARTICLES		= "Sprites & Particles";
diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt
index f7131be55..7b06a7e7f 100644
--- a/wadsrc/static/menudef.txt
+++ b/wadsrc/static/menudef.txt
@@ -600,6 +600,13 @@ OptionValue ColumnMethods
 	1.0, "$OPTVAL_OPTIMIZED"
 }
 
+OptionValue SkyModes
+{
+	0.0, "$OPTVAL_NORMAL"
+	1.0, "$OPTVAL_STRETCH"
+	2.0, "$OPTVAL_CAPPED"
+}
+
 OptionValue RocketTrailTypes
 {
 	0.0, "$OPTVAL_OFF"
@@ -674,8 +681,7 @@ OptionMenu "VideoOptions"
 		//Option "$DSPLYMNU_ATTACHEDSURFACES", 	"vid_attachedsurfaces", "OnOff"
 	}
 	
-	Option "$DSPLYMNU_CAPSKY",					"r_capsky", "OnOff"
-	Option "$DSPLYMNU_STRETCHSKY",				"r_stretchsky", "OnOff"
+	Option "$DSPLYMNU_SKYMODE",					"r_skymode", "SkyModes"
 	Option "$DSPLYMNU_DRAWFUZZ",				"r_drawfuzz", "Fuzziness"
 	Slider "$DSPLYMNU_TRANSSOUL",				"transsouls", 0.25, 1.0, 0.05, 2
 	Option "$DSPLYMNU_FAKECONTRAST",			"r_fakecontrast", "Contrast"

From 19d070c9bd3b92c335e8378b098cfdd91207ee1a Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Thu, 20 Oct 2016 09:08:07 +0200
Subject: [PATCH 7/8] - fixed: averageColor swapped red and blue. - renamed
 some stuff

---
 src/r_plane.cpp          |  4 ++--
 src/textures/texture.cpp | 14 +++++++-------
 src/textures/textures.h  |  6 +++---
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/r_plane.cpp b/src/r_plane.cpp
index 5ddf36f59..07efb84b4 100644
--- a/src/r_plane.cpp
+++ b/src/r_plane.cpp
@@ -935,8 +935,8 @@ static void R_DrawSkyColumnStripe(int start_x, int y1, int y2, int columns, doub
 	dc_dest = (ylookup[y1] + start_x) + dc_destorg;
 	dc_count = y2 - y1;
 
-	uint32_t solid_top = frontskytex->GetSWSkyCapColor(false);
-	uint32_t solid_bottom = frontskytex->GetSWSkyCapColor(true);
+	uint32_t solid_top = frontskytex->GetSkyCapColor(false);
+	uint32_t solid_bottom = frontskytex->GetSkyCapColor(true);
 
 	if (columns == 4)
 		if (!backskytex)
diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp
index f3c9e19a1..bc0eaffa3 100644
--- a/src/textures/texture.cpp
+++ b/src/textures/texture.cpp
@@ -591,9 +591,9 @@ namespace
 		}
 		for (i = 0; i < size; i++)
 		{
-			r += BPART(data[i]);
+			b += BPART(data[i]);
 			g += GPART(data[i]);
-			b += RPART(data[i]);
+			r += RPART(data[i]);
 		}
 
 		r = r / size;
@@ -612,7 +612,7 @@ namespace
 	}
 }
 
-PalEntry FTexture::GetSWSkyCapColor(bool bottom)
+PalEntry FTexture::GetSkyCapColor(bool bottom)
 {
 	PalEntry col;
 	int w;
@@ -631,15 +631,15 @@ PalEntry FTexture::GetSWSkyCapColor(bool bottom)
 		const uint32_t *buffer = (const uint32_t *)bitmap.GetPixels();
 		if (buffer)
 		{
-			SWCeilingSkyColor = averageColor((DWORD *)buffer, w * MIN(30, h), 0);
+			CeilingSkyColor = averageColor((DWORD *)buffer, w * MIN(30, h), 0);
 			if (h>30)
 			{
-				SWFloorSkyColor = averageColor(((DWORD *)buffer) + (h - 30)*w, w * 30, 0);
+				FloorSkyColor = averageColor(((DWORD *)buffer) + (h - 30)*w, w * 30, 0);
 			}
-			else SWFloorSkyColor = SWCeilingSkyColor;
+			else FloorSkyColor = CeilingSkyColor;
 		}
 	}
-	return bottom ? SWFloorSkyColor : SWCeilingSkyColor;
+	return bottom ? FloorSkyColor : CeilingSkyColor;
 }
 
 
diff --git a/src/textures/textures.h b/src/textures/textures.h
index 9402417f7..ad1d9ba8c 100644
--- a/src/textures/textures.h
+++ b/src/textures/textures.h
@@ -239,7 +239,7 @@ public:
 	}
 
 	void SetScaledSize(int fitwidth, int fitheight);
-	PalEntry GetSWSkyCapColor(bool bottom);
+	PalEntry GetSkyCapColor(bool bottom);
 
 	virtual void HackHack (int newheight);	// called by FMultipatchTexture to discover corrupt patches.
 
@@ -262,8 +262,8 @@ protected:
 
 private:
 	bool bSWSkyColorDone = false;
-	PalEntry SWFloorSkyColor;
-	PalEntry SWCeilingSkyColor;
+	PalEntry FloorSkyColor;
+	PalEntry CeilingSkyColor;
 
 public:
 	static void FlipSquareBlock (BYTE *block, int x, int y);

From 4b956a2f2b4ac964c96fb37b68f9d7fd9657a68d Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <c.oelckers@zdoom.fake>
Date: Thu, 20 Oct 2016 09:56:45 +0200
Subject: [PATCH 8/8] - added support for the skyoffset property that had been
 settable in ANIMDEFS for GZDoom. This will only have an effect in sky mode 2.

---
 src/r_sky.cpp | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/r_sky.cpp b/src/r_sky.cpp
index 58caa09bd..37312cbae 100644
--- a/src/r_sky.cpp
+++ b/src/r_sky.cpp
@@ -48,6 +48,11 @@ bool		skystretch;
 fixed_t		sky1cyl,		sky2cyl;
 double		sky1pos,		sky2pos;
 
+CUSTOM_CVAR(Int, testskyoffset, 0, 0)
+{
+	R_InitSkyMap();
+}
+
 // [RH] Stretch sky texture if not taller than 128 pixels?
 // Also now controls capped skies. 0 = normal, 1 = stretched, 2 = capped
 CUSTOM_CVAR (Int, r_skymode, 2, CVAR_ARCHIVE)
@@ -55,6 +60,7 @@ CUSTOM_CVAR (Int, r_skymode, 2, CVAR_ARCHIVE)
 	R_InitSkyMap ();
 }
 
+
 int			freelookviewheight;
 
 //==========================================================================
@@ -108,7 +114,7 @@ void R_InitSkyMap ()
 	}
 	else if (skyheight > 200)
 	{
-		skytexturemid = (200 - skyheight) * skytex1->Scale.Y;
+		skytexturemid = (200 - skyheight) * skytex1->Scale.Y +(r_skymode == 2 ? skytex1->SkyOffset + testskyoffset : 0);
 	}
 
 	if (viewwidth != 0 && viewheight != 0)