50. Asset Management¶
Learn about the asset management feature that allows you to access asset data such as Texture
, Font
, and Audio
from anywhere in your program.
50.1 Overview of Asset Management¶
- Siv3D has an "asset management" feature that allows you to assign names to asset handles like
Texture
,Font
, andAudio
, and access them like global variables from anywhere in your program through those names
50.1.1 Steps for Handling Asset Management¶
- Asset "Registration"
- Asset "Loading" (optional)
- Asset "Usage"
- Asset "Release" (optional)
- Asset "Unregistration" (optional)
50.1.2 Registration¶
- Register assets with the engine
- Call the appropriate function for the asset type (whether it's a texture, audio, etc.), assign a unique name to the asset, and register information such as file names and properties
- Unless otherwise specified, asset data is not constructed at this point, so registration does not increase memory consumption
50.1.3 Loading¶
- Actually load the asset data
- Specify the asset name, and the engine constructs asset data in memory according to the file name and properties given during asset registration
- If the specified asset is already loaded, nothing is done
- Options for asynchronous loading are also provided
50.1.4 Usage¶
- Specify the asset name to get
Texture
orAudio
, and use them to.draw()
or.play()
as usual - If the corresponding asset is not loaded, loading is automatically performed at this timing
- If the specified asset is not registered or is being loaded asynchronously, an empty
Texture
orAudio
is returned
50.1.5 Release¶
- Release asset data from memory while keeping registration information
- Since the asset registration information remains after release, you can load or use it again
- It's good to release assets when you won't use a once-loaded asset for a while and want to reduce memory consumption
50.1.6 Unregistration¶
- Delete asset registration information and name from asset management
- If the corresponding asset is not released, it is automatically released
- When the application terminates, all assets are automatically released and unregistered, so explicit unregistration is not necessary
50.1.7 Functions for Various Operations¶
Code | Description |
---|---|
Register(name, ...) |
Register an asset |
IsRegistered(name) |
Returns whether an asset is registered |
Load(name) |
Load an asset |
LoadAsync(name) |
Start asynchronous loading of an asset |
Wait(name) |
Wait until asynchronous loading of an asset is complete |
IsReady(name) |
Returns whether asset loading is complete (regardless of success or failure) |
Release(name) |
Release an asset |
Unregister(name) |
Unregister an asset |
ReleaseAll() |
Release all registered assets |
UnregisterAll() |
Unregister all registered assets |
Enumerate() |
Enumerate information list of all registered assets |
50.2 Texture Assets¶
- When handling
Texture
through asset management, use functions that start withTextureAsset::
- Access
Texture
assets withTextureAsset(name)
- The following sample code registers
example/windmill.png
with the name"Windmill"
, registersexample/siv3d-kun.png
with the name"Siv3D-kun"
, and registers the emoji 🐈 with the name"Cat"
# include <Siv3D.hpp>
void Draw()
{
// Use Texture assets
TextureAsset(U"Windmill").draw(40, 40);
TextureAsset(U"Siv3D-kun").scaled(0.8).drawAt(300, 300);
TextureAsset(U"Cat").drawAt(600, 400);
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
// Register Texture assets
TextureAsset::Register(U"Windmill", U"example/windmill.png");
TextureAsset::Register(U"Siv3D-kun", U"example/siv3d-kun.png", TextureDesc::Mipped);
TextureAsset::Register(U"Cat", U"🐈"_emoji);
while (System::Update())
{
Draw();
}
}
50.3 Advanced Texture Assets¶
- When registering complex Texture assets that create textures from
Image
or perform preprocessing during loading, useTextureAssetData
- Create an empty
TextureAssetData
and set a function object with the signaturebool(TextureAssetData& asset, const String&)
that describes the loading process in theonLoad
member variable - This function object is automatically called when the asset is loaded
- You are required to assign a texture to
asset.texture
to construct the asset data - The following sample uses
TextureAssetData
to register images generated by the program and reduced versions of images loaded from files as textures- The
Image
class is explained in detail in Tutorial 63
- The
# include <Siv3D.hpp>
std::unique_ptr<TextureAssetData> MakeTextureAssetData1()
{
// Create empty texture asset data
std::unique_ptr<TextureAssetData> assetData = std::make_unique<TextureAssetData>();
// Set the loading job
assetData->onLoad = [](TextureAssetData& asset, const String&)
{
// Assign texture to asset data
asset.texture = Texture{ Image{ 256, 256, Palette::Seagreen }, TextureDesc::Mipped };
return static_cast<bool>(asset.texture);
};
return assetData;
}
std::unique_ptr<TextureAssetData> MakeTextureAssetData2(const FilePath& path, const TextureDesc textureDesc)
{
// Create empty texture asset data
std::unique_ptr<TextureAssetData> assetData = std::make_unique<TextureAssetData>();
// Assign file path
assetData->path = path;
// Assign texture settings
assetData->desc = textureDesc;
// Set the loading job
assetData->onLoad = [](TextureAssetData& asset, const String&)
{
// Scale the image from the specified file path by 0.5 and make it a texture
asset.texture = Texture{ Image{ asset.path }.scaled(0.5), asset.desc };
return static_cast<bool>(asset.texture);
};
return assetData;
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
// Register assets (using custom texture asset data)
TextureAsset::Register(U"MyTexture1", MakeTextureAssetData1());
TextureAsset::Register(U"MyTexture2", MakeTextureAssetData2(U"example/windmill.png", TextureDesc::Mipped));
TextureAsset::Register(U"MyTexture3", MakeTextureAssetData2(U"example/siv3d-kun.png", TextureDesc::Mipped));
while (System::Update())
{
TextureAsset(U"MyTexture1").draw(100, 100);
TextureAsset(U"MyTexture2").draw(300, 300);
TextureAsset(U"MyTexture3").draw(400, 200);
}
}
50.4 Font Assets¶
- When handling
Font
through asset management, use functions that start withFontAsset::
- Access
Font
assets withFontAsset(name)
# include <Siv3D.hpp>
void Draw()
{
// Use assets
FontAsset(U"Title")(U"My Game").drawAt(80, Vec2{ 400, 100 }, Palette::Seagreen);
FontAsset(U"Menu")(U"Play").drawAt(40, Vec2{ 400, 400 }, ColorF{ 0.1 });
FontAsset(U"Menu")(U"Exit").drawAt(40, Vec2{ 400, 500 }, ColorF{ 0.1 });
}
void Main()
{
Scene::SetBackground(ColorF{ 0.6, 0.8, 0.7 });
// Register assets
FontAsset::Register(U"Title", FontMethod::MSDF, 48, U"example/font/RocknRoll/RocknRollOne-Regular.ttf");
FontAsset::Register(U"Menu", FontMethod::MSDF, 48, Typeface::Bold);
while (System::Update())
{
Draw();
}
}
50.5 Audio Assets¶
- When handling
Audio
through asset management, use functions that start withAudioAsset::
- Access
Audio
assets withAudioAsset(name)
# include <Siv3D.hpp>
void PlayPiano()
{
// Use assets
AudioAsset(U"Piano").playOneShot();
}
void PlayShot()
{
// Use assets
AudioAsset(U"SE").playOneShot();
}
void Main()
{
// Register assets
AudioAsset::Register(U"BGM", Audio::Stream, U"example/test.mp3");
AudioAsset::Register(U"SE", U"example/shot.mp3");
AudioAsset::Register(U"Piano", GMInstrument::Piano1, PianoKey::A4, 0.5s);
// Use assets
AudioAsset(U"BGM").setVolume(0.2);
AudioAsset(U"BGM").play();
while (System::Update())
{
if (MouseL.down())
{
PlayPiano();
}
if (MouseR.down())
{
PlayShot();
}
}
}
50.6 Preloading¶
- Using
Load()
for each asset immediately loads the asset if it is not loaded - If you want to prevent frame time spikes caused by loading assets during game progress, you can use this function to preload on loading screens, etc.
- In
FontAsset::Load()
, you can also pass text to preload - You can check if asset loading is complete with
IsReady()
# include <Siv3D.hpp>
void Main()
{
const String preloadText = U"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
FontAsset::Register(U"MyFont", FontMethod::MSDF, 48, Typeface::Bold);
TextureAsset::Register(U"MyTexture", U"example/bay.jpg");
AudioAsset::Register(U"MyAudio", Audio::Stream, U"example/test.mp3");
AudioAsset::Register(U"MyMIDI", U"example/midi/test.mid");
// Preload
FontAsset::Load(U"MyFont", preloadText);
TextureAsset::Load(U"MyTexture");
AudioAsset::Load(U"MyAudio");
AudioAsset::Load(U"MyMIDI");
// Confirm that loading is complete
Print << FontAsset::IsReady(U"MyFont");
Print << TextureAsset::IsReady(U"MyTexture");
Print << AudioAsset::IsReady(U"MyAudio");
Print << AudioAsset::IsReady(U"MyMIDI");
while (System::Update())
{
}
}
50.7 Asynchronous Loading¶
- Using
LoadAsync()
for each asset starts asynchronous loading of the asset using a separate thread if the asset is not loaded - This avoids blocking the main thread processing during asset loading
- You can check if asynchronous loading of an asset is complete with
IsReady()
Wait()
causes the main thread to wait until loading is complete- If you access an asset during asynchronous loading, an empty asset is returned
- Especially with Audio assets, playing empty assets can produce unexpected sounds (Tutorial 41.7), so caution is needed
Note for OpenGL Backend
- With the OpenGL backend (default for macOS and Linux, and when selected on Windows), asynchronous loading of
TextureAsset
progresses withinSystem::Update()
- During asynchronous loading of
TextureAsset
, please callSystem::Update()
at the usual frequency
# include <Siv3D.hpp>
void Main()
{
const String preloadText = U"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
FontAsset::Register(U"MyFont", FontMethod::MSDF, 48, Typeface::Bold);
TextureAsset::Register(U"MyTexture", U"example/bay.jpg");
AudioAsset::Register(U"MyAudio", Audio::Stream, U"example/test.mp3");
AudioAsset::Register(U"MyMIDI", U"example/midi/test.mid");
// Start asynchronous loading
FontAsset::LoadAsync(U"MyFont", preloadText);
TextureAsset::LoadAsync(U"MyTexture");
AudioAsset::LoadAsync(U"MyAudio");
AudioAsset::LoadAsync(U"MyMIDI");
while (System::Update())
{
ClearPrint();
// Check if loading is complete
Print << FontAsset::IsReady(U"MyFont");
Print << TextureAsset::IsReady(U"MyTexture");
Print << AudioAsset::IsReady(U"MyAudio");
Print << AudioAsset::IsReady(U"MyMIDI");
}
}
50.8 Asset List and Tags¶
- In
Register()
, you can register asset names and asset tags with{ assetName, { assetTag, ... } }
- Combined with
::Enumerate()
which gets a list of registered assets, this makes asset management convenient for loading and releasing assets with specific tags
# include <Siv3D.hpp>
void Main()
{
AudioAsset::Register({ U"BGM-0", { U"BGM" } }, Audio::Stream, U"example/test.mp3");
AudioAsset::Register({ U"BGM-1", { U"BGM" } }, U"example/midi/test.mid");
AudioAsset::Register({ U"PianoC", { U"SE", U"Piano" } }, GMInstrument::Piano1, PianoKey::C4, 0.5s);
AudioAsset::Register({ U"PianoD", { U"SE", U"Piano" } }, GMInstrument::Piano1, PianoKey::D4, 0.5s);
AudioAsset::Register({ U"PianoE", { U"SE", U"Piano" } }, GMInstrument::Piano1, PianoKey::E4, 0.5s);
AudioAsset::Register({ U"TrumpetC", { U"SE", U"Trumpet" } }, GMInstrument::Trumpet, PianoKey::C4, 0.5s);
AudioAsset::Register({ U"TrumpetD", { U"SE", U"Trumpet" } }, GMInstrument::Trumpet, PianoKey::D4, 0.5s);
AudioAsset::Register({ U"TrumpetE", { U"SE", U"Trumpet" } }, GMInstrument::Trumpet, PianoKey::E4, 0.5s);
for (auto&& [name, info] : AudioAsset::Enumerate())
{
Print << name << U": " << info.tags;
// Load only assets with the "SE" tag
if (info.tags.includes(U"SE"))
{
AudioAsset::Load(name);
}
}
Print << U"---";
Print << AudioAsset::IsReady(U"BGM-0");
Print << AudioAsset::IsReady(U"BGM-1");
Print << AudioAsset::IsReady(U"PianoC");
Print << AudioAsset::IsReady(U"PianoD");
Print << AudioAsset::IsReady(U"PianoE");
Print << AudioAsset::IsReady(U"TrumpetC");
Print << AudioAsset::IsReady(U"TrumpetD");
Print << AudioAsset::IsReady(U"TrumpetE");
while (System::Update())
{
}
}