Skip to content

Commit

Permalink
fixed: Multipatch textures may not set up their patch references unti…
Browse files Browse the repository at this point in the history
…l all textures have been loaded.

If done earlier they will not be able to detect overrides of sprites and graphics which are not part of the PATCHES lump. There was some fudging code to work around this problem but it was only partially working.
Now these textures only collect the texture name and use type during setup and resolve them after all textures have been created.
  • Loading branch information
IgeNiaI committed Nov 29, 2022
1 parent a69e4f3 commit 7b0700d
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 95 deletions.
203 changes: 108 additions & 95 deletions src/textures/multipatchtexture.cpp
Expand Up @@ -47,6 +47,7 @@
#include "colormatcher.h"
#include "v_palette.h"
#include "v_video.h"
#include "cmdlib.h"
#include "m_fixed.h"
#include "textures/textures.h"
#include "r_data/colormaps.h"
Expand Down Expand Up @@ -137,7 +138,6 @@ struct strifemaptexture_t
struct FPatchLookup
{
char Name[9];
FTexture *Texture;
};


Expand Down Expand Up @@ -165,6 +165,7 @@ class FMultiPatchTexture : public FTexture
int GetSourceLump() { return DefinitionLump; }
FTexture *GetRedirect(bool wantwarped);
FTexture *GetRawTexture();
void ResolvePatches();

protected:
BYTE *Pixels;
Expand All @@ -183,17 +184,29 @@ class FMultiPatchTexture : public FTexture

TexPart();
};

struct TexInit
{
FString TexName;
int UseType = TEX_Null;
TexInit *Inits;
bool Silent = false;
bool HasLine = false;
FScriptPosition sc;
};


int NumParts;
TexPart *Parts;
TexInit *Inits;
bool bRedirect:1;
bool bTranslucentPatches:1;

void MakeTexture ();

private:
void CheckForHacks ();
void ParsePatch(FScanner &sc, TexPart & part, bool silent, int usetype);
void ParsePatch(FScanner &sc, TexPart & part, TexInit &init);
};

//==========================================================================
Expand All @@ -203,7 +216,7 @@ class FMultiPatchTexture : public FTexture
//==========================================================================

FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchlookup, int maxpatchnum, bool strife, int deflumpnum)
: Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false)
: Pixels (0), Spans(0), Parts(nullptr), Inits(nullptr), bRedirect(false), bTranslucentPatches(false)
{
union
{
Expand Down Expand Up @@ -239,7 +252,8 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl
}

UseType = FTexture::TEX_Wall;
Parts = NumParts > 0 ? new TexPart[NumParts] : NULL;
Parts = NumParts > 0 ? new TexPart[NumParts] : nullptr;
Inits = NumParts > 0 ? new TexInit[NumParts] : nullptr;
Width = SAFESHORT(mtexture.d->width);
Height = SAFESHORT(mtexture.d->height);
strncpy (Name, (const char *)mtexture.d->name, 8);
Expand Down Expand Up @@ -272,17 +286,9 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl
}
Parts[i].OriginX = LittleShort(mpatch.d->originx);
Parts[i].OriginY = LittleShort(mpatch.d->originy);
Parts[i].Texture = patchlookup[LittleShort(mpatch.d->patch)].Texture;
if (Parts[i].Texture == NULL)
{
Printf ("Unknown patch %s in texture %s\n", patchlookup[LittleShort(mpatch.d->patch)].Name, Name);
NumParts--;
i--;
}
else
{
Parts[i].Texture->bKeepAround = true;
}
Parts[i].Texture = nullptr;
Inits[i].TexName = patchlookup[LittleShort(mpatch.d->patch)].Name;
Inits[i].UseType = TEX_WallPatch;
if (strife)
mpatch.s++;
else
Expand All @@ -295,17 +301,6 @@ FMultiPatchTexture::FMultiPatchTexture (const void *texdef, FPatchLookup *patchl

CheckForHacks ();

// If this texture is just a wrapper around a single patch, we can simply
// forward GetPixels() and GetColumn() calls to that patch.
if (NumParts == 1)
{
if (Parts->OriginX == 0 && Parts->OriginY == 0 &&
Parts->Texture->GetWidth() == Width &&
Parts->Texture->GetHeight() == Height)
{
bRedirect = true;
}
}
DefinitionLump = deflumpnum;
}

Expand All @@ -327,6 +322,11 @@ FMultiPatchTexture::~FMultiPatchTexture ()
delete[] Parts;
Parts = NULL;
}
if (Inits != nullptr)
{
delete[] Inits;
Inits = nullptr;
}
if (Spans != NULL)
{
FreeSpans (Spans);
Expand Down Expand Up @@ -862,19 +862,6 @@ void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int d
{
pnames.Read (patchlookup[i].Name, 8);
patchlookup[i].Name[8] = 0;
FTextureID j = CheckForTexture (patchlookup[i].Name, FTexture::TEX_WallPatch);
if (j.isValid())
{
patchlookup[i].Texture = Textures[j.GetIndex()].Texture;
}
else
{
// Shareware Doom has the same PNAMES lump as the registered
// Doom, so printing warnings for patches that don't really
// exist isn't such a good idea.
//Printf ("Patch %s not found.\n", patchlookup[i].Name);
patchlookup[i].Texture = NULL;
}
}
}

Expand Down Expand Up @@ -991,49 +978,13 @@ void FTextureManager::AddTexturesLumps (int lump1, int lump2, int patcheslump)
//
//==========================================================================

void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, bool silent, int usetype)
void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init)
{
FString patchname;
sc.MustGetString();

FTextureID texno = TexMan.CheckForTexture(sc.String, usetype);
int Mirror = 0;
sc.MustGetString();

if (!texno.isValid())
{
int lumpnum = Wads.CheckNumForFullName(sc.String);
if (lumpnum >= 0)
{
texno = TexMan.FindTextureByLumpNum(lumpnum);
if (texno.isValid ())
{
part.Texture = TexMan[texno];
}
else
{
part.Texture = FTexture::CreateTexture("", lumpnum, usetype);
TexMan.AddTexture(part.Texture);
}
}
else if (strlen(sc.String) <= 8 && !strpbrk(sc.String, "./"))
{
int lumpnum = Wads.CheckNumForName(sc.String, usetype == TEX_MiscPatch? ns_graphics : ns_patches);
if (lumpnum >= 0)
{
part.Texture = FTexture::CreateTexture(lumpnum, usetype);
TexMan.AddTexture(part.Texture);
}
}
}
else
{
part.Texture = TexMan[texno];
bComplex |= part.Texture->bComplex;
}
if (part.Texture == NULL)
{
if (!silent) Printf("Unknown patch '%s' in texture '%s'\n", sc.String, Name);
}
init.TexName = sc.String;
sc.MustGetStringName(",");
sc.MustGetNumber();
part.OriginX = sc.Number;
Expand Down Expand Up @@ -1216,6 +1167,7 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
: Pixels (0), Spans(0), Parts(0), bRedirect(false), bTranslucentPatches(false)
{
TArray<TexPart> parts;
TArray<TexInit> inits;
bool bSilent = false;

bMultiPatch = true;
Expand Down Expand Up @@ -1276,16 +1228,34 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
else if (sc.Compare("Patch"))
{
TexPart part;
ParsePatch(sc, part, bSilent, TEX_WallPatch);
if (part.Texture != NULL) parts.Push(part);
TexInit init;
ParsePatch(sc, part, init);
if (init.TexName.IsNotEmpty())
{
parts.Push(part);
init.UseType = TEX_WallPatch;
init.Silent = bSilent;
init.HasLine = true;
init.sc = sc;
inits.Push(init);
}
part.Texture = NULL;
part.Translation = NULL;
}
else if (sc.Compare("Graphic"))
{
TexPart part;
ParsePatch(sc, part, bSilent, TEX_MiscPatch);
if (part.Texture != NULL) parts.Push(part);
TexInit init;
ParsePatch(sc, part, init);
if (init.TexName.IsNotEmpty())
{
parts.Push(part);
init.UseType = TEX_MiscPatch;
init.Silent = bSilent;
init.HasLine = true;
init.sc = sc;
inits.Push(init);
}
part.Texture = NULL;
part.Translation = NULL;
}
Expand All @@ -1307,20 +1277,10 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
Parts = new TexPart[NumParts];
memcpy(Parts, &parts[0], NumParts * sizeof(*Parts));

//CalcBitSize ();

// If this texture is just a wrapper around a single patch, we can simply
// forward GetPixels() and GetColumn() calls to that patch.
if (NumParts == 1)
Inits = new TexInit[NumParts];
for (int i = 0; i < NumParts; i++)
{
if (Parts->OriginX == 0 && Parts->OriginY == 0 &&
Parts->Texture->GetWidth() == Width &&
Parts->Texture->GetHeight() == Height &&
Parts->Rotate == 0 &&
!bComplex)
{
bRedirect = true;
}
Inits[i] = inits[i];
}
}

Expand All @@ -1337,6 +1297,59 @@ FMultiPatchTexture::FMultiPatchTexture (FScanner &sc, int usetype)
}


void FMultiPatchTexture::ResolvePatches()
{
if (Inits != nullptr)
{
for (int i = 0; i < NumParts; i++)
{
FTextureID texno = TexMan.CheckForTexture(Inits[i].TexName, Inits[i].UseType);

if (!texno.isValid())
{
if (!Inits[i].Silent)
{
if (Inits[i].HasLine) Inits[i].sc.Message(MSG_WARNING, "Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name);
else Printf("Unknown patch '%s' in texture '%s'\n", Inits[i].TexName.GetChars(), Name);
}
}
else
{
Parts[i].Texture = TexMan[texno];
bComplex |= Parts[i].Texture->bComplex;
Parts[i].Texture->bKeepAround = true;
}
}
for (int i = 0; i < NumParts; i++)
{
if (Parts[i].Texture == nullptr)
{
memcpy(&Parts[i], &Parts[i + 1], NumParts - i - 1);
i--;
NumParts--;
}
}
}
delete[] Inits;
Inits = nullptr;

// If this texture is just a wrapper around a single patch, we can simply
// forward GetPixels() and GetColumn() calls to that patch.

if (NumParts == 1)
{
if (Parts->OriginX == 0 && Parts->OriginY == 0 &&
Parts->Texture->GetWidth() == Width &&
Parts->Texture->GetHeight() == Height &&
Parts->Rotate == 0 &&
!bComplex)
{
bRedirect = true;
}
}
}



void FTextureManager::ParseXTexture(FScanner &sc, int usetype)
{
Expand Down
4 changes: 4 additions & 0 deletions src/textures/texturemanager.cpp
Expand Up @@ -978,6 +978,10 @@ void FTextureManager::Init()
{
AddTexturesForWad(i);
}
for (unsigned i = 0; i < Textures.Size(); i++)
{
Textures[i].Texture->ResolvePatches();
}

// Add one marker so that the last WAD is easier to handle and treat
// Build tiles as a completely separate block.
Expand Down
1 change: 1 addition & 0 deletions src/textures/textures.h
Expand Up @@ -268,6 +268,7 @@ class FTexture
int GetScaledTopOffset () { int foo = (TopOffset << 17) / yScale; return (foo >> 1) + (foo & 1); }
double GetScaledLeftOffsetDouble() { return (LeftOffset * 65536.) / xScale; }
double GetScaledTopOffsetDouble() { return (TopOffset * 65536.) / yScale; }
virtual void ResolvePatches() {}

virtual void SetFrontSkyLayer();

Expand Down

0 comments on commit 7b0700d

Please sign in to comment.