Files
FlaxEngine/Source/Engine/Render2D/SpriteAtlas.cpp
2022-10-20 17:28:12 +02:00

198 lines
4.5 KiB
C++

// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#include "SpriteAtlas.h"
#include "Engine/Core/Log.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Serialization/MemoryWriteStream.h"
#include "Engine/Content/Loading/Tasks/LoadAssetDataTask.h"
#include "Engine/Content/Upgraders/TextureAssetUpgrader.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Graphics/GPUDevice.h"
const SpriteHandle SpriteHandle::Invalid = { nullptr, INVALID_INDEX };
REGISTER_BINARY_ASSET_WITH_UPGRADER(SpriteAtlas, "FlaxEngine.SpriteAtlas", TextureAssetUpgrader, true);
bool SpriteHandle::GetSprite(Sprite* result) const
{
if (IsValid())
{
*result = Atlas->Sprites[Index];
return true;
}
return false;
}
bool SpriteHandle::IsValid() const
{
return Atlas && Index >= 0 && Atlas->Sprites.Count() > Index;
}
GPUTexture* SpriteHandle::GetAtlasTexture() const
{
ASSERT(Atlas);
return Atlas->GetTexture();
}
SpriteAtlas::SpriteAtlas(const SpawnParams& params, const AssetInfo* info)
: TextureBase(params, info)
{
}
int32 SpriteAtlas::GetSpritesCount() const
{
return Sprites.Count();
}
Sprite SpriteAtlas::GetSprite(int32 index) const
{
CHECK_RETURN(index >= 0 && index < Sprites.Count(), Sprite())
return Sprites.Get()[index];
}
void SpriteAtlas::SetSprite(int32 index, const Sprite& value)
{
CHECK(index >= 0 && index < Sprites.Count());
Sprites.Get()[index] = value;
}
SpriteHandle SpriteAtlas::FindSprite(const StringView& name) const
{
SpriteHandle result(const_cast<SpriteAtlas*>(this), -1);
for (int32 i = 0; i < Sprites.Count(); i++)
{
if (name == Sprites[i].Name)
{
result.Index = i;
break;
}
}
return result;
}
SpriteHandle SpriteAtlas::AddSprite(const Sprite& sprite)
{
const int32 index = Sprites.Count();
Sprites.Add(sprite);
return SpriteHandle(this, index);
}
void SpriteAtlas::RemoveSprite(int32 index)
{
Sprites.RemoveAt(index);
}
#if USE_EDITOR
bool SpriteAtlas::SaveSprites()
{
ScopeLock lock(Locker);
// Load whole asset
if (LoadChunks(ALL_ASSET_CHUNKS))
{
return true;
}
// Prepare asset data
AssetInitData data;
data.SerializedVersion = 4;
data.CustomData.Copy(_texture.GetHeader());
// Write sprites data
MemoryWriteStream stream(1024);
stream.WriteInt32(1); // Version
stream.WriteInt32(Sprites.Count()); // Sprites Count
for (Sprite& t : Sprites)
{
stream.Write(t.Area);
stream.WriteString(t.Name, 49);
}
// Link sprites data (unlink after safe)
auto dataChunk = GetOrCreateChunk(15);
dataChunk->Data.Link(stream.GetHandle(), stream.GetLength());
// Save (use silent mode to prevent asset reloading)
bool saveResult = SaveAsset(data, true);
dataChunk->Data.Unlink();
if (saveResult)
{
LOG(Warning, "Failed to save sprite atlas \'{0}\'.", GetPath());
return true;
}
return false;
}
#endif
bool SpriteAtlas::LoadSprites(ReadStream& stream)
{
ScopeLock lock(Locker);
// Sprites may be used on rendering thread so lock drawing for a while
#if USE_EDITOR
GPUDevice* gpuDevice = GPUDevice::Instance;
if (gpuDevice)
gpuDevice->Locker.Lock();
#endif
Sprites.Clear();
int32 tilesVersion, tilesCount;
stream.ReadInt32(&tilesVersion);
if (tilesVersion != 1)
{
#if USE_EDITOR
if (gpuDevice)
gpuDevice->Locker.Unlock();
#endif
LOG(Warning, "Invalid tiles version.");
return true;
}
stream.ReadInt32(&tilesCount);
Sprites.Resize(tilesCount);
for (Sprite& t : Sprites)
{
stream.Read(t.Area);
stream.ReadString(&t.Name, 49);
}
#if USE_EDITOR
if (gpuDevice)
gpuDevice->Locker.Unlock();
#endif
return false;
}
Asset::LoadResult SpriteAtlas::load()
{
auto spritesDataChunk = GetChunk(15);
if (spritesDataChunk == nullptr || spritesDataChunk->IsMissing())
return LoadResult::MissingDataChunk;
MemoryReadStream spritesData(spritesDataChunk->Get(), spritesDataChunk->Size());
if (LoadSprites(spritesData))
{
LOG(Warning, "Cannot load sprites atlas data.");
return LoadResult::Failed;
}
return TextureBase::load();
}
void SpriteAtlas::unload(bool isReloading)
{
Sprites.Resize(0);
// Base
TextureBase::unload(isReloading);
}
AssetChunksFlag SpriteAtlas::getChunksToPreload() const
{
return GET_CHUNK_FLAG(15);
}