From 594ec6626c2e154ed74ba1e7cc3593a8a9fec675 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 29 May 2020 15:55:08 +0200 Subject: [PATCH] - 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. --- source/common/rendering/gl/gl_hwtexture.cpp | 3 +- source/common/textures/gametexture.cpp | 2 +- source/common/textures/gametexture.h | 7 + source/common/textures/hw_texcontainer.h | 1 + source/common/textures/texture.cpp | 117 ++++++++++------- source/core/textures/buildtiles.cpp | 3 +- source/core/textures/buildtiles.h | 1 - source/glbackend/gl_texture.cpp | 136 ++++---------------- source/glbackend/glbackend.h | 6 +- 9 files changed, 106 insertions(+), 170 deletions(-) diff --git a/source/common/rendering/gl/gl_hwtexture.cpp b/source/common/rendering/gl/gl_hwtexture.cpp index 31e104cfe..d16af5e8c 100644 --- a/source/common/rendering/gl/gl_hwtexture.cpp +++ b/source/common/rendering/gl/gl_hwtexture.cpp @@ -302,7 +302,7 @@ bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, i { int usebright = false; - bool needmipmap = (clampmode <= CLAMP_XY); + bool needmipmap = (clampmode <= CLAMP_XY) && !forcenofilter; // Bind it to the system. if (!Bind(texunit, needmipmap)) @@ -331,6 +331,7 @@ bool FHardwareTexture::BindOrCreate(FTexture *tex, int texunit, int clampmode, i return false; } } + if (forcenofilter) clampmode += CLAMP_NOFILTER - CLAMP_NONE; GLRenderer->mSamplerManager->Bind(texunit, clampmode, 255); return true; } diff --git a/source/common/textures/gametexture.cpp b/source/common/textures/gametexture.cpp index 3ab74a5c3..d47ffb733 100644 --- a/source/common/textures/gametexture.cpp +++ b/source/common/textures/gametexture.cpp @@ -187,7 +187,7 @@ void FGameTexture::AddAutoMaterials() void FGameTexture::CreateDefaultBrightmap() { auto tex = GetTexture(); - if (flags & GTexf_BrightmapChecked) + if (!(flags & GTexf_BrightmapChecked)) { flags |= GTexf_BrightmapChecked; // Check for brightmaps diff --git a/source/common/textures/gametexture.h b/source/common/textures/gametexture.h index 38c0908c6..2b8638ea5 100644 --- a/source/common/textures/gametexture.h +++ b/source/common/textures/gametexture.h @@ -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) diff --git a/source/common/textures/hw_texcontainer.h b/source/common/textures/hw_texcontainer.h index c75d42278..a29fc6396 100644 --- a/source/common/textures/hw_texcontainer.h +++ b/source/common/textures/hw_texcontainer.h @@ -14,6 +14,7 @@ enum ECreateTexBufferFlags 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_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 diff --git a/source/common/textures/texture.cpp b/source/common/textures/texture.cpp index e8626eaf7..bddd16c23 100644 --- a/source/common/textures/texture.cpp +++ b/source/common/textures/texture.cpp @@ -48,6 +48,7 @@ #include "formats/multipatchtexture.h" #include "texturemanager.h" #include "c_cvars.h" +#include "imagehelpers.h" // Wrappers to keep the definitions of these classes out of here. 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 result; - - 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) + if (flags & CTF_Indexed) { - buffer = new unsigned char[W * (H + 1) * 4]; - memset(buffer, 0, W * (H + 1) * 4); + // Indexed textures will never be translated and never be scaled. + int w = GetWidth(), h = GetHeight(); - auto remap = translation <= 0 ? nullptr : GPalette.TranslationToTable(translation); - if (remap) translation = remap->Index; - FBitmap bmp(buffer, W * 4, W, H); + auto store = Get8BitPixels(false); + const uint8_t* p = store.Data(); - int trans; - auto Pixels = GetBgraBitmap(remap ? remap->Palette : nullptr, &trans); - bmp.Blit(exx, exx, Pixels); + result.mBuffer = new uint8_t[w * h]; + result.mWidth = w; + 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); - isTransparent = bTranslucent; + buffer = new unsigned char[W * (H + 1) * 4]; + 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; - // A translated image is not conclusive for setting the texture's transparency info. + 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); } } - - 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; + } //=========================================================================== diff --git a/source/core/textures/buildtiles.cpp b/source/core/textures/buildtiles.cpp index ad4217257..02cefd3e6 100644 --- a/source/core/textures/buildtiles.cpp +++ b/source/core/textures/buildtiles.cpp @@ -138,7 +138,6 @@ void BuildTiles::Init() tile.picanm = {}; tile.RotTile = { -1,-1 }; tile.replacement = ReplacementType::Art; - tile.NoBrightmapFlag.Zero(); } } @@ -743,7 +742,7 @@ int BuildTiles::findUnusedTile(void) for (; lastUnusedTile >= 0; --lastUnusedTile) { auto tex = tileGetTexture(lastUnusedTile); - if (!tex || tex->GetTexelWidth() <= 0 || tex->GetTexelHeight() <= 0) return lastUnusedTile; + if (!tex || !tex->isValid()) return lastUnusedTile; } return -1; } diff --git a/source/core/textures/buildtiles.h b/source/core/textures/buildtiles.h index 04a423fcc..9cece50fc 100644 --- a/source/core/textures/buildtiles.h +++ b/source/core/textures/buildtiles.h @@ -265,7 +265,6 @@ struct TileDesc rottile_t RotTile;// = { -1,-1 }; TArray Hightiles; ReplacementType replacement; - FixedBitArray<256> NoBrightmapFlag; }; struct BuildTiles diff --git a/source/glbackend/gl_texture.cpp b/source/glbackend/gl_texture.cpp index da92509f3..605085540 100644 --- a/source/glbackend/gl_texture.cpp +++ b/source/glbackend/gl_texture.cpp @@ -43,98 +43,26 @@ #include "palettecontainer.h" #include "../../glbackend/glbackend.h" #include "texturemanager.h" +#include "v_video.h" // Test CVARs. CVAR(Int, fixpalette, -1, 0) CVAR(Int, fixpalswap, -1, 0) -template -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 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. // //=========================================================================== -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; - auto phwtex = tex->GetTexture()->SystemTextures.GetHardwareTexture(palid, false); + auto phwtex = tex->SystemTextures.GetHardwareTexture(palid, false); if (phwtex) return (OpenGLRenderer::FHardwareTexture*)phwtex; - OpenGLRenderer::FHardwareTexture *hwtex = nullptr; - if (textype == TT_INDEXED) - 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); + auto hwtex = static_cast(screen->CreateHardwareTexture(textype == TT_INDEXED? 1:4)); + if (hwtex) tex->SystemTextures.AddHardwareTexture(palid, false, 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) { - 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 palette = GetTranslationIndex(paletteid); 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; int lookuppal = 0; + int bindflags = 0; VSMatrix texmat; 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; TextureType = TT_HICREPLACE; + bindflags = CTF_Upscale; } else { @@ -254,7 +184,9 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid if (!(h.f & HICTINT_APPLYOVERPALSWAP)) usepalswap = 0; } 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. @@ -264,7 +196,8 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid // Load the main texture - auto mtex = LoadTexture(tex, TextureType, lookuppal); + + auto mtex = LoadTexture(tex->GetTexture(), TextureType, lookuppal); if (mtex) { 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); UseBrightmaps(false); + mtex->BindOrCreate(tex->GetTexture(), 0, sampler, lookuppal, bindflags); BindTexture(0, mtex, sampler); // 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)) @@ -305,8 +239,9 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid } if (det) { - auto htex = LoadTexture(det, TT_HICREPLACE, 0); + auto htex = LoadTexture(det->GetTexture(), TT_HICREPLACE, 0); UseDetailMapping(true); + htex->BindOrCreate(det->GetTexture(), 3, CLAMP_NONE, 0, 0); BindTexture(3, htex, SamplerRepeat); texbound[0] = true; @@ -335,44 +270,38 @@ bool GLInstance::SetTextureInternal(int picnum, FGameTexture* tex, int paletteid } if (glow) { - auto htex = LoadTexture(glow, TT_HICREPLACE, 0); + auto htex = LoadTexture(glow->GetTexture(), TT_HICREPLACE, 0); UseGlowMapping(true); + htex->BindOrCreate(glow->GetTexture(), 4, sampler, 0, CTF_Upscale); BindTexture(4, htex, SamplerRepeat); texbound[1] = true; } } #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) { auto brep = TileFiles.FindReplacement(picnum, BRIGHTPAL); if (brep) { - LoadTexture(brep->faces[0], TT_HICREPLACE, 0); + auto mtex = LoadTexture(brep->faces[0]->GetTexture(), TT_HICREPLACE, 0); UseBrightmaps(true); + mtex->BindOrCreate(brep->faces[0]->GetTexture(), 5, sampler, 0, CTF_Upscale); BindTexture(5, mtex, sampler); texbound[2] = true; } - else - { - TileFiles.tiledata[picnum].picanm.sf |= PICANM_NOFULLBRIGHT_BIT; - } } else if (TextureType == TT_TRUECOLOR) { - lookuppal = -1;// Needs some work on the texture management first. palmanager.LookupPalette(usepalette, usepalswap, true); - if (lookuppal >= 0) + auto btex = tex->GetBrightmap(); + if (btex) { - auto htex = LoadTexture(tex, TT_BRIGHTMAP, lookuppal); - if (htex == nullptr) - { - // Flag the texture as not being brightmapped for the given palette - TileFiles.tiledata[picnum].NoBrightmapFlag.Set(usepalswap); - } - else + auto htex = LoadTexture(btex, TT_BRIGHTMAP, lookuppal); + if (htex != nullptr) { UseBrightmaps(true); + htex->BindOrCreate(btex, 5, sampler, 0, CTF_Upscale); BindTexture(5, htex, sampler); 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 -// a direct index into the palette map. +// stand-ins for the texture system. Nothing of this is used right now, but needs to be present to satisfy the linker // //=========================================================================== -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) { return tex; diff --git a/source/glbackend/glbackend.h b/source/glbackend/glbackend.h index 97661bbd2..95df70fa3 100644 --- a/source/glbackend/glbackend.h +++ b/source/glbackend/glbackend.h @@ -487,13 +487,9 @@ public: renderState.AlphaThreshold = al; } - OpenGLRenderer::FHardwareTexture* CreateIndexedTexture(FGameTexture* tex); - OpenGLRenderer::FHardwareTexture* CreateTrueColorTexture(FGameTexture* tex, int palid, bool checkfulltransparency = false, bool rgb8bit = false); - OpenGLRenderer::FHardwareTexture *LoadTexture(FGameTexture* tex, int texturetype, int palid); + OpenGLRenderer::FHardwareTexture *LoadTexture(FTexture* tex, int texturetype, int palid); 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) { return SetTextureInternal(globalpicnum, tex, palette, method, sampleroverride, nullptr, 1, nullptr);