From 42304d9680c753b04fa0236b86bd22833fa4c4a9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 17 Apr 2020 01:03:21 +0200 Subject: [PATCH] - store the material layers in reference counted pointers in the FGameTexture object. Reference counting is used because a texture image may be shared by more than one game texture. --- src/common/textures/hw_material.cpp | 27 ++-- src/common/textures/texture.cpp | 65 ++++----- src/common/textures/texturemanager.cpp | 3 - src/common/textures/textures.h | 185 +++++++++++++------------ src/common/utility/refcounted.h | 103 ++++++++++++++ 5 files changed, 244 insertions(+), 139 deletions(-) create mode 100644 src/common/utility/refcounted.h diff --git a/src/common/textures/hw_material.cpp b/src/common/textures/hw_material.cpp index 14f031ee1..41c85fccf 100644 --- a/src/common/textures/hw_material.cpp +++ b/src/common/textures/hw_material.cpp @@ -60,17 +60,18 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags) { mShaderIndex = tx->isWarped(); // This picks SHADER_Warp1 or SHADER_Warp2 } - else if (imgtex->Normal && imgtex->Specular) + // Note that the material takes no ownership of the texture! + else if (tx->Normal.get() && tx->Specular.get()) { - for (auto &texture : { imgtex->Normal, imgtex->Specular }) + for (auto &texture : { tx->Normal.get(), tx->Specular.get() }) { mTextureLayers.Push(texture); } mShaderIndex = SHADER_Specular; } - else if (imgtex->Normal && imgtex->Metallic && imgtex->Roughness && imgtex->AmbientOcclusion) + else if (tx->Normal.get() && tx->Metallic.get() && tx->Roughness.get() && tx->AmbientOcclusion.get()) { - for (auto &texture : { imgtex->Normal, imgtex->Metallic, imgtex->Roughness, imgtex->AmbientOcclusion }) + for (auto &texture : { tx->Normal.get(), tx->Metallic.get(), tx->Roughness.get(), tx->AmbientOcclusion.get() }) { mTextureLayers.Push(texture); } @@ -80,27 +81,27 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags) // Note that these layers must present a valid texture even if not used, because empty TMUs in the shader are an undefined condition. tx->CreateDefaultBrightmap(); auto placeholder = TexMan.GameByIndex(1); - if (imgtex->Brightmap) + if (tx->Brightmap.get()) { - mTextureLayers.Push(imgtex->Brightmap); + mTextureLayers.Push(tx->Brightmap.get()); mLayerFlags |= TEXF_Brightmap; } else { mTextureLayers.Push(placeholder->GetTexture()); } - if (imgtex->Detailmap) + if (tx->Detailmap.get()) { - mTextureLayers.Push(imgtex->Detailmap); + mTextureLayers.Push(tx->Detailmap.get()); mLayerFlags |= TEXF_Detailmap; } else { mTextureLayers.Push(placeholder->GetTexture()); } - if (imgtex->Glowmap) + if (tx->Glowmap.get()) { - mTextureLayers.Push(imgtex->Glowmap); + mTextureLayers.Push(tx->Glowmap.get()); mLayerFlags |= TEXF_Glowmap; } else @@ -113,10 +114,10 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags) const UserShaderDesc &usershader = usershaders[imgtex->shaderindex - FIRST_USER_SHADER]; if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material { - for (auto &texture : imgtex->CustomShaderTextures) + for (auto &texture : tx->CustomShaderTextures) { if (texture == nullptr) continue; - mTextureLayers.Push(texture); + mTextureLayers.Push(texture.get()); } mShaderIndex = tx->GetShaderIndex(); } @@ -167,7 +168,7 @@ FMaterial * FMaterial::ValidateTexture(FGameTexture * gtex, int scaleflags, bool if (gtex && gtex->isValid()) { auto tex = gtex->GetTexture(); - if (!tex->ShouldExpandSprite()) scaleflags &= ~CTF_Expand; + if (!gtex->ShouldExpandSprite()) scaleflags &= ~CTF_Expand; FMaterial *hwtex = tex->Material[scaleflags]; if (hwtex == NULL && create) diff --git a/src/common/textures/texture.cpp b/src/common/textures/texture.cpp index 01ad66c31..acdba3431 100644 --- a/src/common/textures/texture.cpp +++ b/src/common/textures/texture.cpp @@ -288,30 +288,30 @@ int FTexture::CheckRealHeight() // //========================================================================== -void FTexture::AddAutoMaterials() +void FGameTexture::AddAutoMaterials() { struct AutoTextureSearchPath { const char *path; - FTexture *FTexture::*pointer; + RefCountedPtr FGameTexture::*pointer; }; static AutoTextureSearchPath autosearchpaths[] = { - { "brightmaps/", &FTexture::Brightmap }, // For backwards compatibility, only for short names - { "materials/brightmaps/", &FTexture::Brightmap }, - { "materials/normalmaps/", &FTexture::Normal }, - { "materials/specular/", &FTexture::Specular }, - { "materials/metallic/", &FTexture::Metallic }, - { "materials/roughness/", &FTexture::Roughness }, - { "materials/ao/", &FTexture::AmbientOcclusion } + { "brightmaps/", &FGameTexture::Brightmap }, // For backwards compatibility, only for short names + { "materials/brightmaps/", &FGameTexture::Brightmap }, + { "materials/normalmaps/", &FGameTexture::Normal }, + { "materials/specular/", &FGameTexture::Specular }, + { "materials/metallic/", &FGameTexture::Metallic }, + { "materials/roughness/", &FGameTexture::Roughness }, + { "materials/ao/", &FGameTexture::AmbientOcclusion } }; - int startindex = bFullNameTexture ? 1 : 0; - FString searchname = Name; + int startindex = Base->bFullNameTexture ? 1 : 0; + FString searchname = GetName(); - if (bFullNameTexture) + if (Base->bFullNameTexture) { auto dot = searchname.LastIndexOf('.'); auto slash = searchname.LastIndexOf('/'); @@ -323,7 +323,7 @@ void FTexture::AddAutoMaterials() auto &layer = autosearchpaths[i]; if (this->*(layer.pointer) == nullptr) // only if no explicit assignment had been done. { - FStringf lookup("%s%s%s", layer.path, bFullNameTexture ? "" : "auto/", searchname.GetChars()); + FStringf lookup("%s%s%s", layer.path, Base->bFullNameTexture ? "" : "auto/", searchname.GetChars()); auto lump = fileSystem.CheckNumForFullName(lookup, false, ns_global, true); if (lump != -1) { @@ -351,7 +351,7 @@ void FGameTexture::CreateDefaultBrightmap() // Check for brightmaps if (tex->GetImage() && tex->GetImage()->UseGamePalette() && GPalette.HasGlobalBrightmap && GetUseType() != ETextureType::Decal && GetUseType() != ETextureType::MiscPatch && GetUseType() != ETextureType::FontChar && - tex->Brightmap == NULL) + Brightmap == nullptr) { // May have one - let's check when we use this texture auto texbuf = tex->Get8BitPixels(false); @@ -364,7 +364,7 @@ void FGameTexture::CreateDefaultBrightmap() { // Create a brightmap DPrintf(DMSG_NOTIFY, "brightmap created for texture '%s'\n", GetName().GetChars()); - tex->Brightmap = CreateBrightmapTexture(static_cast(tex)->GetImage()); + Brightmap = CreateBrightmapTexture(tex->GetImage()); tex->bBrightmapChecked = true; //TexMan.AddGameTexture(MakeGameTexture(tex->Brightmap)); return; @@ -743,21 +743,21 @@ TArray FTexture::Get8BitPixels(bool alphatex) // //=========================================================================== -bool FTexture::ShouldExpandSprite() +bool FGameTexture::ShouldExpandSprite() { - if (bExpandSprite != -1) return bExpandSprite; - if (isWarped() || isHardwareCanvas() || shaderindex != SHADER_Default) + if (Base->bExpandSprite != -1) return Base->bExpandSprite; + if (isWarped() || isHardwareCanvas() || GetShaderIndex() != SHADER_Default) { - bExpandSprite = false; + Base->bExpandSprite = false; return false; } if (Brightmap != NULL && (GetTexelWidth() != Brightmap->GetTexelWidth() || GetTexelHeight() != Brightmap->GetTexelHeight())) { // do not expand if the brightmap's size differs. - bExpandSprite = false; + Base->bExpandSprite = false; return false; } - bExpandSprite = true; + Base->bExpandSprite = true; return true; } @@ -857,14 +857,14 @@ outl: // //=========================================================================== -void FTexture::SetupSpriteData() +void FGameTexture::SetupSpriteData() { // Since this is only needed for real sprites it gets allocated on demand. // It also allocates from the image memory arena because it has the same lifetime and to reduce maintenance. - if (spi == nullptr) spi = (SpritePositioningInfo*)ImageArena.Alloc(2 * sizeof(SpritePositioningInfo)); + if (Base->spi == nullptr) Base->spi = (SpritePositioningInfo*)ImageArena.Alloc(2 * sizeof(SpritePositioningInfo)); for (int i = 0; i < 2; i++) { - auto& spi = this->spi[i]; + auto& spi = Base->spi[i]; spi.mSpriteU[0] = spi.mSpriteV[0] = 0.f; spi.mSpriteU[1] = spi.mSpriteV[1] = 1.f; spi.spriteWidth = GetTexelWidth(); @@ -872,7 +872,7 @@ void FTexture::SetupSpriteData() if (i == 1 && ShouldExpandSprite()) { - spi.mTrimResult = TrimBorders(spi.trim); // get the trim size before adding the empty frame + spi.mTrimResult = Base->TrimBorders(spi.trim); // get the trim size before adding the empty frame spi.spriteWidth += 2; spi.spriteHeight += 2; } @@ -886,19 +886,19 @@ void FTexture::SetupSpriteData() // //=========================================================================== -void FTexture::SetSpriteRect() +void FGameTexture::SetSpriteRect() { - if (!spi) return; + if (!Base->spi) return; auto leftOffset = GetLeftOffsetHW(); auto topOffset = GetTopOffsetHW(); - float fxScale = (float)Scale.X; - float fyScale = (float)Scale.Y; + float fxScale = (float)Base->Scale.X; + float fyScale = (float)Base->Scale.Y; for (int i = 0; i < 2; i++) { - auto& spi = this->spi[i]; + auto& spi = Base->spi[i]; // mSpriteRect is for positioning the sprite in the scene. spi.mSpriteRect.left = -leftOffset / fxScale; @@ -1087,12 +1087,13 @@ FGameTexture::~FGameTexture() { FGameTexture* link = fileSystem.GetLinkedTexture(GetSourceLump()); if (link == this) fileSystem.SetLinkedTexture(GetSourceLump(), nullptr); - delete wrapped; + auto str = GetName(); + Printf("Deleting texture %s\n", str.GetChars()); } bool FGameTexture::isUserContent() const { - int filenum = fileSystem.GetFileContainer(wrapped->GetSourceLump()); + int filenum = fileSystem.GetFileContainer(Base->GetSourceLump()); return (filenum > fileSystem.GetMaxIwadNum()); } diff --git a/src/common/textures/texturemanager.cpp b/src/common/textures/texturemanager.cpp index f9fe4d84e..8265f3617 100644 --- a/src/common/textures/texturemanager.cpp +++ b/src/common/textures/texturemanager.cpp @@ -1093,9 +1093,6 @@ void FTextureManager::Init(void (*progressFunc_)(), void (*checkForHacks)(BuildI DeleteAll(); //if (BuildTileFiles.Size() == 0) CountBuildTiles (); - // Texture 0 is a dummy texture used to indicate "no texture" - auto nulltex = MakeGameTexture(new FImageTexture(nullptr, ""), ETextureType::Null); - AddGameTexture (nulltex); // This is for binding to unused texture units, because accessing an unbound texture unit is undefined. It's a one pixel empty texture. auto emptytex = MakeGameTexture(new FImageTexture(CreateEmptyTexture(), ""), ETextureType::Override); emptytex->SetSize(1, 1); diff --git a/src/common/textures/textures.h b/src/common/textures/textures.h index 492807882..6946a4d96 100644 --- a/src/common/textures/textures.h +++ b/src/common/textures/textures.h @@ -42,6 +42,7 @@ #include "textureid.h" #include #include "hw_texcontainer.h" +#include "refcounted.h" // 15 because 0th texture is our texture #define MAX_CUSTOM_HW_SHADER_TEXTURES 15 @@ -235,7 +236,7 @@ struct SpritePositioningInfo }; // Base texture class -class FTexture +class FTexture : public RefCountedBase { friend class FGameTexture; // only for the porting work friend class FTexture; @@ -253,9 +254,9 @@ public: static FTexture *CreateTexture(const char *name, int lumpnum, ETextureType UseType); virtual ~FTexture (); virtual FImageSource *GetImage() const { return nullptr; } - void AddAutoMaterials(); void CreateUpsampledTextureBuffer(FTextureBuffer &texbuffer, bool hasAlpha, bool checkonly); void CleanHardwareTextures(bool reallyclean); + void SetSpriteRect(); // These are mainly meant for 2D code which only needs logical information about the texture to position it properly. int GetDisplayWidth() { int foo = int((Width * 2) / Scale.X); return (foo >> 1) + (foo & 1); } @@ -325,9 +326,6 @@ public: } bool TrimBorders(uint16_t* rect); - void SetSpriteRect(); - bool ShouldExpandSprite(); - void SetupSpriteData(); int GetAreas(FloatRect** pAreas) const; // Returns the whole texture, stored in column-major order @@ -360,19 +358,6 @@ public: protected: ISoftwareTexture *SoftwareTexture = nullptr; - public: - // Material layers - FTexture *Brightmap = nullptr; - FTexture* Detailmap = nullptr; - FTexture* Glowmap = nullptr; - FTexture *Normal = nullptr; // Normal map texture - FTexture *Specular = nullptr; // Specular light texture for the diffuse+normal+specular light model - FTexture *Metallic = nullptr; // Metalness texture for the physically based rendering (PBR) light model - FTexture *Roughness = nullptr; // Roughness texture for PBR - FTexture *AmbientOcclusion = nullptr; // Ambient occlusion texture for PBR - - FTexture *CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES] = { nullptr }; // Custom texture maps for custom hardware shaders - protected: FString Name; @@ -623,127 +608,145 @@ public: // Refactoring helper to allow piece by piece adjustment of the API class FGameTexture { - FTexture *wrapped; + friend class FMaterial; + + // Material layers + RefCountedPtr Base; + RefCountedPtr Brightmap; + RefCountedPtr Detailmap; + RefCountedPtr Glowmap; + RefCountedPtr Normal; // Normal map texture + RefCountedPtr Specular; // Specular light texture for the diffuse+normal+specular light model + RefCountedPtr Metallic; // Metalness texture for the physically based rendering (PBR) light model + RefCountedPtr Roughness; // Roughness texture for PBR + RefCountedPtr AmbientOcclusion; // Ambient occlusion texture for PBR + RefCountedPtr CustomShaderTextures[MAX_CUSTOM_HW_SHADER_TEXTURES]; // Custom texture maps for custom hardware shaders + int8_t shouldUpscaleFlag = 0; // Without explicit setup, scaling is disabled for a texture. ETextureType UseType = ETextureType::Wall; // This texture's primary purpose public: - FGameTexture(FTexture* wrap) : wrapped(wrap) {} + FGameTexture(FTexture* wrap) : Base(wrap) {} ~FGameTexture(); void CreateDefaultBrightmap(); + void AddAutoMaterials(); + bool ShouldExpandSprite(); + void SetupSpriteData(); + void SetSpriteRect(); ETextureType GetUseType() const { return UseType; } void SetUpscaleFlag(int what) { shouldUpscaleFlag = what; } int GetUpscaleFlag() { return shouldUpscaleFlag; } - FTexture* GetTexture() { return wrapped; } - int GetSourceLump() const { return wrapped->GetSourceLump(); } - void SetBrightmap(FGameTexture* tex) { wrapped->Brightmap = tex->GetTexture(); } + FTexture* GetTexture() { return Base.get(); } + int GetSourceLump() const { return Base->GetSourceLump(); } + void SetBrightmap(FGameTexture* tex) { Brightmap = tex->GetTexture(); } - double GetDisplayWidth() /*const*/ { return wrapped->GetDisplayWidthDouble(); } - double GetDisplayHeight() /*const*/ { return wrapped->GetDisplayHeightDouble(); } - int GetTexelWidth() /*const*/ { return wrapped->GetTexelWidth(); } - int GetTexelHeight() /*const*/ { return wrapped->GetTexelHeight(); } - int GetTexelLeftOffset(int adjusted = 0) /*const*/ { return wrapped->GetTexelLeftOffset(adjusted); } - int GetTexelTopOffset(int adjusted = 0) /*const*/ { return wrapped->GetTexelTopOffset(adjusted); } - double GetDisplayLeftOffset(int adjusted = 0) /*const*/ { return wrapped->GetDisplayLeftOffsetDouble(adjusted); } - double GetDisplayTopOffset(int adjusted = 0) /*const*/ { return wrapped->GetDisplayTopOffsetDouble(adjusted); } + double GetDisplayWidth() /*const*/ { return Base->GetDisplayWidthDouble(); } + double GetDisplayHeight() /*const*/ { return Base->GetDisplayHeightDouble(); } + int GetTexelWidth() /*const*/ { return Base->GetTexelWidth(); } + int GetTexelHeight() /*const*/ { return Base->GetTexelHeight(); } + int GetTexelLeftOffset(int adjusted = 0) /*const*/ { return Base->GetTexelLeftOffset(adjusted); } + int GetTexelTopOffset(int adjusted = 0) /*const*/ { return Base->GetTexelTopOffset(adjusted); } + double GetDisplayLeftOffset(int adjusted = 0) /*const*/ { return Base->GetDisplayLeftOffsetDouble(adjusted); } + double GetDisplayTopOffset(int adjusted = 0) /*const*/ { return Base->GetDisplayTopOffsetDouble(adjusted); } + // For the hardware renderer. The software renderer's have been offloaded to FSoftwareTexture + int GetLeftOffsetHW() { return GetTexelLeftOffset(r_spriteadjustHW); } + int GetTopOffsetHW() { return GetTexelTopOffset(r_spriteadjustHW); } bool isValid() const { return UseType != ETextureType::Null; } - int isWarped() { return wrapped->isWarped(); } - void SetWarpStyle(int style) { wrapped->bWarped = style; } - bool isMasked() { return wrapped->isMasked(); } - bool isHardwareCanvas() const { return wrapped->isHardwareCanvas(); } // There's two here so that this can deal with software canvases in the hardware renderer later. - bool isSoftwareCanvas() const { return wrapped->isCanvas(); } + int isWarped() { return Base->isWarped(); } + void SetWarpStyle(int style) { Base->bWarped = style; } + bool isMasked() { return Base->isMasked(); } + bool isHardwareCanvas() const { return Base->isHardwareCanvas(); } // There's two here so that this can deal with software canvases in the hardware renderer later. + bool isSoftwareCanvas() const { return Base->isCanvas(); } bool isMiscPatch() const { return GetUseType() == ETextureType::MiscPatch; } // only used by the intermission screen to decide whether to tile the background image or not. - bool isMultiPatch() const { return wrapped->bMultiPatch; } - bool isFullbrightDisabled() const { return wrapped->isFullbrightDisabled(); } - bool isFullbright() const { return wrapped->isFullbright(); } - bool isFullNameTexture() const { return wrapped->bFullNameTexture; } - bool expandSprites() const { return wrapped->bExpandSprite; } - bool useWorldPanning() const { return wrapped->UseWorldPanning(); } - void SetWorldPanning(bool on) { wrapped->SetWorldPanning(on); } - bool allowNoDecals() const { return wrapped->allowNoDecals(); } - void SetNoDecals(bool on) { wrapped->bNoDecals = on; } - void SetTranslucent(bool on) { wrapped->bTranslucent = on; } + bool isMultiPatch() const { return Base->bMultiPatch; } + bool isFullbrightDisabled() const { return Base->isFullbrightDisabled(); } + bool isFullbright() const { return Base->isFullbright(); } + bool isFullNameTexture() const { return Base->bFullNameTexture; } + bool expandSprites() const { return Base->bExpandSprite; } + bool useWorldPanning() const { return Base->UseWorldPanning(); } + void SetWorldPanning(bool on) { Base->SetWorldPanning(on); } + bool allowNoDecals() const { return Base->allowNoDecals(); } + void SetNoDecals(bool on) { Base->bNoDecals = on; } + void SetTranslucent(bool on) { Base->bTranslucent = on; } void SetUseType(ETextureType type) { UseType = type; } - int GetShaderIndex() const { return wrapped->shaderindex; } - float GetShaderSpeed() const { return wrapped->GetShaderSpeed(); } - uint16_t GetRotations() const { return wrapped->GetRotations(); } - void SetRotations(int index) { wrapped->SetRotations(index); } - void SetSkyOffset(int ofs) { wrapped->SetSkyOffset(ofs); } - int GetSkyOffset() const { return wrapped->GetSkyOffset(); } - FTextureID GetID() const { return wrapped->GetID(); } - ISoftwareTexture* GetSoftwareTexture() { return wrapped->GetSoftwareTexture(); } - void SetSoftwareTexture(ISoftwareTexture* swtex) { wrapped->SetSoftwareTextue(swtex); } - void SetScale(DVector2 vec) { wrapped->SetScale(vec); } - const FString& GetName() const { return wrapped->GetName(); } - void SetShaderSpeed(float speed) { wrapped->shaderspeed = speed; } - void SetShaderIndex(int index) { wrapped->shaderindex = index; } + int GetShaderIndex() const { return Base->shaderindex; } + float GetShaderSpeed() const { return Base->GetShaderSpeed(); } + uint16_t GetRotations() const { return Base->GetRotations(); } + void SetRotations(int index) { Base->SetRotations(index); } + void SetSkyOffset(int ofs) { Base->SetSkyOffset(ofs); } + int GetSkyOffset() const { return Base->GetSkyOffset(); } + FTextureID GetID() const { return Base->GetID(); } + ISoftwareTexture* GetSoftwareTexture() { return Base->GetSoftwareTexture(); } + void SetSoftwareTexture(ISoftwareTexture* swtex) { Base->SetSoftwareTextue(swtex); } + void SetScale(DVector2 vec) { Base->SetScale(vec); } + const FString& GetName() const { return Base->GetName(); } + void SetShaderSpeed(float speed) { Base->shaderspeed = speed; } + void SetShaderIndex(int index) { Base->shaderindex = index; } void SetShaderLayers(MaterialLayers& lay) { // Only update layers that have something defind. - if (lay.Glossiness > -1000) wrapped->Glossiness = lay.Glossiness; - if (lay.SpecularLevel > -1000) wrapped->SpecularLevel = lay.SpecularLevel; - if (lay.Brightmap) wrapped->Brightmap = lay.Brightmap->GetTexture(); - if (lay.Normal) wrapped->Normal = lay.Normal->GetTexture(); - if (lay.Specular) wrapped->Specular = lay.Specular->GetTexture(); - if (lay.Metallic) wrapped->Metallic = lay.Metallic->GetTexture(); - if (lay.Roughness) wrapped->Roughness = lay.Roughness->GetTexture(); - if (lay.AmbientOcclusion) wrapped->AmbientOcclusion = lay.AmbientOcclusion->GetTexture(); + if (lay.Glossiness > -1000) Base->Glossiness = lay.Glossiness; + if (lay.SpecularLevel > -1000) Base->SpecularLevel = lay.SpecularLevel; + if (lay.Brightmap) Brightmap = lay.Brightmap->GetTexture(); + if (lay.Normal) Normal = lay.Normal->GetTexture(); + if (lay.Specular) Specular = lay.Specular->GetTexture(); + if (lay.Metallic) Metallic = lay.Metallic->GetTexture(); + if (lay.Roughness) Roughness = lay.Roughness->GetTexture(); + if (lay.AmbientOcclusion) AmbientOcclusion = lay.AmbientOcclusion->GetTexture(); for (int i = 0; i < MAX_CUSTOM_HW_SHADER_TEXTURES; i++) { - if (lay.CustomShaderTextures[i]) wrapped->CustomShaderTextures[i] = lay.CustomShaderTextures[i]->GetTexture(); + if (lay.CustomShaderTextures[i]) CustomShaderTextures[i] = lay.CustomShaderTextures[i]->GetTexture(); } } - float GetGlossiness() const { return wrapped->Glossiness; } - float GetSpecularLevel() const { return wrapped->SpecularLevel; } + float GetGlossiness() const { return Base->Glossiness; } + float GetSpecularLevel() const { return Base->SpecularLevel; } void CopySize(FGameTexture* BaseTexture) { - wrapped->CopySize(BaseTexture->wrapped); + Base->CopySize(BaseTexture->Base.get()); } // Glowing is a pure material property that should not filter down to the actual texture objects. - void GetGlowColor(float* data) { wrapped->GetGlowColor(data); } - bool isGlowing() const { return wrapped->isGlowing(); } - bool isAutoGlowing() const { return wrapped->isAutoGlowing(); } - int GetGlowHeight() const { return wrapped->GetGlowHeight(); } + void GetGlowColor(float* data) { Base->GetGlowColor(data); } + bool isGlowing() const { return Base->isGlowing(); } + bool isAutoGlowing() const { return Base->isAutoGlowing(); } + int GetGlowHeight() const { return Base->GetGlowHeight(); } void SetAutoGlowing() { auto tex = GetTexture(); tex->bAutoGlowing = tex->bGlowing = tex->bFullbright = true; } - void SetGlowHeight(int v) { wrapped->GlowHeight = v; } - void SetFullbright() { wrapped->bFullbright = true; } - void SetDisableFullbright(bool on) { wrapped->bDisableFullbright = on; } + void SetGlowHeight(int v) { Base->GlowHeight = v; } + void SetFullbright() { Base->bFullbright = true; } + void SetDisableFullbright(bool on) { Base->bDisableFullbright = on; } void SetGlowing(PalEntry color) { auto tex = GetTexture(); tex->bAutoGlowing = false; tex->bGlowing = true; tex->GlowColor = color; } bool isUserContent() const; - void AddAutoMaterials() { wrapped->AddAutoMaterials(); } - int CheckRealHeight() { return wrapped->CheckRealHeight(); } - bool isSkybox() const { return wrapped->isSkybox(); } - void SetSize(int x, int y) { wrapped->SetSize(x, y); } - void SetDisplaySize(float w, float h) { wrapped->SetSize((int)w, (int)h); } + int CheckRealHeight() { return Base->CheckRealHeight(); } + bool isSkybox() const { return Base->isSkybox(); } + void SetSize(int x, int y) { Base->SetSize(x, y); } + void SetDisplaySize(float w, float h) { Base->SetSize((int)w, (int)h); } - void SetSpriteRect() { wrapped->SetSpriteRect(); } - const SpritePositioningInfo& GetSpritePositioning(int which) { if (wrapped->spi == nullptr) wrapped->SetupSpriteData(); return wrapped->spi[which]; } - int GetAreas(FloatRect** pAreas) const { return wrapped->GetAreas(pAreas); } - PalEntry GetSkyCapColor(bool bottom) { return wrapped->GetSkyCapColor(bottom); } + const SpritePositioningInfo& GetSpritePositioning(int which) { if (Base->spi == nullptr) SetupSpriteData(); return Base->spi[which]; } + int GetAreas(FloatRect** pAreas) const { return Base->GetAreas(pAreas); } + PalEntry GetSkyCapColor(bool bottom) { return Base->GetSkyCapColor(bottom); } bool GetTranslucency() { - return wrapped->GetTranslucency(); + return Base->GetTranslucency(); } // Since these properties will later piggyback on existing members of FGameTexture, the accessors need to be here. FGameTexture *GetSkyFace(int num) { - return (isSkybox() ? static_cast(wrapped)->faces[num] : nullptr); + return (isSkybox() ? static_cast(Base.get())->faces[num] : nullptr); } - bool GetSkyFlip() { return isSkybox() ? static_cast(wrapped)->fliptop : false; } + bool GetSkyFlip() { return isSkybox() ? static_cast(Base.get())->fliptop : false; } int GetClampMode(int clampmode) { if (GetUseType() == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER; else if (isHardwareCanvas()) clampmode = CLAMP_CAMTEX; - else if ((isWarped() || wrapped->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; + else if ((isWarped() || Base->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; return clampmode; } }; diff --git a/src/common/utility/refcounted.h b/src/common/utility/refcounted.h new file mode 100644 index 000000000..b0c87d934 --- /dev/null +++ b/src/common/utility/refcounted.h @@ -0,0 +1,103 @@ +#pragma once + +// Simple lightweight reference counting pointer alternative for std::shared_ptr which stores the reference counter in the handled object itself. + + // Base class for handled objects +class RefCountedBase +{ +public: + void IncRef() { refCount++; } + void DecRef() { if (--refCount <= 0) delete this; } +private: + int refCount = 0; +protected: + virtual ~RefCountedBase() = default; +}; + + // The actual pointer object +template +class RefCountedPtr +{ +public: + ~RefCountedPtr() + { + if (ptr) ptr->DecRef(); + } + + RefCountedPtr() : ptr(nullptr) + {} + + explicit RefCountedPtr(T* p) : ptr(p) + { + if (ptr) ptr->IncRef(); + } + + RefCountedPtr & operator=(const RefCountedPtr& r) + { + if (ptr != r.ptr) + { + if (ptr) ptr->DecRef(); + ptr = r.ptr; + if (ptr) ptr->IncRef(); + } + return *this; + } + + RefCountedPtr& operator=(T* r) + { + if (ptr != r) + { + if (ptr) ptr->DecRef(); + ptr = r; + if (ptr) ptr->IncRef(); + } + return *this; + } + + RefCountedPtr & operator=(const RefCountedPtr&& r) + { + if (ptr) ptr->DecRef(); + ptr = r.ptr; + r.ptr = nullptr; + return *this; + } + + bool operator==(T* p) const + { + return ptr == p; + } + + bool operator!=(T* p) const + { + return ptr != p; + } + + bool operator==(const RefCountedPtr &p) const + { + return ptr == p.ptr; + } + + bool operator!=(const RefCountedPtr& p) const + { + return ptr != p.ptr; + } + + T& operator* () const + { + return *ptr; + } + + T* operator-> () const + { + return ptr; + } + + T* get() const + { + return ptr; + } + +private: + + T * ptr; +}; \ No newline at end of file