- made the necessary adjustments to the HW2D interfaces to handle alpha textures properly.

These cannot be done with the regular textures so there needs to be an option to create more than one native texture per FTexture. For completeness' sake there is also the option now to create a paletted version of a texture if the regular one is true color. This fixes a long standing problem that translations were not applied to non-paletted textures.
This commit is contained in:
Christoph Oelckers 2018-03-23 23:04:30 +01:00
parent 3c6b09b3a1
commit 7301001a3f
9 changed files with 87 additions and 106 deletions

View file

@ -2050,7 +2050,8 @@ void OpenGLSWFrameBuffer::Atlas::FreeBox(OpenGLSWFrameBuffer::PackedTexture *box
//
//==========================================================================
OpenGLSWFrameBuffer::OpenGLTex::OpenGLTex(FTexture *tex, OpenGLSWFrameBuffer *fb, bool wrapping)
OpenGLSWFrameBuffer::OpenGLTex::OpenGLTex(FTexture *tex, FTextureFormat fmt, OpenGLSWFrameBuffer *fb, bool wrapping)
: FNativeTexture(tex, fmt)
{
// Attach to the texture list for the OpenGLSWFrameBuffer
Next = fb->Textures;
@ -2090,7 +2091,7 @@ OpenGLSWFrameBuffer::OpenGLTex::~OpenGLTex()
// Remove link from the game texture
if (GameTex != nullptr)
{
GameTex->Native = nullptr;
mGameTex->Native[mFormat] = nullptr;
}
}
@ -2199,7 +2200,7 @@ bool OpenGLSWFrameBuffer::OpenGLTex::Update()
{
dest += pitch + (format == GL_R8 ? 1 : 4);
}
GameTex->FillBuffer(dest, pitch, GameTex->GetHeight(), ToTexFmt(format));
GameTex->FillBuffer(dest, pitch, GameTex->GetHeight(), mFormat);
if (Box->Padded)
{
// Clear top padding row.
@ -2265,50 +2266,25 @@ bool OpenGLSWFrameBuffer::OpenGLTex::Update()
int OpenGLSWFrameBuffer::OpenGLTex::GetTexFormat()
{
FTextureFormat fmt = GameTex->GetFormat();
IsGray = false;
switch (fmt)
switch (mFormat)
{
case TEX_Pal: return GL_R8;
case TEX_Gray: IsGray = true; return GL_R8;
case TEX_RGB: return GL_RGBA8;
#if 0
case TEX_DXT1: return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
case TEX_DXT2: return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
case TEX_DXT3: return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
case TEX_DXT4: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; // Doesn't exist in OpenGL. Closest match is DXT5.
case TEX_DXT5: return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
#endif
default: I_FatalError("GameTex->GetFormat() returned invalid format.");
}
return GL_R8;
}
//==========================================================================
//
// OpenGLTex :: ToTexFmt
//
// Converts an OpenGL internal format constant to something the FTexture system
// understands.
//
//==========================================================================
FTextureFormat OpenGLSWFrameBuffer::OpenGLTex::ToTexFmt(int fmt)
{
switch (fmt)
{
case GL_R8: return IsGray ? TEX_Gray : TEX_Pal;
case GL_RGBA8: return TEX_RGB;
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return TEX_DXT1;
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: return TEX_DXT2;
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return TEX_DXT3;
case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return TEX_DXT5;
default:
assert(0); // LOL WUT?
return TEX_Pal;
}
}
//==========================================================================
//
// OpenGLPal Constructor
@ -2540,9 +2516,9 @@ void OpenGLSWFrameBuffer::DrawBlendingRect()
//
//==========================================================================
FNativeTexture *OpenGLSWFrameBuffer::CreateTexture(FTexture *gametex, bool wrapping)
FNativeTexture *OpenGLSWFrameBuffer::CreateTexture(FTexture *gametex, FTextureFormat fmt, bool wrapping)
{
OpenGLTex *tex = new OpenGLTex(gametex, this, wrapping);
OpenGLTex *tex = new OpenGLTex(gametex, fmt, this, wrapping);
if (tex->Box == nullptr)
{
delete tex;
@ -2767,7 +2743,12 @@ void OpenGLSWFrameBuffer::DrawTextureParms(FTexture *img, DrawParms &parms)
return;
}
OpenGLTex *tex = static_cast<OpenGLTex *>(img->GetNative(false));
FTextureFormat fmt;
if (parms.style.Flags & STYLEF_RedIsAlpha) fmt = TEX_Gray;
else if (parms.remap != nullptr) fmt = TEX_Pal;
else fmt = img->GetFormat();
OpenGLTex *tex = static_cast<OpenGLTex *>(img->GetNative(fmt, false));
if (tex == nullptr)
{
@ -2944,7 +2925,7 @@ void OpenGLSWFrameBuffer::FlatFill(int left, int top, int right, int bottom, FTe
{
return;
}
OpenGLTex *tex = static_cast<OpenGLTex *>(src->GetNative(true));
OpenGLTex *tex = static_cast<OpenGLTex *>(src->GetNative(src->GetFormat(), true));
if (tex == nullptr)
{
return;
@ -3069,7 +3050,7 @@ void OpenGLSWFrameBuffer::FillSimplePoly(FTexture *texture, FVector2 *points, in
{
return;
}
tex = static_cast<OpenGLTex *>(texture->GetNative(true));
tex = static_cast<OpenGLTex *>(texture->GetNative(texture->GetFormat(), true));
if (tex == nullptr)
{
return;

View file

@ -49,7 +49,7 @@ public:
void SetBlendingRect(int x1, int y1, int x2, int y2) override;
bool Begin2D(bool copy3d) override;
void DrawBlendingRect() override;
FNativeTexture *CreateTexture(FTexture *gametex, bool wrapping) override;
FNativeTexture *CreateTexture(FTexture *gametex, FTextureFormat fmt, bool wrapping) override;
FNativePalette *CreatePalette(FRemapTable *remap) override;
void DrawTextureParms(FTexture *img, DrawParms &parms) override;
void DoClear(int left, int top, int right, int bottom, int palcolor, uint32_t color) override;
@ -265,7 +265,7 @@ private:
class OpenGLTex : public FNativeTexture
{
public:
OpenGLTex(FTexture *tex, OpenGLSWFrameBuffer *fb, bool wrapping);
OpenGLTex(FTexture *tex, FTextureFormat fmt, OpenGLSWFrameBuffer *fb, bool wrapping);
~OpenGLTex();
FTexture *GameTex;
@ -280,7 +280,6 @@ private:
bool Update();
bool CheckWrapping(bool wrapping);
int GetTexFormat();
FTextureFormat ToTexFmt(int fmt);
};
class OpenGLPal : public FNativePalette

View file

@ -150,7 +150,7 @@ FTexture::FTexture (const char *name, int lumpnum)
WidthBits(0), HeightBits(0), Scale(1,1), SourceLump(lumpnum),
UseType(TEX_Any), bNoDecals(false), bNoRemap0(false), bWorldPanning(false),
bMasked(true), bAlphaTexture(false), bHasCanvas(false), bWarped(0), bComplex(false), bMultiPatch(false), bKeepAround(false),
Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0), WidthMask(0), Native(NULL)
Rotations(0xFFFF), SkyOffset(0), Width(0), Height(0), WidthMask(0)
{
id.SetInvalid();
if (name != NULL)
@ -711,34 +711,37 @@ void FTexture::FlipNonSquareBlockRemap (uint8_t *dst, const uint8_t *src, int x,
}
}
FNativeTexture *FTexture::GetNative(bool wrapping)
FNativeTexture *FTexture::GetNative(FTextureFormat fmt, bool wrapping)
{
if (Native != NULL)
if (Native[fmt] != NULL)
{
if (!Native->CheckWrapping(wrapping))
if (!Native[fmt]->CheckWrapping(wrapping))
{ // Texture's wrapping mode is not compatible.
// Destroy it and get a new one.
delete Native;
delete Native[fmt];
}
else
{
if (CheckModified(DefaultRenderStyle()))
{
Native->Update();
Native[fmt]->Update();
}
return Native;
return Native[fmt];
}
}
Native = screen->CreateTexture(this, wrapping);
return Native;
Native[fmt] = screen->CreateTexture(this, fmt, wrapping);
return Native[fmt];
}
void FTexture::KillNative()
{
if (Native != NULL)
for (auto &nat : Native)
{
delete Native;
Native = NULL;
if (nat != nullptr)
{
delete nat;
nat = nullptr;
}
}
}
@ -1000,4 +1003,7 @@ CCMD (printspans)
Printf ("\n");
}
}
#endif

View file

@ -159,15 +159,20 @@ enum FTextureFormat
TEX_Pal,
TEX_Gray,
TEX_RGB, // Actually ARGB
/*
TEX_DXT1,
TEX_DXT2,
TEX_DXT3,
TEX_DXT4,
TEX_DXT5,
*/
TEX_Count
};
class FNativeTexture;
// Base texture class
class FTexture
{
@ -257,7 +262,7 @@ public:
virtual FTextureFormat GetFormat();
// Returns a native 3D representation of the texture
FNativeTexture *GetNative(bool wrapping);
FNativeTexture *GetNative(FTextureFormat fmt, bool wrapping);
// Frees the native 3D representation of the texture
void KillNative();
@ -310,7 +315,7 @@ public:
protected:
uint16_t Width, Height, WidthMask;
static uint8_t GrayMap[256];
FNativeTexture *Native;
FNativeTexture *Native[TEX_Count] = { nullptr }; // keep a slot for each type, because some render modes do not work with the base texture
uint8_t *GetRemap(FRenderStyle style, bool srcisgrayscale = false)
{
if (style.Flags & STYLEF_RedIsAlpha)
@ -399,7 +404,7 @@ public:
static void FlipNonSquareBlockBgra (uint32_t *blockto, const uint32_t *blockfrom, int x, int y, int srcpitch);
static void FlipNonSquareBlockRemap (uint8_t *blockto, const uint8_t *blockfrom, int x, int y, int srcpitch, const uint8_t *remap);
friend class D3DTex;
friend class FNativeTexture;
friend class OpenGLSWFrameBuffer;
public:

View file

@ -973,6 +973,9 @@ void FFont::LoadTranslations()
// means all the characters of a font have a better chance of being packed
// into the same hardware texture.
//
// (Note that this is a rather dumb implementation. The atlasing should
// occur at a higher level, independently of the renderer being used.)
//
//==========================================================================
void FFont::Preload() const
@ -989,7 +992,7 @@ void FFont::Preload() const
FTexture *pic = GetChar(i, &foo);
if (pic != NULL)
{
pic->GetNative(false);
pic->GetNative(pic->GetFormat(), false);
}
}
}

View file

@ -1161,10 +1161,12 @@ void DFrameBuffer::DrawBlendingRect()
// DFrameBuffer :: CreateTexture
//
// Creates a native texture for a game texture, if supported.
// The hardware renderer does not use this interface because it is
// far too limited
//
//==========================================================================
FNativeTexture *DFrameBuffer::CreateTexture(FTexture *gametex, bool wrapping)
FNativeTexture *DFrameBuffer::CreateTexture(FTexture *gametex, FTextureFormat fmt, bool wrapping)
{
return NULL;
}
@ -1261,6 +1263,12 @@ FNativePalette::~FNativePalette()
FNativeTexture::~FNativeTexture()
{
// Remove link from the game texture
if (mGameTex != nullptr)
{
mGameTex->Native[mFormat] = nullptr;
}
}
bool FNativeTexture::CheckWrapping(bool wrapping)

View file

@ -53,6 +53,7 @@ void V_CalcCleanFacs (int designwidth, int designheight, int realwidth, int real
class FTexture;
struct FColormap;
enum FTextureFormat;
// TagItem definitions for DrawTexture. As far as I know, tag lists
// originated on the Amiga.
@ -336,7 +337,11 @@ protected:
// This class represents a native texture, as opposed to an FTexture.
class FNativeTexture
{
protected:
FTexture * mGameTex;
FTextureFormat mFormat;
public:
FNativeTexture(FTexture *tex, FTextureFormat fmt) : mGameTex(tex), mFormat(fmt) {}
virtual ~FNativeTexture();
virtual bool Update() = 0;
virtual bool CheckWrapping(bool wrapping);
@ -425,7 +430,7 @@ public:
virtual void DrawBlendingRect();
// Create a native texture from a game texture.
virtual FNativeTexture *CreateTexture(FTexture *gametex, bool wrapping);
virtual FNativeTexture *CreateTexture(FTexture *gametex, FTextureFormat fmt, bool wrapping);
// Create a palette texture from a remap/palette table.
virtual FNativePalette *CreatePalette(FRemapTable *remap);

View file

@ -128,10 +128,9 @@ struct D3DFB::Atlas
class D3DTex : public FNativeTexture
{
public:
D3DTex(FTexture *tex, D3DFB *fb, bool wrapping);
D3DTex(FTexture *tex, FTextureFormat fmt, D3DFB *fb, bool wrapping);
~D3DTex();
FTexture *GameTex;
D3DFB::PackedTexture *Box;
D3DTex **Prev;
@ -143,7 +142,6 @@ public:
bool Update();
bool CheckWrapping(bool wrapping);
D3DFORMAT GetTexFormat();
FTextureFormat ToTexFmt(D3DFORMAT fmt);
};
class D3DPal : public FNativePalette
@ -2208,7 +2206,8 @@ void D3DFB::Atlas::FreeBox(D3DFB::PackedTexture *box)
//
//==========================================================================
D3DTex::D3DTex(FTexture *tex, D3DFB *fb, bool wrapping)
D3DTex::D3DTex(FTexture *tex, FTextureFormat fmt, D3DFB *fb, bool wrapping)
: FNativeTexture(tex, fmt)
{
// Attach to the texture list for the D3DFB
Next = fb->Textures;
@ -2219,7 +2218,6 @@ D3DTex::D3DTex(FTexture *tex, D3DFB *fb, bool wrapping)
Prev = &fb->Textures;
fb->Textures = this;
GameTex = tex;
Box = NULL;
IsGray = false;
@ -2245,11 +2243,6 @@ D3DTex::~D3DTex()
{
Next->Prev = Prev;
}
// Remove link from the game texture
if (GameTex != NULL)
{
GameTex->Native = NULL;
}
}
//==========================================================================
@ -2289,7 +2282,7 @@ bool D3DTex::Create(D3DFB *fb, bool wrapping)
Box->Owner->FreeBox(Box);
}
Box = fb->AllocPackedTexture(GameTex->GetWidth(), GameTex->GetHeight(), wrapping, GetTexFormat());
Box = fb->AllocPackedTexture(mGameTex->GetWidth(), mGameTex->GetHeight(), wrapping, GetTexFormat());
if (Box == NULL)
{
@ -2322,7 +2315,7 @@ bool D3DTex::Update()
assert(Box != NULL);
assert(Box->Owner != NULL);
assert(Box->Owner->Tex != NULL);
assert(GameTex != NULL);
assert(mGameTex != NULL);
if (FAILED(Box->Owner->Tex->GetLevelDesc(0, &desc)))
{
@ -2338,12 +2331,12 @@ bool D3DTex::Update()
{
dest += lrect.Pitch + (desc.Format == D3DFMT_L8 ? 1 : 4);
}
GameTex->FillBuffer(dest, lrect.Pitch, GameTex->GetHeight(), ToTexFmt(desc.Format));
mGameTex->FillBuffer(dest, lrect.Pitch, mGameTex->GetHeight(), mFormat);
if (Box->Padded)
{
// Clear top padding row.
dest = (uint8_t *)lrect.pBits;
int numbytes = GameTex->GetWidth() + 2;
int numbytes = mGameTex->GetWidth() + 2;
if (desc.Format != D3DFMT_L8)
{
numbytes <<= 2;
@ -2386,51 +2379,25 @@ bool D3DTex::Update()
D3DFORMAT D3DTex::GetTexFormat()
{
FTextureFormat fmt = GameTex->GetFormat();
IsGray = false;
switch (fmt)
switch (mFormat)
{
case TEX_Pal: return D3DFMT_L8;
case TEX_Gray: IsGray = true; return D3DFMT_L8;
case TEX_RGB: return D3DFMT_A8R8G8B8;
#if 0
case TEX_DXT1: return D3DFMT_DXT1;
case TEX_DXT2: return D3DFMT_DXT2;
case TEX_DXT3: return D3DFMT_DXT3;
case TEX_DXT4: return D3DFMT_DXT4;
case TEX_DXT5: return D3DFMT_DXT5;
#endif
default: I_FatalError ("GameTex->GetFormat() returned invalid format.");
}
return D3DFMT_L8;
}
//==========================================================================
//
// D3DTex :: ToTexFmt
//
// Converts a D3DFORMAT constant to something the FTexture system
// understands.
//
//==========================================================================
FTextureFormat D3DTex::ToTexFmt(D3DFORMAT fmt)
{
switch (fmt)
{
case D3DFMT_L8: return IsGray ? TEX_Gray : TEX_Pal;
case D3DFMT_A8R8G8B8: return TEX_RGB;
case D3DFMT_DXT1: return TEX_DXT1;
case D3DFMT_DXT2: return TEX_DXT2;
case D3DFMT_DXT3: return TEX_DXT3;
case D3DFMT_DXT4: return TEX_DXT4;
case D3DFMT_DXT5: return TEX_DXT5;
default:
assert(0); // LOL WUT?
return TEX_Pal;
}
}
//==========================================================================
//
// D3DPal Constructor
@ -2597,9 +2564,9 @@ void D3DFB::DrawBlendingRect()
//
//==========================================================================
FNativeTexture *D3DFB::CreateTexture(FTexture *gametex, bool wrapping)
FNativeTexture *D3DFB::CreateTexture(FTexture *gametex, FTextureFormat fmt, bool wrapping)
{
D3DTex *tex = new D3DTex(gametex, this, wrapping);
D3DTex *tex = new D3DTex(gametex, fmt, this, wrapping);
if (tex->Box == NULL)
{
delete tex;
@ -2824,7 +2791,12 @@ void D3DFB::DrawTextureParms (FTexture *img, DrawParms &parms)
return;
}
D3DTex *tex = static_cast<D3DTex *>(img->GetNative(false));
FTextureFormat fmt;
if (parms.style.Flags & STYLEF_RedIsAlpha) fmt = TEX_Gray;
else if (parms.remap != nullptr) fmt = TEX_Pal;
else fmt = img->GetFormat();
D3DTex *tex = static_cast<D3DTex *>(img->GetNative(fmt, false));
if (tex == NULL)
{
@ -3023,7 +2995,8 @@ void D3DFB::FlatFill(int left, int top, int right, int bottom, FTexture *src, bo
{
return;
}
D3DTex *tex = static_cast<D3DTex *>(src->GetNative(true));
D3DTex *tex = static_cast<D3DTex *>(src->GetNative(src->GetFormat(), true));
if (tex == NULL)
{
return;
@ -3158,7 +3131,8 @@ void D3DFB::FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
{
return;
}
tex = static_cast<D3DTex *>(texture->GetNative(true));
tex = static_cast<D3DTex *>(texture->GetNative(texture->GetFormat(), true));
if (tex == NULL)
{
return;

View file

@ -129,7 +129,7 @@ public:
void SetBlendingRect (int x1, int y1, int x2, int y2);
bool Begin2D (bool copy3d);
void DrawBlendingRect ();
FNativeTexture *CreateTexture (FTexture *gametex, bool wrapping);
FNativeTexture *CreateTexture (FTexture *gametex, FTextureFormat fmt, bool wrapping);
FNativePalette *CreatePalette (FRemapTable *remap);
void DrawTextureParms (FTexture *img, DrawParms &parms);
void DoClear (int left, int top, int right, int bottom, int palcolor, uint32_t color);