Files
leocad/common/lc_texturemanager.cpp
T
Leonardo Zide 98c67f3705 Align texture acquisition and scoped ownership
Texture lookup previously acquired references implicitly, and mesh sections and
loader requests paired raw texture pointers with manual release paths. Separate
borrowed lookup from scoped acquisition and explicit load requests/waits to match
the piece data ownership API.

Store lcTextureRef in mesh sections and loader requests, retain references on
section copies, and reset worker-shared request handles on the UI thread before
completion, cancellation, or shutdown. Keep reference primitives internal and use
scoped acquisitions for merge validation. Remove redundant section initialization
and synth-notification resets, and document the resulting ownership contracts.

Validation: macOS Debug build, diff whitespace checks, and 30 offscreen lifecycle
checks covering reference copies/moves, texture dependencies, cancellation,
shutdown, merge conflicts, and existing piece ownership paths. Successful GPU
upload/rendering is not covered by the offscreen checks.
2026-10-19 10:38:51 -07:00

136 lines
3.0 KiB
C++

#include "lc_global.h"
#include "lc_texturemanager.h"
#include "lc_file.h"
#include "lc_string.h"
lcTextureManager::~lcTextureManager()
{
Clear();
}
void lcTextureManager::Clear()
{
QMutexLocker Lock(&mMutex);
for (lcTexture* Texture : mTextures)
delete Texture;
mTextures.clear();
}
void lcTextureManager::AddTextureReference(lcTexture* Texture)
{
QMutexLocker Lock(&mMutex);
Texture->AddRef();
}
lcTexture* lcTextureManager::FindTexture(const lcFileSource& Source)
{
QMutexLocker Lock(&mMutex);
for (lcTexture* Texture : mTextures)
if (Texture->mSource == Source)
return Texture;
return nullptr;
}
lcTexture* lcTextureManager::AcquireTexture(const char* TextureName, const lcFileSource& Source, const QString& ProjectPath)
{
if (!TextureName[0] || strlen(TextureName) >= LC_TEXTURE_NAME_LEN)
return nullptr;
if (!Source.EmbeddedData && Source.FilePath.isEmpty() && Source.ArchiveIndex == -1)
return nullptr;
QMutexLocker Lock(&mMutex);
for (lcTexture* Texture : mTextures)
{
if (Texture->mSource != Source)
continue;
Texture->AddRef();
return Texture;
}
lcTexture* Texture = new lcTexture(LC_TEXTURE_MIPMAPS);
lcstrcpy(Texture->mName, TextureName);
Texture->mSource = Source;
Texture->SetTemporary(bool(Source.EmbeddedData) || !ProjectPath.isEmpty());
Texture->AddRef();
mTextures.push_back(Texture);
return Texture;
}
lcTextureBuildResult lcTextureManager::BuildTextureData(lcFile& File)
{
lcTextureBuildResult Result = DecodeTextureData(File);
if (!Result.DecodedImage.isNull())
{
Result.DecodedImage = lcTexture::PrepareImage(std::move(Result.DecodedImage));
if (Result.DecodedImage.isNull())
Result.Error = lcTextureLoadError::DecodeFailed;
}
return Result;
}
lcTextureBuildResult lcTextureManager::DecodeTextureData(lcFile& File)
{
lcTextureBuildResult Result;
bool Loaded = false;
if (lcMemFile* MemoryFile = dynamic_cast<lcMemFile*>(&File))
{
if (MemoryFile->mBuffer && MemoryFile->mPosition < MemoryFile->mFileSize)
{
const size_t Length = MemoryFile->mFileSize - MemoryFile->mPosition;
if (Length <= static_cast<size_t>(std::numeric_limits<int>::max()))
Loaded = Result.DecodedImage.loadFromData(MemoryFile->mBuffer + MemoryFile->mPosition, static_cast<int>(Length));
}
}
else if (lcDiskFile* DiskFile = dynamic_cast<lcDiskFile*>(&File))
{
QFile& Device = DiskFile->GetFile();
const qint64 Position = Device.pos();
if (Position >= 0)
{
Loaded = Result.DecodedImage.load(&Device, nullptr);
const bool Restored = Device.seek(Position);
Loaded = Loaded && Restored;
}
}
if (!Loaded || Result.DecodedImage.isNull())
{
Result.DecodedImage = QImage();
Result.Error = lcTextureLoadError::DecodeFailed;
}
return Result;
}
void lcTextureManager::ReleaseTexture(lcTexture* Texture)
{
QMutexLocker Lock(&mMutex);
if (Texture->Release() == 0 && Texture->IsTemporary())
{
std::vector<lcTexture*>::iterator TextureIt = std::find(mTextures.begin(), mTextures.end(), Texture);
if (TextureIt != mTextures.end())
mTextures.erase(TextureIt);
delete Texture;
}
}