From 18c1a3abe5f7c9ca48d7f14af30492b500861b56 Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@users.noreply.github.com>
Date: Fri, 7 Dec 2018 00:58:37 +0100
Subject: [PATCH] - make the FWarpTexture class local to the software renderer.

This class has only meaning for software-based warping so it doesn't have to be a part of the FTexture hierarchy.
Making it a subclass of FSoftwareTexture is fully sufficient.
---
 src/CMakeLists.txt                            |  2 +-
 src/hwrenderer/textures/hw_material.cpp       |  1 -
 src/swrenderer/line/r_line.cpp                |  1 +
 src/swrenderer/textures/r_swtexture.cpp       |  2 +-
 src/swrenderer/textures/r_swtexture.h         | 38 +++++++++-
 src/{ => swrenderer}/textures/warpbuffer.h    |  0
 .../textures}/warptexture.cpp                 | 70 +++++--------------
 src/textures/animations.cpp                   |  8 +--
 src/textures/formats/worldtexture.cpp         |  4 --
 src/textures/texture.cpp                      |  6 --
 src/textures/textures.h                       | 37 +---------
 11 files changed, 64 insertions(+), 105 deletions(-)
 rename src/{ => swrenderer}/textures/warpbuffer.h (100%)
 rename src/{textures/formats => swrenderer/textures}/warptexture.cpp (63%)

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2a0d2a413b..035e2016c6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1118,7 +1118,6 @@ set (PCH_SOURCES
 	textures/formats/shadertexture.cpp
 	textures/formats/tgatexture.cpp
 	textures/formats/worldtexture.cpp
-	textures/formats/warptexture.cpp
 	textures/hires/hqresize.cpp
 	textures/hires/hirestex.cpp
 	xlat/parse_xlat.cpp
@@ -1246,6 +1245,7 @@ set (PCH_SOURCES
 	sound/wildmidi/wildmidi_lib.cpp
 	sound/wildmidi/wm_error.cpp
 	swrenderer/textures/r_swtexture.cpp
+	swrenderer/textures/warptexture.cpp
 	events.cpp
 )
 
diff --git a/src/hwrenderer/textures/hw_material.cpp b/src/hwrenderer/textures/hw_material.cpp
index 6f0e3eecab..530be94580 100644
--- a/src/hwrenderer/textures/hw_material.cpp
+++ b/src/hwrenderer/textures/hw_material.cpp
@@ -167,7 +167,6 @@ FMaterial::FMaterial(FTexture * tx, bool expanded)
 	else if (tx->isWarped())
 	{
 		mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2
-		tx->shaderspeed = static_cast<FWarpTexture*>(tx)->GetSpeed();
 	}
 	else if (tx->isHardwareCanvas())
 	{
diff --git a/src/swrenderer/line/r_line.cpp b/src/swrenderer/line/r_line.cpp
index ddb291c360..f77971a289 100644
--- a/src/swrenderer/line/r_line.cpp
+++ b/src/swrenderer/line/r_line.cpp
@@ -941,6 +941,7 @@ namespace swrenderer
 		
 		FTexture *tex = TexMan(sidedef->GetTexture(side_t::bottom), true);;
 		mBottomPart.Texture = tex && tex->isValid() ? tex->GetSoftwareTexture() : nullptr;
+		if (!mBottomPart.Texture) return;
 
 		mBottomPart.TextureOffsetU = FLOAT2FIXED(sidedef->GetTextureXOffset(side_t::bottom));
 		double rowoffset = sidedef->GetTextureYOffset(side_t::bottom);
diff --git a/src/swrenderer/textures/r_swtexture.cpp b/src/swrenderer/textures/r_swtexture.cpp
index 8a389f44a4..67a48beefb 100644
--- a/src/swrenderer/textures/r_swtexture.cpp
+++ b/src/swrenderer/textures/r_swtexture.cpp
@@ -61,7 +61,7 @@ const uint32_t *FSoftwareTexture::GetColumnBgra(unsigned int column, const FSoft
 
 const uint32_t *FSoftwareTexture::GetPixelsBgra()
 {
-	if (PixelsBgra.empty() || mTexture->CheckModified(DefaultRenderStyle()))
+	if (PixelsBgra.empty() || CheckModified(DefaultRenderStyle()))
 	{
 		if (!GetColumn(DefaultRenderStyle(), 0, nullptr))
 			return nullptr;
diff --git a/src/swrenderer/textures/r_swtexture.h b/src/swrenderer/textures/r_swtexture.h
index a6aaa02bb0..3d350e9c50 100644
--- a/src/swrenderer/textures/r_swtexture.h
+++ b/src/swrenderer/textures/r_swtexture.h
@@ -12,8 +12,10 @@ struct FSoftwareTextureSpan
 // For now this is just a minimal wrapper around FTexture. Once the software renderer no longer accesses FTexture directly, it is time for cleaning up.
 class FSoftwareTexture
 {
+protected:
 	FTexture *mTexture;
 	FTexture *mSource;
+	uint8_t *Pixels[2];
 	std::vector<uint32_t> PixelsBgra;
 	FSoftwareTextureSpan **Spandata[2] = { nullptr, nullptr };
 
@@ -88,7 +90,7 @@ public:
 	DVector2 GetScale() const { return mTexture->Scale; }
 	
 	// Returns the whole texture, stored in column-major order
-	const uint8_t *GetPixels(FRenderStyle style)
+	virtual const uint8_t *GetPixels(FRenderStyle style)
 	{
 		return mTexture->GetPixels(style);
 	}
@@ -98,6 +100,11 @@ public:
 		mTexture->Unload();
 		PixelsBgra = std::vector<uint32_t>();
 	}
+	
+	// Returns true if the next call to GetPixels() will return an image different from the
+	// last call to GetPixels(). This should be considered valid only if a call to CheckModified()
+	// is immediately followed by a call to GetPixels().
+	virtual bool CheckModified (FRenderStyle style) { return false; }
 
 	void GenerateBgraFromBitmap(const FBitmap &bitmap);
 	void CreatePixelsBgraWithMipmaps();
@@ -121,9 +128,36 @@ public:
 	
 };
 
+// A texture that returns a wiggly version of another texture.
+class FWarpTexture : public FSoftwareTexture
+{
+	TArray<uint8_t> WarpedPixels[2];
+	int bWarped = 0;
+public:
+	FWarpTexture (FTexture *source, int warptype);
+
+	const uint32_t *GetPixelsBgra() override;
+	bool CheckModified (FRenderStyle) override;
+
+	float GetSpeed() const { return mTexture->shaderspeed; }
+
+	uint64_t GenTime[2] = { 0, 0 };
+	uint64_t GenTimeBgra = 0;
+	int WidthOffsetMultiplier, HeightOffsetMultiplier;  // [mxd]
+protected:
+
+	const uint8_t *GetPixels(FRenderStyle style);
+	int NextPo2 (int v); // [mxd]
+	void SetupMultipliers (int width, int height); // [mxd]
+};
+
 
 inline FSoftwareTexture *FTexture::GetSoftwareTexture()
 {
-	if (!SoftwareTexture) SoftwareTexture = new FSoftwareTexture(this);
+	if (!SoftwareTexture)
+	{
+		if (bWarped) SoftwareTexture = new FWarpTexture(this, bWarped);
+		else SoftwareTexture = new FSoftwareTexture(this);
+	}
 	return SoftwareTexture;
 }
diff --git a/src/textures/warpbuffer.h b/src/swrenderer/textures/warpbuffer.h
similarity index 100%
rename from src/textures/warpbuffer.h
rename to src/swrenderer/textures/warpbuffer.h
diff --git a/src/textures/formats/warptexture.cpp b/src/swrenderer/textures/warptexture.cpp
similarity index 63%
rename from src/textures/formats/warptexture.cpp
rename to src/swrenderer/textures/warptexture.cpp
index a19c5b284b..41f563ed4c 100644
--- a/src/textures/formats/warptexture.cpp
+++ b/src/swrenderer/textures/warptexture.cpp
@@ -4,6 +4,7 @@
 **
 **---------------------------------------------------------------------------
 ** Copyright 2004-2006 Randy Heit
+** Copyright 2006-2018 Christoph Oelckers
 ** All rights reserved.
 **
 ** Redistribution and use in source and binary forms, with or without
@@ -35,46 +36,31 @@
 
 #include "doomtype.h"
 #include "r_utility.h"
-#include "textures/textures.h"
+#include "r_swtexture.h"
 #include "warpbuffer.h"
 #include "v_video.h"
 
 
 FWarpTexture::FWarpTexture (FTexture *source, int warptype)
-	: SourcePic (source)
+	: FSoftwareTexture (source)
 {
-	CopyInfo(source);
 	if (warptype == 2) SetupMultipliers(256, 128); 
 	SetupMultipliers(128, 128); // [mxd]
 	bWarped = warptype;
 }
 
-FWarpTexture::~FWarpTexture ()
-{
-	Unload ();
-	delete SourcePic;
-}
-
-void FWarpTexture::Unload ()
-{
-	SourcePic->Unload ();
-	FWorldTexture::Unload();
-	//FreeAllSpans();
-}
-
 bool FWarpTexture::CheckModified (FRenderStyle style)
 {
 	return screen->FrameTime != GenTime[!!(style.Flags & STYLEF_RedIsAlpha)];
 }
 
-/*
 const uint32_t *FWarpTexture::GetPixelsBgra()
 {
 	auto Pixels = GetPixels(DefaultRenderStyle());
 	if (PixelsBgra.empty() || GenTime[0] != GenTimeBgra)
 	{
 		CreatePixelsBgraWithMipmaps();
-		for (int i = 0; i < Width * Height; i++)
+		for (int i = 0; i < GetWidth() * GetHeight(); i++)
 		{
 			if (Pixels[i] != 0)
 				PixelsBgra[i] = 0xff000000 | GPalette.BaseColors[Pixels[i]].d;
@@ -86,18 +72,21 @@ const uint32_t *FWarpTexture::GetPixelsBgra()
 	}
 	return PixelsBgra.data();
 }
-*/
 
 
-uint8_t *FWarpTexture::MakeTexture(FRenderStyle style)
+const uint8_t *FWarpTexture::GetPixels(FRenderStyle style)
 {
+	int index = !!(style.Flags & STYLEF_RedIsAlpha);
 	uint64_t time = screen->FrameTime;
-	const uint8_t *otherpix = SourcePic->GetPixels(style);
-	auto Pixels = new uint8_t[Width * Height];
-	WarpBuffer(Pixels, otherpix, Width, Height, WidthOffsetMultiplier, HeightOffsetMultiplier, time, Speed, bWarped);
-	//FreeAllSpans();
-	GenTime[!!(style.Flags & STYLEF_RedIsAlpha)] = time;
-	return Pixels;
+	if (time != GenTime[index])
+	{
+		const uint8_t *otherpix = FSoftwareTexture::GetPixels(style);
+		WarpedPixels[index].Resize(GetWidth() * GetHeight());
+		WarpBuffer(WarpedPixels[index].Data(), otherpix, GetWidth(), GetHeight(), WidthOffsetMultiplier, HeightOffsetMultiplier, time, mTexture->shaderspeed, bWarped);
+		FreeAllSpans();
+		GenTime[index] = time;
+	}
+	return WarpedPixels[index].Data();
 }
 
 // [mxd] Non power of 2 textures need different offset multipliers, otherwise warp animation won't sync across texture
@@ -105,10 +94,10 @@ void FWarpTexture::SetupMultipliers (int width, int height)
 {
 	WidthOffsetMultiplier = width;
 	HeightOffsetMultiplier = height;
-	int widthpo2 = NextPo2(Width);
-	int heightpo2 = NextPo2(Height);
-	if(widthpo2 != Width) WidthOffsetMultiplier = (int)(WidthOffsetMultiplier * ((float)widthpo2 / Width));
-	if(heightpo2 != Height) HeightOffsetMultiplier = (int)(HeightOffsetMultiplier * ((float)heightpo2 / Height));
+	int widthpo2 = NextPo2(GetWidth());
+	int heightpo2 = NextPo2(GetHeight());
+	if(widthpo2 != GetWidth()) WidthOffsetMultiplier = (int)(WidthOffsetMultiplier * ((float)widthpo2 / GetWidth()));
+	if(heightpo2 != GetHeight()) HeightOffsetMultiplier = (int)(HeightOffsetMultiplier * ((float)heightpo2 / GetHeight()));
 }
 
 int FWarpTexture::NextPo2 (int v)
@@ -121,24 +110,3 @@ int FWarpTexture::NextPo2 (int v)
 	v |= v >> 16;
 	return ++v;
 }
-
-//==========================================================================
-//
-// FMultiPatchTexture :: CopyTrueColorPixels
-//
-// True color texture generation must never hit the paletted path which
-// always warps the buffer.
-// As a result even CopyTrueColorTranslated must be overrideen here.
-//
-//==========================================================================
-
-int FWarpTexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate, FCopyInfo *inf)
-{
-	return SourcePic->CopyTrueColorPixels(bmp, x, y, rotate, inf);
-}
-
-int FWarpTexture::CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, PalEntry *remap, FCopyInfo *inf)
-{
-	return SourcePic->CopyTrueColorTranslated(bmp, x, y, rotate, remap, inf);
-}
-
diff --git a/src/textures/animations.cpp b/src/textures/animations.cpp
index 7ac07fb257..031a940e7a 100644
--- a/src/textures/animations.cpp
+++ b/src/textures/animations.cpp
@@ -226,8 +226,7 @@ void FTextureManager::InitAnimated (void)
 			// SMMU-style swirly hack? Don't apply on already-warping texture
 			if (animspeed > 65535 && tex1 != NULL && !tex1->isWarped())
 			{
-				FTexture *warper = new FWarpTexture (tex1, 2);
-				ReplaceTexture (pic1, warper, false);
+				tex1->bWarped = 2;
 			}
 			// These tests were not really relevant for swirling textures, or even potentially
 			// harmful, so they have been moved to the else block.
@@ -624,13 +623,12 @@ void FTextureManager::ParseWarp(FScanner &sc)
 		// don't warp a texture more than once
 		if (!warper->isWarped())
 		{
-			warper = new FWarpTexture (warper, type2? 2:1);
-			ReplaceTexture (picnum, warper, false);
+			warper->bWarped = type2? 2:1;
 		}
 
 		if (sc.CheckFloat())
 		{
-			static_cast<FWarpTexture*>(warper)->SetSpeed(float(sc.Float));
+			warper->SetSpeed(float(sc.Float));
 		}
 
 		// No decals on warping textures, by default.
diff --git a/src/textures/formats/worldtexture.cpp b/src/textures/formats/worldtexture.cpp
index e409ae5120..6613265fda 100644
--- a/src/textures/formats/worldtexture.cpp
+++ b/src/textures/formats/worldtexture.cpp
@@ -85,10 +85,6 @@ void FWorldTexture::Unload ()
 
 const uint8_t *FWorldTexture::GetPixels (FRenderStyle style)
 {
-	if (CheckModified(style))
-	{
-		Unload();
-	}
 	int index = !!(style.Flags & STYLEF_RedIsAlpha);
 	if (Pixeldata[index] == nullptr)
 	{
diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp
index ef948fc769..6cfb04c196 100644
--- a/src/textures/texture.cpp
+++ b/src/textures/texture.cpp
@@ -45,7 +45,6 @@
 #include "c_dispatch.h"
 #include "v_video.h"
 #include "m_fixed.h"
-#include "textures/warpbuffer.h"
 #include "hwrenderer/textures/hw_material.h"
 #include "hwrenderer/textures/hw_ihwtexture.h"
 
@@ -239,11 +238,6 @@ void FTexture::Unload()
 //
 //==========================================================================
 
-bool FTexture::CheckModified (FRenderStyle)
-{
-	return false;
-}
-
 FTextureFormat FTexture::GetFormat()
 {
 	return TEX_Pal;
diff --git a/src/textures/textures.h b/src/textures/textures.h
index b703e00f51..32e989afa5 100644
--- a/src/textures/textures.h
+++ b/src/textures/textures.h
@@ -382,6 +382,7 @@ protected:
 	int shaderindex = 0;
 
 
+
 	// Returns the whole texture, stored in column-major order
 	virtual const uint8_t *GetPixels(FRenderStyle style);
 
@@ -400,6 +401,7 @@ protected:
 
 	// Fill the native texture buffer with pixel data for this image
 	virtual void FillBuffer(uint8_t *buff, int pitch, int height, FTextureFormat fmt);
+	void SetSpeed(float fac) { shaderspeed = fac; }
 
 	int GetWidth () { return Width; }
 	int GetHeight () { return Height; }
@@ -443,11 +445,6 @@ protected:
 
 	void CopyToBlock (uint8_t *dest, int dwidth, int dheight, int x, int y, int rotate, const uint8_t *translation, FRenderStyle style);
 
-	// Returns true if the next call to GetPixels() will return an image different from the
-	// last call to GetPixels(). This should be considered valid only if a call to CheckModified()
-	// is immediately followed by a call to GetPixels().
-	virtual bool CheckModified (FRenderStyle style);
-
 	static void InitGrayMap();
 
 	void CopySize(FTexture *BaseTexture)
@@ -770,34 +767,6 @@ public:
 	void SetSize (int width, int height);
 };
 
-// A texture that returns a wiggly version of another texture.
-class FWarpTexture : public FWorldTexture
-{
-public:
-	FWarpTexture (FTexture *source, int warptype);
-	~FWarpTexture ();
-	void Unload() override;
-
-	virtual int CopyTrueColorPixels(FBitmap *bmp, int x, int y, int rotate=0, FCopyInfo *inf = NULL) override;
-	virtual int CopyTrueColorTranslated(FBitmap *bmp, int x, int y, int rotate, PalEntry *remap, FCopyInfo *inf = NULL) override;
-	//const uint32_t *GetPixelsBgra() override;
-	bool CheckModified (FRenderStyle) override;
-
-	float GetSpeed() const { return Speed; }
-	int GetSourceLump() { return SourcePic->GetSourceLump(); }
-	void SetSpeed(float fac) { Speed = fac; }
-
-	uint64_t GenTime[2] = { 0, 0 };
-	uint64_t GenTimeBgra = 0;
-	float Speed = 1.f;
-	int WidthOffsetMultiplier, HeightOffsetMultiplier;  // [mxd]
-protected:
-	FTexture *SourcePic;
-
-	uint8_t *MakeTexture (FRenderStyle style) override;
-	int NextPo2 (int v); // [mxd]
-	void SetupMultipliers (int width, int height); // [mxd]
-};
 
 // A texture that can be drawn to.
 class DCanvas;
@@ -814,7 +783,7 @@ public:
 
 	const uint8_t *GetPixels (FRenderStyle style);
 	void Unload ();
-	bool CheckModified (FRenderStyle) override;
+	bool CheckModified (FRenderStyle) /*override*/;
 	void NeedUpdate() { bNeedsUpdate=true; }
 	void SetUpdated() { bNeedsUpdate = false; bDidUpdate = true; bFirstUpdate = false; }
 	DCanvas *GetCanvas() { return Canvas; }