mirror of
https://github.com/luanti-org/luanti.git
synced 2025-10-29 22:55:19 +01:00
Add inventory image animation API (#16538)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -20,21 +20,29 @@ namespace video { class ITexture; }
|
||||
|
||||
struct ItemVisualsManager
|
||||
{
|
||||
ItemVisualsManager()
|
||||
{
|
||||
m_main_thread = std::this_thread::get_id();
|
||||
}
|
||||
ItemVisualsManager();
|
||||
~ItemVisualsManager();
|
||||
|
||||
void clear() {
|
||||
m_cached_item_visuals.clear();
|
||||
}
|
||||
/// Clears the cached visuals
|
||||
void clear();
|
||||
|
||||
// Get item inventory texture
|
||||
video::ITexture* getInventoryTexture(const ItemStack &item, Client *client) const;
|
||||
|
||||
// Get item wield mesh
|
||||
// Get item inventory overlay texture
|
||||
video::ITexture* getInventoryOverlayTexture(const ItemStack &item, Client *client) const;
|
||||
|
||||
// Get item inventory animation
|
||||
// returns nullptr if it is not animated
|
||||
AnimationInfo *getInventoryAnimation(const ItemStack &item, Client *client) const;
|
||||
|
||||
// Get item inventory overlay animation
|
||||
// returns nullptr if it is not animated
|
||||
AnimationInfo *getInventoryOverlayAnimation(const ItemStack &item, Client *client) const;
|
||||
|
||||
// Get item mesh
|
||||
// Once said to return nullptr if there is an inventory image, but this is wrong
|
||||
ItemMesh* getWieldMesh(const ItemStack &item, Client *client) const;
|
||||
ItemMesh *getItemMesh(const ItemStack &item, Client *client) const;
|
||||
|
||||
// Get item palette
|
||||
Palette* getPalette(const ItemStack &item, Client *client) const;
|
||||
@@ -44,21 +52,7 @@ struct ItemVisualsManager
|
||||
video::SColor getItemstackColor(const ItemStack &stack, Client *client) const;
|
||||
|
||||
private:
|
||||
struct ItemVisuals
|
||||
{
|
||||
video::ITexture *inventory_texture;
|
||||
ItemMesh wield_mesh;
|
||||
Palette *palette;
|
||||
|
||||
ItemVisuals():
|
||||
inventory_texture(nullptr),
|
||||
palette(nullptr)
|
||||
{}
|
||||
|
||||
~ItemVisuals();
|
||||
|
||||
DISABLE_CLASS_COPY(ItemVisuals);
|
||||
};
|
||||
struct ItemVisuals;
|
||||
|
||||
// The id of the thread that is allowed to use irrlicht directly
|
||||
std::thread::id m_main_thread;
|
||||
|
||||
@@ -5,17 +5,26 @@
|
||||
#include "tile.h"
|
||||
#include <cassert>
|
||||
|
||||
video::ITexture *AnimationInfo::getTexture(float animation_time)
|
||||
{
|
||||
if (getFrameCount() == 0)
|
||||
return nullptr;
|
||||
|
||||
// Figure out current frame
|
||||
u16 frame = (u32)(animation_time * 1000.0f / std::max<u16>(1, m_frame_length_ms))
|
||||
% m_frame_count;
|
||||
|
||||
assert(frame < m_frames->size());
|
||||
return (*m_frames)[frame].texture;
|
||||
}
|
||||
|
||||
void AnimationInfo::updateTexture(video::SMaterial &material, float animation_time)
|
||||
{
|
||||
// Figure out current frame
|
||||
u16 frame = (u16)(animation_time * 1000 / m_frame_length_ms) % m_frame_count;
|
||||
// Only adjust if frame changed
|
||||
if (frame != m_frame) {
|
||||
m_frame = frame;
|
||||
assert(m_frame < m_frames->size());
|
||||
material.setTexture(0, (*m_frames)[m_frame].texture);
|
||||
video::ITexture *texture = getTexture(animation_time);
|
||||
if (texture) {
|
||||
material.setTexture(0, texture);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void TileLayer::applyMaterialOptions(video::SMaterial &material, int layer) const
|
||||
{
|
||||
|
||||
@@ -158,14 +158,34 @@ struct AnimationInfo {
|
||||
m_frames(tile.frames)
|
||||
{};
|
||||
|
||||
AnimationInfo(std::vector<FrameSpec> *frames, u16 frame_length_ms) :
|
||||
m_frame_length_ms(frame_length_ms),
|
||||
m_frame_count(frames->size()),
|
||||
m_frames(frames)
|
||||
{};
|
||||
|
||||
void freeFrames()
|
||||
{
|
||||
delete m_frames;
|
||||
m_frames = nullptr;
|
||||
}
|
||||
|
||||
size_t getFrameCount() const
|
||||
{
|
||||
return m_frames ? m_frame_count : 0;
|
||||
}
|
||||
|
||||
void updateTexture(video::SMaterial &material, float animation_time);
|
||||
|
||||
// Returns nullptr if texture did not change since last time
|
||||
video::ITexture *getTexture(float animation_time);
|
||||
|
||||
private:
|
||||
u16 m_frame = 0; // last animation frame
|
||||
u16 m_frame_length_ms = 0;
|
||||
u16 m_frame_count = 1;
|
||||
|
||||
/// @note not owned by this struct
|
||||
/// @note by default not owned by this struct
|
||||
/// TODO. Change this to a shared pointer.
|
||||
std::vector<FrameSpec> *m_frames = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -26,6 +26,8 @@ struct ItemStack;
|
||||
struct TileDef;
|
||||
class Client;
|
||||
class ITextureSource;
|
||||
struct ItemDefinition;
|
||||
struct TileAnimationParams;
|
||||
class ShadowRenderer;
|
||||
|
||||
/*
|
||||
@@ -56,6 +58,14 @@ public:
|
||||
layer(layer)
|
||||
{}
|
||||
|
||||
ItemMeshBufferInfo(int layer, const AnimationInfo *animation,
|
||||
bool override_c = false, video::SColor color = {}) :
|
||||
override_color(color), override_color_set(override_c), layer(layer)
|
||||
{
|
||||
if (animation)
|
||||
animation_info = std::make_unique<AnimationInfo>(*animation);
|
||||
}
|
||||
|
||||
ItemMeshBufferInfo(int layer_num, const TileLayer &layer);
|
||||
|
||||
void applyOverride(video::SColor &dest) const {
|
||||
@@ -109,9 +119,6 @@ public:
|
||||
void setExtruded(const TileDef &d0, const TileLayer &l0,
|
||||
const TileDef &d1, const TileLayer &l1,
|
||||
v3f wield_scale, ITextureSource *tsrc);
|
||||
// Set apperance from texture name
|
||||
void setExtruded(const std::string &image, const std::string &overlay,
|
||||
v3f wield_scale, ITextureSource *tsrc);
|
||||
|
||||
void setItem(const ItemStack &item, Client *client,
|
||||
bool check_wield_image = true);
|
||||
@@ -153,6 +160,11 @@ private:
|
||||
*/
|
||||
video::SColor m_base_color;
|
||||
|
||||
// Empty if wield image is empty or not animated
|
||||
// Owned by this class to get AnimationInfo for the mesh buffer info
|
||||
std::vector<FrameSpec> m_wield_image_frames;
|
||||
std::vector<FrameSpec> m_wield_overlay_frames;
|
||||
|
||||
// Bounding box culling is disabled for this type of scene node,
|
||||
// so this variable is just required so we can implement
|
||||
// getBoundingBox() and is set to an empty box.
|
||||
@@ -161,14 +173,20 @@ private:
|
||||
ShadowRenderer *m_shadow;
|
||||
};
|
||||
|
||||
std::vector<FrameSpec> createAnimationFrames(ITextureSource *tsrc,
|
||||
const std::string &image_name, const TileAnimationParams &animation,
|
||||
int& result_frame_length_ms);
|
||||
|
||||
scene::SMesh *getExtrudedMesh(video::ITexture *texture,
|
||||
video::ITexture *overlay_texture = nullptr);
|
||||
|
||||
/**
|
||||
* NOTE: The item mesh is only suitable for inventory rendering (due to its
|
||||
* material types). In-world rendering of items must go through WieldMeshSceneNode.
|
||||
*/
|
||||
void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);
|
||||
|
||||
scene::SMesh *getExtrudedMesh(video::ITexture *texture,
|
||||
video::ITexture *overlay_texture);
|
||||
|
||||
scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename,
|
||||
const std::string &overlay_name);
|
||||
// This is only used to initially generate an ItemMesh
|
||||
// To get the mesh, use ItemVisualsManager::getItemMesh(item, client) instead
|
||||
void createItemMesh(Client *client, const ItemDefinition &def,
|
||||
AnimationInfo &animation_normal,
|
||||
AnimationInfo &animation_overlay,
|
||||
ItemMesh *result);
|
||||
|
||||
Reference in New Issue
Block a user