- transitioned to using GZDoom's texture creation code.

Also added support for creating indexed textures directly into CreateTexBuffer, where this functionality can be shared.
As an added plus, brightmaps are working again, this time with less hackery.
This commit is contained in:
Christoph Oelckers 2020-05-29 15:55:08 +02:00
parent 66809ca9f4
commit 594ec6626c
9 changed files with 106 additions and 170 deletions

View file

@ -302,7 +302,7 @@ bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, i
{ {
int usebright = false; int usebright = false;
bool needmipmap = (clampmode <= CLAMP_XY); bool needmipmap = (clampmode <= CLAMP_XY) && !forcenofilter;
// Bind it to the system. // Bind it to the system.
if (!Bind(texunit, needmipmap)) if (!Bind(texunit, needmipmap))
@ -331,6 +331,7 @@ bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, i
return false; return false;
} }
} }
if (forcenofilter) clampmode += CLAMP_NOFILTER - CLAMP_NONE;
GLRenderer->mSamplerManager->Bind(texunit, clampmode, 255); GLRenderer->mSamplerManager->Bind(texunit, clampmode, 255);
return true; return true;
} }

View file

@ -187,7 +187,7 @@ void FGameTexture::AddAutoMaterials()
void FGameTexture::CreateDefaultBrightmap() void FGameTexture::CreateDefaultBrightmap()
{ {
auto tex = GetTexture(); auto tex = GetTexture();
if (flags & GTexf_BrightmapChecked) if (!(flags & GTexf_BrightmapChecked))
{ {
flags |= GTexf_BrightmapChecked; flags |= GTexf_BrightmapChecked;
// Check for brightmaps // Check for brightmaps

View file

@ -305,6 +305,13 @@ public:
} }
} }
FTexture* GetBrightmap()
{
if (Brightmap.get() || (flags & GTexf_BrightmapChecked)) return Brightmap.get();
CreateDefaultBrightmap();
return Brightmap.get();
}
}; };
inline FGameTexture* MakeGameTexture(FTexture* tex, const char *name, ETextureType useType) inline FGameTexture* MakeGameTexture(FTexture* tex, const char *name, ETextureType useType)

View file

@ -14,6 +14,7 @@ enum ECreateTexBufferFlags
CTF_CreateMask = 3, // Flags that are relevant for hardware texture creation. CTF_CreateMask = 3, // Flags that are relevant for hardware texture creation.
CTF_ProcessData = 4, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture. CTF_ProcessData = 4, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture.
CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures. CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures.
CTF_Indexed = 16 // Tell the backend to create an indexed texture.
}; };
class FHardwareTextureContainer class FHardwareTextureContainer

View file

@ -48,6 +48,7 @@
#include "formats/multipatchtexture.h" #include "formats/multipatchtexture.h"
#include "texturemanager.h" #include "texturemanager.h"
#include "c_cvars.h" #include "c_cvars.h"
#include "imagehelpers.h"
// Wrappers to keep the definitions of these classes out of here. // Wrappers to keep the definitions of these classes out of here.
IHardwareTexture* CreateHardwareTexture(int numchannels); IHardwareTexture* CreateHardwareTexture(int numchannels);
@ -323,66 +324,82 @@ bool FTexture::ProcessData(unsigned char* buffer, int w, int h, bool ispatch)
FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags) FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
{ {
FTextureBuffer result; FTextureBuffer result;
if (flags & CTF_Indexed)
unsigned char* buffer = nullptr;
int W, H;
int isTransparent = -1;
bool checkonly = !!(flags & CTF_CheckOnly);
int exx = !!(flags & CTF_Expand);
W = GetWidth() + 2 * exx;
H = GetHeight() + 2 * exx;
if (!checkonly)
{ {
buffer = new unsigned char[W * (H + 1) * 4]; // Indexed textures will never be translated and never be scaled.
memset(buffer, 0, W * (H + 1) * 4); int w = GetWidth(), h = GetHeight();
auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation); auto store = Get8BitPixels(false);
if (remap) translation = remap->Index; const uint8_t* p = store.Data();
FBitmap bmp(buffer, W * 4, W, H);
int trans; result.mBuffer = new uint8_t[w * h];
auto Pixels = GetBgraBitmap(remap ? remap->Palette : nullptr, &trans); result.mWidth = w;
bmp.Blit(exx, exx, Pixels); result.mHeight = h;
result.mContentId = 0;
ImageHelpers::FlipNonSquareBlock(result.mBuffer, p, h, w, h);
}
else
{
unsigned char* buffer = nullptr;
int W, H;
int isTransparent = -1;
bool checkonly = !!(flags & CTF_CheckOnly);
if (remap == nullptr) int exx = !!(flags & CTF_Expand);
W = GetWidth() + 2 * exx;
H = GetHeight() + 2 * exx;
if (!checkonly)
{ {
CheckTrans(buffer, W * H, trans); buffer = new unsigned char[W * (H + 1) * 4];
isTransparent = bTranslucent; memset(buffer, 0, W * (H + 1) * 4);
auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation);
if (remap) translation = remap->Index;
FBitmap bmp(buffer, W * 4, W, H);
int trans;
auto Pixels = GetBgraBitmap(remap ? remap->Palette : nullptr, &trans);
bmp.Blit(exx, exx, Pixels);
if (remap == nullptr)
{
CheckTrans(buffer, W * H, trans);
isTransparent = bTranslucent;
}
else
{
isTransparent = 0;
// A translated image is not conclusive for setting the texture's transparency info.
}
} }
else
if (GetImage())
{ {
isTransparent = 0; FContentIdBuilder builder;
// A translated image is not conclusive for setting the texture's transparency info. builder.id = 0;
builder.imageID = GetImage()->GetId();
builder.translation = MAX(0, translation);
builder.expand = exx;
result.mContentId = builder.id;
}
else result.mContentId = 0; // for non-image backed textures this has no meaning so leave it at 0.
result.mBuffer = buffer;
result.mWidth = W;
result.mHeight = H;
// Only do postprocessing for image-backed textures. (i.e. not for the burn texture which can also pass through here.)
if (GetImage() && flags & CTF_ProcessData)
{
if (flags & CTF_Upscale) CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly);
if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false);
} }
} }
if (GetImage())
{
FContentIdBuilder builder;
builder.id = 0;
builder.imageID = GetImage()->GetId();
builder.translation = MAX(0, translation);
builder.expand = exx;
result.mContentId = builder.id;
}
else result.mContentId = 0; // for non-image backed textures this has no meaning so leave it at 0.
result.mBuffer = buffer;
result.mWidth = W;
result.mHeight = H;
// Only do postprocessing for image-backed textures. (i.e. not for the burn texture which can also pass through here.)
if (GetImage() && flags & CTF_ProcessData)
{
if (flags & CTF_Upscale) CreateUpsampledTextureBuffer(result, !!isTransparent, checkonly);
if (!checkonly) ProcessData(result.mBuffer, result.mWidth, result.mHeight, false);
}
return result; return result;
} }
//=========================================================================== //===========================================================================

View file

@ -138,7 +138,6 @@ void BuildTiles::Init()
tile.picanm = {}; tile.picanm = {};
tile.RotTile = { -1,-1 }; tile.RotTile = { -1,-1 };
tile.replacement = ReplacementType::Art; tile.replacement = ReplacementType::Art;
tile.NoBrightmapFlag.Zero();
} }
} }
@ -743,7 +742,7 @@ int BuildTiles::findUnusedTile(void)
for (; lastUnusedTile >= 0; --lastUnusedTile) for (; lastUnusedTile >= 0; --lastUnusedTile)
{ {
auto tex = tileGetTexture(lastUnusedTile); auto tex = tileGetTexture(lastUnusedTile);
if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return lastUnusedTile; if (!tex || !tex->isValid()) return lastUnusedTile;
} }
return -1; return -1;
} }

View file

@ -265,7 +265,6 @@ struct TileDesc
rottile_t RotTile;// = { -1,-1 }; rottile_t RotTile;// = { -1,-1 };
TArray<HightileReplacement> Hightiles; TArray<HightileReplacement> Hightiles;
ReplacementType replacement; ReplacementType replacement;
FixedBitArray<256> NoBrightmapFlag;
}; };
struct BuildTiles struct BuildTiles

View file

@ -43,98 +43,26 @@
#include "palettecontainer.h" #include "palettecontainer.h"
#include "../../glbackend/glbackend.h" #include "../../glbackend/glbackend.h"
#include "texturemanager.h" #include "texturemanager.h"
#include "v_video.h"
// Test CVARs. // Test CVARs.
CVAR(Int, fixpalette, -1, 0) CVAR(Int, fixpalette, -1, 0)
CVAR(Int, fixpalswap, -1, 0) CVAR(Int, fixpalswap, -1, 0)
template<class T>
void FlipNonSquareBlock(T* dst, const T* src, int x, int y, int srcpitch)
{
for (int i = 0; i < x; ++i)
{
for (int j = 0; j < y; ++j)
{
dst[i * y + j] = src[i + j * srcpitch];
}
}
}
//===========================================================================
//
// Create an indexed version of the requested texture
//
//===========================================================================
OpenGLRenderer::FHardwareTexture* GLInstance::CreateIndexedTexture(FGameTexture* tex)
{
vec2_t siz = { tex->GetTexelWidth(), tex->GetTexelHeight() };
auto store = tex->GetTexture()->Get8BitPixels(false);
const uint8_t* p = store.Data();
auto glpic = GLInterface.NewTexture(1);
TArray<uint8_t> flipped(siz.x * siz.y, true);
FlipNonSquareBlock(flipped.Data(), p, siz.y, siz.x, siz.y);
glpic->CreateTexture(flipped.Data(), siz.x, siz.y, 15, false, tex->GetName());
return glpic;
}
//===========================================================================
//
// Create a true color version of the requested tile
//
//===========================================================================
OpenGLRenderer::FHardwareTexture* GLInstance::CreateTrueColorTexture(FGameTexture* tex, int palid, bool checkfulltransparency, bool rgb8bit)
{
if (tex == TexMan.GameByIndex(0))
return nullptr;
auto texbuffer = tex->GetTexture()->CreateTexBuffer(palid, checkfulltransparency? 0: CTF_ProcessData);
// Check if the texture is fully transparent. When creating a brightmap such textures can be discarded.
if (checkfulltransparency)
{
int siz = texbuffer.mWidth * texbuffer.mHeight * 4;
bool found = false;
for (int i = 3; i < siz; i+=4)
{
if (texbuffer.mBuffer[i] > 0)
{
found = true;
break;
}
}
if (!found) return nullptr;
}
auto glpic = GLInterface.NewTexture(4);
glpic->CreateTexture(texbuffer.mBuffer, texbuffer.mWidth, texbuffer.mHeight, 15, true, tex->GetName());
return glpic;
}
//=========================================================================== //===========================================================================
// //
// Retrieve the texture to be used. // Retrieve the texture to be used.
// //
//=========================================================================== //===========================================================================
OpenGLRenderer::FHardwareTexture* GLInstance::LoadTexture(FGameTexture* tex, int textype, int palid) OpenGLRenderer::FHardwareTexture* GLInstance::LoadTexture(FTexture *tex, int textype, int palid)
{ {
if (textype == TT_INDEXED) palid = -1; if (textype == TT_INDEXED) palid = -1;
auto phwtex = tex->GetTexture()->SystemTextures.GetHardwareTexture(palid, false); auto phwtex = tex->SystemTextures.GetHardwareTexture(palid, false);
if (phwtex) return (OpenGLRenderer::FHardwareTexture*)phwtex; if (phwtex) return (OpenGLRenderer::FHardwareTexture*)phwtex;
OpenGLRenderer::FHardwareTexture *hwtex = nullptr; auto hwtex = static_cast<OpenGLRenderer::FHardwareTexture*>(screen->CreateHardwareTexture(textype == TT_INDEXED? 1:4));
if (textype == TT_INDEXED) if (hwtex) tex->SystemTextures.AddHardwareTexture(palid, false, hwtex);
hwtex = CreateIndexedTexture(tex);
else if (!tex->GetTexture()->isHardwareCanvas())
hwtex = CreateTrueColorTexture(tex, textype == TT_HICREPLACE? -1 : palid, textype == TT_BRIGHTMAP, textype == TT_BRIGHTMAP);
else
hwtex = nullptr;
if (hwtex) tex->GetTexture()->SystemTextures.AddHardwareTexture(palid, false, hwtex);
return hwtex; return hwtex;
} }
@ -203,7 +131,7 @@ TexturePick PickTexture(int tilenum, int basepal, int palette)
bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid, int method, int sampleroverride, FGameTexture *det, float detscale, FGameTexture *glow) bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid, int method, int sampleroverride, FGameTexture *det, float detscale, FGameTexture *glow)
{ {
if (tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return false; if (!tex->isValid() || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return false;
int curbasepal = GetTranslationType(paletteid) - Translation_Remap; int curbasepal = GetTranslationType(paletteid) - Translation_Remap;
int palette = GetTranslationIndex(paletteid); int palette = GetTranslationIndex(paletteid);
int usepalette = fixpalette >= 0 ? fixpalette : curbasepal; int usepalette = fixpalette >= 0 ? fixpalette : curbasepal;
@ -216,6 +144,7 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid
TextureType = hw_int_useindexedcolortextures? TT_INDEXED : TT_TRUECOLOR; TextureType = hw_int_useindexedcolortextures? TT_INDEXED : TT_TRUECOLOR;
int lookuppal = 0; int lookuppal = 0;
int bindflags = 0;
VSMatrix texmat; VSMatrix texmat;
GLInterface.SetBasepalTint(0xffffff); GLInterface.SetBasepalTint(0xffffff);
@ -241,6 +170,7 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid
} }
if (!rep || rep->palnum != palette || (h.f & HICTINT_APPLYOVERALTPAL)) applytint = true; if (!rep || rep->palnum != palette || (h.f & HICTINT_APPLYOVERALTPAL)) applytint = true;
TextureType = TT_HICREPLACE; TextureType = TT_HICREPLACE;
bindflags = CTF_Upscale;
} }
else else
{ {
@ -254,7 +184,9 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid
if (!(h.f & HICTINT_APPLYOVERPALSWAP)) usepalswap = 0; if (!(h.f & HICTINT_APPLYOVERPALSWAP)) usepalswap = 0;
} }
lookuppal = TRANSLATION(usepalette + Translation_Remap, usepalswap); lookuppal = TRANSLATION(usepalette + Translation_Remap, usepalswap);
bindflags = CTF_Upscale;
} }
else bindflags = CTF_Indexed;
} }
// This is intentionally the same value for both parameters. The shader does not use the same uniform for modulation and overlay colors. // This is intentionally the same value for both parameters. The shader does not use the same uniform for modulation and overlay colors.
@ -264,7 +196,8 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid
// Load the main texture // Load the main texture
auto mtex = LoadTexture(tex, TextureType, lookuppal);
auto mtex = LoadTexture(tex->GetTexture(), TextureType, lookuppal);
if (mtex) if (mtex)
{ {
auto sampler = (method & DAMETH_CLAMPED) ? (sampleroverride != -1 ? sampleroverride : SamplerClampXY) : SamplerRepeat; auto sampler = (method & DAMETH_CLAMPED) ? (sampleroverride != -1 ? sampleroverride : SamplerClampXY) : SamplerRepeat;
@ -280,6 +213,7 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid
UseGlowMapping(false); UseGlowMapping(false);
UseBrightmaps(false); UseBrightmaps(false);
mtex->BindOrCreate(tex->GetTexture(), 0, sampler, lookuppal, bindflags);
BindTexture(0, mtex, sampler); BindTexture(0, mtex, sampler);
// Needs a) testing and b) verification for correctness. This doesn't look like it makes sense. // Needs a) testing and b) verification for correctness. This doesn't look like it makes sense.
if (rep && (rep->scale.x != 1.0f || rep->scale.y != 1.0f)) if (rep && (rep->scale.x != 1.0f || rep->scale.y != 1.0f))
@ -305,8 +239,9 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid
} }
if (det) if (det)
{ {
auto htex = LoadTexture(det, TT_HICREPLACE, 0); auto htex = LoadTexture(det->GetTexture(), TT_HICREPLACE, 0);
UseDetailMapping(true); UseDetailMapping(true);
htex->BindOrCreate(det->GetTexture(), 3, CLAMP_NONE, 0, 0);
BindTexture(3, htex, SamplerRepeat); BindTexture(3, htex, SamplerRepeat);
texbound[0] = true; texbound[0] = true;
@ -335,44 +270,38 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid
} }
if (glow) if (glow)
{ {
auto htex = LoadTexture(glow, TT_HICREPLACE, 0); auto htex = LoadTexture(glow->GetTexture(), TT_HICREPLACE, 0);
UseGlowMapping(true); UseGlowMapping(true);
htex->BindOrCreate(glow->GetTexture(), 4, sampler, 0, CTF_Upscale);
BindTexture(4, htex, SamplerRepeat); BindTexture(4, htex, SamplerRepeat);
texbound[1] = true; texbound[1] = true;
} }
} }
#if 1 #if 1
if (picnum > -1 && !(TileFiles.tiledata[picnum].picanm.sf & PICANM_NOFULLBRIGHT_BIT) && !(globalflags & GLOBAL_NO_GL_FULLBRIGHT) && !TileFiles.tiledata[picnum].NoBrightmapFlag[usepalswap]) if (picnum > -1 && !(TileFiles.tiledata[picnum].picanm.sf & PICANM_NOFULLBRIGHT_BIT) && !(globalflags & GLOBAL_NO_GL_FULLBRIGHT))
{ {
if (TextureType == TT_HICREPLACE) if (TextureType == TT_HICREPLACE)
{ {
auto brep = TileFiles.FindReplacement(picnum, BRIGHTPAL); auto brep = TileFiles.FindReplacement(picnum, BRIGHTPAL);
if (brep) if (brep)
{ {
LoadTexture(brep->faces[0], TT_HICREPLACE, 0); auto mtex = LoadTexture(brep->faces[0]->GetTexture(), TT_HICREPLACE, 0);
UseBrightmaps(true); UseBrightmaps(true);
mtex->BindOrCreate(brep->faces[0]->GetTexture(), 5, sampler, 0, CTF_Upscale);
BindTexture(5, mtex, sampler); BindTexture(5, mtex, sampler);
texbound[2] = true; texbound[2] = true;
} }
else
{
TileFiles.tiledata[picnum].picanm.sf |= PICANM_NOFULLBRIGHT_BIT;
}
} }
else if (TextureType == TT_TRUECOLOR) else if (TextureType == TT_TRUECOLOR)
{ {
lookuppal = -1;// Needs some work on the texture management first. palmanager.LookupPalette(usepalette, usepalswap, true); auto btex = tex->GetBrightmap();
if (lookuppal >= 0) if (btex)
{ {
auto htex = LoadTexture(tex, TT_BRIGHTMAP, lookuppal); auto htex = LoadTexture(btex, TT_BRIGHTMAP, lookuppal);
if (htex == nullptr) if (htex != nullptr)
{
// Flag the texture as not being brightmapped for the given palette
TileFiles.tiledata[picnum].NoBrightmapFlag.Set(usepalswap);
}
else
{ {
UseBrightmaps(true); UseBrightmaps(true);
htex->BindOrCreate(btex, 5, sampler, 0, CTF_Upscale);
BindTexture(5, htex, sampler); BindTexture(5, htex, sampler);
texbound[2] = true; texbound[2] = true;
} }
@ -399,23 +328,10 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid
//=========================================================================== //===========================================================================
// //
// Sets a named texture for 2D rendering. In this case the palette is // stand-ins for the texture system. Nothing of this is used right now, but needs to be present to satisfy the linker
// a direct index into the palette map.
// //
//=========================================================================== //===========================================================================
bool GLInstance::SetNamedTexture(FGameTexture* tex, int palette, int sampler)
{
auto mtex = LoadTexture(tex, palette>= 0? TT_TRUECOLOR : TT_HICREPLACE, palette);
if (!mtex) return false;
BindTexture(0, mtex, sampler);
GLInterface.SetAlphaThreshold(tex->GetTranslucency()? 0.f : 0.5f);
return true;
}
// stand-ins for the texture system. Nothing of this is used right now, but needs to be present to satisfy the linker
int PalCheck(int tex) int PalCheck(int tex)
{ {
return tex; return tex;

View file

@ -487,13 +487,9 @@ public:
renderState.AlphaThreshold = al; renderState.AlphaThreshold = al;
} }
OpenGLRenderer::FHardwareTexture* CreateIndexedTexture(FGameTexture* tex); OpenGLRenderer::FHardwareTexture *LoadTexture(FTexture* tex, int texturetype, int palid);
OpenGLRenderer::FHardwareTexture* CreateTrueColorTexture(FGameTexture* tex, int palid, bool checkfulltransparency = false, bool rgb8bit = false);
OpenGLRenderer::FHardwareTexture *LoadTexture(FGameTexture* tex, int texturetype, int palid);
bool SetTextureInternal(int globalpicnum, FGameTexture* tex, int palette, int method, int sampleroverride, FGameTexture *det, float detscale, FGameTexture *glow); bool SetTextureInternal(int globalpicnum, FGameTexture* tex, int palette, int method, int sampleroverride, FGameTexture *det, float detscale, FGameTexture *glow);
bool SetNamedTexture(FGameTexture* tex, int palette, int sampleroverride);
bool SetTexture(int globalpicnum, FGameTexture* tex, int palette, int method, int sampleroverride) bool SetTexture(int globalpicnum, FGameTexture* tex, int palette, int method, int sampleroverride)
{ {
return SetTextureInternal(globalpicnum, tex, palette, method, sampleroverride, nullptr, 1, nullptr); return SetTextureInternal(globalpicnum, tex, palette, method, sampleroverride, nullptr, 1, nullptr);