1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-10-31 15:35:21 +01:00

Add inventory image animation API (#16538)

This commit is contained in:
cx384
2025-10-26 18:48:53 +01:00
committed by GitHub
parent dde463635e
commit 93ccb4b355
23 changed files with 606 additions and 227 deletions

View File

@@ -10,10 +10,28 @@
#include "itemdef.h"
#include "inventory.h"
ItemVisualsManager::ItemVisuals::~ItemVisuals() {
if (wield_mesh.mesh)
wield_mesh.mesh->drop();
}
struct ItemVisualsManager::ItemVisuals
{
ItemMesh item_mesh;
Palette *palette;
AnimationInfo inventory_normal;
AnimationInfo inventory_overlay;
ItemVisuals() :
palette(nullptr)
{}
~ItemVisuals()
{
inventory_normal.freeFrames();
inventory_overlay.freeFrames();
if (item_mesh.mesh)
item_mesh.mesh->drop();
}
DISABLE_CLASS_COPY(ItemVisuals);
};
ItemVisualsManager::ItemVisuals *ItemVisualsManager::createItemVisuals( const ItemStack &item,
Client *client) const
@@ -24,13 +42,18 @@ ItemVisualsManager::ItemVisuals *ItemVisualsManager::createItemVisuals( const It
IItemDefManager *idef = client->idef();
const ItemDefinition &def = item.getDefinition(idef);
std::string inventory_image = item.getInventoryImage(idef);
std::string inventory_overlay = item.getInventoryOverlay(idef);
std::string cache_key = def.name;
if (!inventory_image.empty())
cache_key += "/" + inventory_image;
if (!inventory_overlay.empty())
cache_key += ":" + inventory_overlay;
ItemImageDef inventory_image = item.getInventoryImage(idef);
ItemImageDef inventory_overlay = item.getInventoryOverlay(idef);
// Key only consists of item name + image name,
// because animation currently cannot be overridden by meta
std::ostringstream os(def.name);
if (!inventory_image.name.empty())
os << "/" << inventory_image.name;
if (!inventory_overlay.name.empty())
os << ":" << inventory_overlay.name;
std::string cache_key = os.str();
// Skip if already in cache
auto it = m_cached_item_visuals.find(cache_key);
@@ -43,36 +66,105 @@ ItemVisualsManager::ItemVisuals *ItemVisualsManager::createItemVisuals( const It
ITextureSource *tsrc = client->getTextureSource();
// Create new ItemVisuals
auto cc = std::make_unique<ItemVisuals>();
auto iv = std::make_unique<ItemVisuals>();
cc->inventory_texture = NULL;
if (!inventory_image.empty())
cc->inventory_texture = tsrc->getTexture(inventory_image);
getItemMesh(client, item, &(cc->wield_mesh));
auto populate_texture_and_animation = [tsrc](
const ItemImageDef &image,
AnimationInfo &animation)
{
int frame_length_ms = 0;
auto frames = std::make_unique<std::vector<FrameSpec>>();
if (image.name.empty()) {
// no-op
} else if (image.animation.type == TileAnimationType::TAT_NONE) {
frames->push_back({0, tsrc->getTexture(image.name)});
} else {
// Animated
// Get inventory texture frames
*frames = createAnimationFrames(tsrc, image.name, image.animation, frame_length_ms);
}
animation = AnimationInfo(frames.release(), frame_length_ms);
// `frames` are freed in `ItemVisuals::~ItemVisuals`
};
cc->palette = tsrc->getPalette(def.palette_image);
populate_texture_and_animation(inventory_image, iv->inventory_normal);
populate_texture_and_animation(inventory_overlay, iv->inventory_overlay);
createItemMesh(client, def,
iv->inventory_normal,
iv->inventory_overlay,
&(iv->item_mesh));
iv->palette = tsrc->getPalette(def.palette_image);
// Put in cache
ItemVisuals *ptr = cc.get();
m_cached_item_visuals[cache_key] = std::move(cc);
ItemVisuals *ptr = iv.get();
m_cached_item_visuals[cache_key] = std::move(iv);
return ptr;
}
video::ITexture* ItemVisualsManager::getInventoryTexture(const ItemStack &item,
// Needed because `ItemVisuals` is not known in the header.
ItemVisualsManager::ItemVisualsManager()
{
m_main_thread = std::this_thread::get_id();
}
ItemVisualsManager::~ItemVisualsManager()
{
}
void ItemVisualsManager::clear()
{
m_cached_item_visuals.clear();
}
video::ITexture *ItemVisualsManager::getInventoryTexture(const ItemStack &item,
Client *client) const
{
ItemVisuals *iv = createItemVisuals(item, client);
if (!iv)
return nullptr;
return iv->inventory_texture;
// Texture animation update (if >1 frame)
return iv->inventory_normal.getTexture(client->getAnimationTime());
}
ItemMesh* ItemVisualsManager::getWieldMesh(const ItemStack &item, Client *client) const
video::ITexture *ItemVisualsManager::getInventoryOverlayTexture(const ItemStack &item,
Client *client) const
{
ItemVisuals *iv = createItemVisuals(item, client);
if (!iv)
return nullptr;
return &(iv->wield_mesh);
// Texture animation update (if >1 frame)
return iv->inventory_overlay.getTexture(client->getAnimationTime());
}
ItemMesh *ItemVisualsManager::getItemMesh(const ItemStack &item, Client *client) const
{
ItemVisuals *iv = createItemVisuals(item, client);
return iv ? &(iv->item_mesh) : nullptr;
}
AnimationInfo *ItemVisualsManager::getInventoryAnimation(const ItemStack &item,
Client *client) const
{
ItemVisuals *iv = createItemVisuals(item, client);
if (!iv || iv->inventory_normal.getFrameCount() <= 1)
return nullptr;
return &iv->inventory_normal;
}
// Get item inventory overlay animation
// returns nullptr if it is not animated
AnimationInfo *ItemVisualsManager::getInventoryOverlayAnimation(const ItemStack &item,
Client *client) const
{
ItemVisuals *iv = createItemVisuals(item, client);
if (!iv || iv->inventory_overlay.getFrameCount() <= 1)
return nullptr;
return &iv->inventory_overlay;
}
Palette* ItemVisualsManager::getPalette(const ItemStack &item, Client *client) const