You're breathtaking!
This commit is contained in:
191
Source/Engine/Render2D/SpriteAtlas.cpp
Normal file
191
Source/Engine/Render2D/SpriteAtlas.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
// Copyright (c) 2012-2020 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(SpriteAtlas, "FlaxEngine.SpriteAtlas", ::New<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 != INVALID_INDEX && Atlas->Sprites.Count() > Index;
|
||||
}
|
||||
|
||||
GPUTexture* SpriteHandle::GetAtlasTexture() const
|
||||
{
|
||||
ASSERT(Atlas);
|
||||
return Atlas->GetTexture();
|
||||
}
|
||||
|
||||
SpriteAtlas::SpriteAtlas(const SpawnParams& params, const AssetInfo* info)
|
||||
: TextureBase(params, info)
|
||||
{
|
||||
}
|
||||
|
||||
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 (int32 i = 0; i < Sprites.Count(); i++)
|
||||
{
|
||||
// Save sprite
|
||||
Sprite t = Sprites[i];
|
||||
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.Release();
|
||||
if (saveResult)
|
||||
{
|
||||
LOG(Warning, "Failed to save sprite atlas \'{0}\'.", GetPath());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool SpriteAtlas::LoadSprites(ReadStream& stream)
|
||||
{
|
||||
#if USE_EDITOR
|
||||
// Sprites may be used on rendering thread so lock drawing for a while
|
||||
if (GPUDevice::Instance)
|
||||
GPUDevice::Instance->Locker.Lock();
|
||||
#endif
|
||||
|
||||
// Cleanup first
|
||||
Sprites.Clear();
|
||||
|
||||
// Load tiles data
|
||||
int32 tilesVersion, tilesCount;
|
||||
stream.ReadInt32(&tilesVersion);
|
||||
if (tilesVersion != 1)
|
||||
{
|
||||
#if USE_EDITOR
|
||||
if (GPUDevice::Instance)
|
||||
GPUDevice::Instance->Locker.Unlock();
|
||||
#endif
|
||||
LOG(Warning, "Invalid tiles version.");
|
||||
return true;
|
||||
}
|
||||
stream.ReadInt32(&tilesCount);
|
||||
Sprites.Resize(tilesCount);
|
||||
for (int32 i = 0; i < tilesCount; i++)
|
||||
{
|
||||
// Load sprite
|
||||
Sprite& t = Sprites[i];
|
||||
stream.Read(&t.Area);
|
||||
stream.ReadString(&t.Name, 49);
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
if (GPUDevice::Instance)
|
||||
GPUDevice::Instance->Locker.Unlock();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
Asset::LoadResult SpriteAtlas::load()
|
||||
{
|
||||
// Get sprites data
|
||||
auto spritesDataChunk = GetChunk(15);
|
||||
if (spritesDataChunk == nullptr || spritesDataChunk->IsMissing())
|
||||
return LoadResult::MissingDataChunk;
|
||||
MemoryReadStream spritesData(spritesDataChunk->Get(), spritesDataChunk->Size());
|
||||
|
||||
// Load sprites
|
||||
if (LoadSprites(spritesData))
|
||||
{
|
||||
LOG(Warning, "Cannot load sprites atlas data.");
|
||||
return LoadResult::Failed;
|
||||
}
|
||||
|
||||
return TextureBase::load();
|
||||
}
|
||||
|
||||
void SpriteAtlas::unload(bool isReloading)
|
||||
{
|
||||
// Release sprites
|
||||
Sprites.Resize(0);
|
||||
|
||||
// Base
|
||||
TextureBase::unload(isReloading);
|
||||
}
|
||||
|
||||
AssetChunksFlag SpriteAtlas::getChunksToPreload() const
|
||||
{
|
||||
return GET_CHUNK_FLAG(15);
|
||||
}
|
||||
Reference in New Issue
Block a user