1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-10-29 06:35:20 +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

@@ -301,17 +301,8 @@ void WieldMeshSceneNode::setExtruded(const TileDef &d0, const TileLayer &l0,
extractTexture(d1, l1, tsrc), wield_scale);
// Add color
m_buffer_info.clear();
m_buffer_info.emplace_back(0, l0.has_color, l0.color);
m_buffer_info.emplace_back(1, l1.has_color, l1.color);
}
void WieldMeshSceneNode::setExtruded(const std::string &image,
const std::string &overlay, v3f wield_scale, ITextureSource *tsrc)
{
video::ITexture *texture = tsrc->getTexture(image);
video::ITexture *overlay_texture =
overlay.empty() ? nullptr : tsrc->getTexture(overlay);
setExtruded(texture, overlay_texture, wield_scale);
m_buffer_info.emplace_back(0, l0);
m_buffer_info.emplace_back(1, l1);
}
void WieldMeshSceneNode::setExtruded(video::ITexture *texture,
@@ -322,11 +313,13 @@ void WieldMeshSceneNode::setExtruded(video::ITexture *texture,
return;
}
// Get mesh from cache
core::dimension2d<u32> dim = texture->getSize();
scene::IMesh *original = g_extrusion_mesh_cache->create(dim);
scene::SMesh *mesh = cloneStaticMesh(original);
original->drop();
// Set texture
mesh->getMeshBuffer(0)->getMaterial().setTexture(0, texture);
if (overlay_texture) {
// duplicate the extruded mesh for the overlay
@@ -416,6 +409,38 @@ static scene::SMesh *createGenericNodeMesh(Client *client, MapNode n,
return mesh;
}
std::vector<FrameSpec> createAnimationFrames(ITextureSource *tsrc,
const std::string &image_name, const TileAnimationParams &animation,
int &result_frame_length_ms)
{
result_frame_length_ms = 0;
if (image_name.empty() || animation.type == TileAnimationType::TAT_NONE)
return {};
video::ITexture *orginal_texture = tsrc->getTexture(image_name);
if (!orginal_texture)
return {};
int frame_count = 1;
auto orginal_size = orginal_texture->getOriginalSize();
animation.determineParams(orginal_size, &frame_count, &result_frame_length_ms, nullptr);
std::vector<FrameSpec> frames(frame_count);
std::ostringstream os(std::ios::binary);
for (int i = 0; i < frame_count; i++) {
os.str("");
os << image_name;
animation.getTextureModifer(os, orginal_size, i);
u32 id;
frames[i].texture = tsrc->getTextureForMesh(os.str(), &id);
frames[i].texture_id = id;
}
return frames;
}
void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool check_wield_image)
{
ITextureSource *tsrc = client->getTextureSource();
@@ -438,16 +463,46 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
m_buffer_info.clear();
m_base_color = item_visuals->getItemstackColor(item, client);
const std::string wield_image = item.getWieldImage(idef);
const std::string wield_overlay = item.getWieldOverlay(idef);
const ItemImageDef wield_image = item.getWieldImage(idef);
const ItemImageDef wield_overlay = item.getWieldOverlay(idef);
const v3f wield_scale = item.getWieldScale(idef);
// If wield_image needs to be checked and is defined, it overrides everything else
if (!wield_image.empty() && check_wield_image) {
setExtruded(wield_image, wield_overlay, wield_scale, tsrc);
m_buffer_info.emplace_back(0);
// overlay is white, if present
m_buffer_info.emplace_back(1, true, video::SColor(0xFFFFFFFF));
if (!wield_image.name.empty() && check_wield_image) {
video::ITexture *wield_texture;
video::ITexture *wield_overlay_texture = nullptr;
int frame_length_ms;
m_wield_image_frames = createAnimationFrames(tsrc,
wield_image.name, wield_image.animation, frame_length_ms);
auto &l0 = m_buffer_info.emplace_back(0);
if (m_wield_image_frames.empty()) {
wield_texture = tsrc->getTexture(wield_image.name);
} else {
wield_texture = m_wield_image_frames[0].texture;
l0.animation_info = std::make_unique<AnimationInfo>(
&m_wield_image_frames, frame_length_ms);
}
// Overlay
if (!wield_overlay.name.empty()) {
int overlay_frame_length_ms;
m_wield_overlay_frames = createAnimationFrames(tsrc,
wield_overlay.name, wield_overlay.animation, overlay_frame_length_ms);
// overlay is white, if present
auto &l1 = m_buffer_info.emplace_back(1, true, video::SColor(0xFFFFFFFF));
if (m_wield_overlay_frames.empty()) {
wield_overlay_texture = tsrc->getTexture(wield_overlay.name);
} else {
wield_overlay_texture = m_wield_overlay_frames[0].texture;
l1.animation_info = std::make_unique<AnimationInfo>(
&m_wield_overlay_frames, overlay_frame_length_ms);
}
}
setExtruded(wield_texture, wield_overlay_texture, wield_scale);
// initialize the color
setColor(video::SColor(0xFFFFFFFF));
return;
@@ -457,8 +512,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
if (def.type == ITEM_NODE) {
switch (f.drawtype) {
case NDT_AIRLIKE:
setExtruded("no_texture_airlike.png", "",
v3f(1), tsrc);
setExtruded(tsrc->getTexture("no_texture_airlike.png"), nullptr, v3f(1));
break;
case NDT_SIGNLIKE:
case NDT_TORCHLIKE:
@@ -510,17 +564,19 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
setColor(video::SColor(0xFFFFFFFF));
return;
} else {
const std::string inventory_image = item.getInventoryImage(idef);
if (!inventory_image.empty()) {
const std::string inventory_overlay = item.getInventoryOverlay(idef);
setExtruded(inventory_image, inventory_overlay, def.wield_scale, tsrc);
video::ITexture* inventory_texture = item_visuals->getInventoryTexture(item, client);
if (inventory_texture) {
video::ITexture* inventory_overlay = item_visuals->getInventoryOverlayTexture(item,
client);
setExtruded(inventory_texture, inventory_overlay, wield_scale);
} else {
setExtruded("no_texture.png", "", def.wield_scale, tsrc);
setExtruded(tsrc->getTexture("no_texture.png"), nullptr, wield_scale);
}
m_buffer_info.emplace_back(0);
m_buffer_info.emplace_back(0, item_visuals->getInventoryAnimation(item, client));
// overlay is white, if present
m_buffer_info.emplace_back(1, true, video::SColor(0xFFFFFFFF));
m_buffer_info.emplace_back(1, item_visuals->getInventoryOverlayAnimation(item, client),
true, video::SColor(0xFFFFFFFF));
// initialize the color
setColor(video::SColor(0xFFFFFFFF));
@@ -599,12 +655,13 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
m_meshnode->setVisible(true);
}
void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
void createItemMesh(Client *client, const ItemDefinition &def,
AnimationInfo &animation_normal,
AnimationInfo &animation_overlay,
ItemMesh *result)
{
ITextureSource *tsrc = client->getTextureSource();
IItemDefManager *idef = client->getItemDefManager();
const NodeDefManager *ndef = client->getNodeDefManager();
const ItemDefinition &def = item.getDefinition(idef);
const ContentFeatures &f = ndef->get(def.name);
assert(result);
@@ -615,19 +672,26 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
// Shading is on by default
result->needs_shading = true;
video::ITexture *inventory_texture = animation_normal.getTexture(0.0f),
*inventory_overlay_texture = animation_overlay.getTexture(0.0f);
// If inventory_image is defined, it overrides everything else
const std::string inventory_image = item.getInventoryImage(idef);
const std::string inventory_overlay = item.getInventoryOverlay(idef);
if (!inventory_image.empty()) {
mesh = getExtrudedMesh(tsrc, inventory_image, inventory_overlay);
result->buffer_info.emplace_back(0);
if (inventory_texture) {
mesh = getExtrudedMesh(inventory_texture, inventory_overlay_texture);
result->buffer_info.emplace_back(0, &animation_normal);
// overlay is white, if present
result->buffer_info.emplace_back(1, true, video::SColor(0xFFFFFFFF));
result->buffer_info.emplace_back(1, &animation_overlay,
true, video::SColor(0xFFFFFFFF));
// Items with inventory images do not need shading
result->needs_shading = false;
} else if (def.type == ITEM_NODE && f.drawtype == NDT_AIRLIKE) {
// Fallback image for airlike node
mesh = getExtrudedMesh(tsrc, "no_texture_airlike.png", inventory_overlay);
mesh = getExtrudedMesh(tsrc->getTexture("no_texture_airlike.png"),
inventory_overlay_texture);
result->buffer_info.emplace_back(0);
// overlay is white, if present
result->buffer_info.emplace_back(1, true, video::SColor(0xFFFFFFFF));
result->needs_shading = false;
@@ -636,21 +700,17 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
case NDT_PLANTLIKE: {
const TileLayer &l0 = f.tiles[0].layers[0];
const TileLayer &l1 = f.tiles[0].layers[1];
mesh = getExtrudedMesh(
extractTexture(f.tiledef[0], l0, tsrc),
extractTexture(f.tiledef[1], l1, tsrc));
mesh = getExtrudedMesh(l0.texture, l1.texture);
// Add color
result->buffer_info.emplace_back(0, l0.has_color, l0.color);
result->buffer_info.emplace_back(1, l1.has_color, l1.color);
result->buffer_info.emplace_back(0, l0);
result->buffer_info.emplace_back(1, l1);
break;
}
case NDT_PLANTLIKE_ROOTED: {
// Use the plant tile
const TileLayer &l0 = f.special_tiles[0].layers[0];
mesh = getExtrudedMesh(
extractTexture(f.tiledef_special[0], l0, tsrc), nullptr
);
result->buffer_info.emplace_back(0, l0.has_color, l0.color);
mesh = getExtrudedMesh(l0.texture);
result->buffer_info.emplace_back(0, l0);
break;
}
default: {
@@ -689,27 +749,19 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
result->mesh = mesh;
}
scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
const std::string &imagename, const std::string &overlay_name)
{
video::ITexture *texture = tsrc->getTexture(imagename);
video::ITexture *overlay_texture =
overlay_name.empty() ? nullptr : tsrc->getTexture(overlay_name);
return getExtrudedMesh(texture, overlay_texture);
}
scene::SMesh *getExtrudedMesh(video::ITexture *texture,
video::ITexture *overlay_texture)
{
if (!texture)
return nullptr;
// get mesh
// Get mesh
core::dimension2d<u32> dim = texture->getSize();
scene::IMesh *original = g_extrusion_mesh_cache->create(dim);
scene::SMesh *mesh = cloneStaticMesh(original);
original->drop();
// Set texture
mesh->getMeshBuffer(0)->getMaterial().setTexture(0, texture);
if (overlay_texture) {
scene::IMeshBuffer *copy = cloneMeshBuffer(mesh->getMeshBuffer(0));