198 lines
4.5 KiB
C++
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);
|
|
}
|