1
0
mirror of https://github.com/luanti-org/luanti.git synced 2025-10-12 16:15:20 +02:00

Respect node alpha node for inventory drawing (#16556)

This commit is contained in:
sfan5
2025-10-11 19:37:30 +02:00
committed by GitHub
parent a141f8478b
commit c2e2b97944
4 changed files with 114 additions and 64 deletions

View File

@@ -2,29 +2,22 @@
local S = core.get_translator("testnodes")
-- Complex mesh
core.register_node("testnodes:performance_mesh_clip", {
description = S("Performance Test Node") .. "\n" .. S("Marble with 'clip' transparency"),
for use_texture_alpha, description in pairs({
opaque = S("Marble with 'opaque' transparency"),
clip = S("Marble with 'clip' transparency"),
blend = S("Marble with 'blend' transparency"),
}) do
core.register_node("testnodes:performance_mesh_" .. use_texture_alpha, {
description = S("Performance Test Node") .. "\n" .. description,
drawtype = "mesh",
mesh = "testnodes_marble_glass.obj",
tiles = {"testnodes_marble_glass.png"},
paramtype = "light",
use_texture_alpha = "clip",
use_texture_alpha = use_texture_alpha,
groups = {dig_immediate=3},
})
-- Complex mesh, alpha blending
core.register_node("testnodes:performance_mesh_blend", {
description = S("Performance Test Node") .. "\n" .. S("Marble with 'blend' transparency"),
drawtype = "mesh",
mesh = "testnodes_marble_glass.obj",
tiles = {"testnodes_marble_glass.png"},
paramtype = "light",
use_texture_alpha = "blend",
groups = {dig_immediate=3},
})
})
end
-- Overlay
core.register_node("testnodes:performance_overlay_clip", {

View File

@@ -31,9 +31,10 @@
#define MIN_EXTRUSION_MESH_RESOLUTION 16
#define MAX_EXTRUSION_MESH_RESOLUTION 512
ItemMeshBufferInfo::ItemMeshBufferInfo(const TileLayer &layer) :
ItemMeshBufferInfo::ItemMeshBufferInfo(int layer_num, const TileLayer &layer) :
override_color(layer.color),
override_color_set(layer.has_color),
layer(layer_num),
animation_info((layer.material_flags & MATERIAL_FLAG_ANIMATION) ?
std::make_unique<AnimationInfo>(layer) :
nullptr)
@@ -131,6 +132,51 @@ static video::ITexture *extractTexture(const TileDef &def, const TileLayer &laye
return nullptr;
}
// (the function name represents the amount of time wasted on all of this)
static void setAlphaBullshit(video::SMaterial &mat,
AlphaMode mode, bool overlay)
{
switch (mode) {
case ALPHAMODE_BLEND:
mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
mat.MaterialTypeParam = 0;
return;
case ALPHAMODE_OPAQUE:
if (!overlay) {
mat.MaterialType = video::EMT_SOLID;
return;
}
[[fallthrough]];
case ALPHAMODE_CLIP:
default:
mat.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
mat.MaterialTypeParam = 0.5f;
return;
}
}
static void setAlphaBullshit(video::SMaterial &mat, IShaderSource *shdsrc,
AlphaMode mode, bool overlay)
{
MaterialType mt;
switch (mode) {
case ALPHAMODE_BLEND:
mt = TILE_MATERIAL_ALPHA;
break;
case ALPHAMODE_OPAQUE:
mt = overlay ? TILE_MATERIAL_BASIC : TILE_MATERIAL_OPAQUE;
break;
case ALPHAMODE_CLIP:
default:
mt = TILE_MATERIAL_BASIC;
break;
}
u32 shader_id = shdsrc->getShader("object_shader", mt, NDT_NORMAL);
mat.MaterialType = shdsrc->getShaderInfo(shader_id).material;
}
/*
Caches extrusion meshes so that only one of them per resolution
is needed. Also caches one cube (for convenience).
@@ -255,8 +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(l0.has_color, l0.color);
m_buffer_info.emplace_back(l1.has_color, l1.color);
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,
@@ -359,7 +405,7 @@ static scene::SMesh *createGenericNodeMesh(Client *client, MapNode n,
p.layer.applyMaterialOptions(buf->Material, layer);
mesh->addMeshBuffer(buf.get());
buffer_info->emplace_back(p.layer);
buffer_info->emplace_back(layer, p.layer);
}
}
mesh->recalculateBoundingBox();
@@ -371,17 +417,19 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
ITextureSource *tsrc = client->getTextureSource();
IItemDefManager *idef = client->getItemDefManager();
ItemVisualsManager *item_visuals = client->getItemVisualsManager();
IShaderSource *shdrsrc = client->getShaderSource();
IShaderSource *shdsrc = client->getShaderSource();
const NodeDefManager *ndef = client->getNodeDefManager();
const ItemDefinition &def = item.getDefinition(idef);
const ContentFeatures &f = ndef->get(def.name);
content_t id = ndef->getId(def.name);
{
// Initialize material type used by setExtruded
u32 shader_id = shdsrc->getShader("object_shader", TILE_MATERIAL_BASIC, NDT_NORMAL);
m_material_type = shdsrc->getShaderInfo(shader_id).material;
}
scene::SMesh *mesh = nullptr;
u32 shader_id = shdrsrc->getShader("object_shader", TILE_MATERIAL_BASIC, NDT_NORMAL);
m_material_type = shdrsrc->getShaderInfo(shader_id).material;
// Color-related
m_buffer_info.clear();
m_base_color = item_visuals->getItemstackColor(item, client);
@@ -393,9 +441,9 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
// 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();
m_buffer_info.emplace_back(0);
// overlay is white, if present
m_buffer_info.emplace_back(true, video::SColor(0xFFFFFFFF));
m_buffer_info.emplace_back(1, true, video::SColor(0xFFFFFFFF));
// initialize the color
setColor(video::SColor(0xFFFFFFFF));
return;
@@ -403,7 +451,6 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
// Handle nodes
if (def.type == ITEM_NODE) {
switch (f.drawtype) {
case NDT_AIRLIKE:
setExtruded("no_texture_airlike.png", "",
@@ -429,7 +476,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
}
default: {
// Render all other drawtypes like the actual node
MapNode n(id);
MapNode n(ndef->getId(def.name));
if (def.place_param2)
n.setParam2(*def.place_param2);
@@ -446,9 +493,9 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
u32 material_count = m_meshnode->getMaterialCount();
for (u32 i = 0; i < material_count; ++i) {
video::SMaterial &material = m_meshnode->getMaterial(i);
// FIXME: we should take different alpha modes of the mesh into account here
material.MaterialType = m_material_type;
material.MaterialTypeParam = 0.5f;
// apply node's alpha mode
setAlphaBullshit(material, shdsrc, f.alpha,
m_buffer_info[i].layer == 1);
material.forEachTexture([this] (auto &tex) {
setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter,
m_anisotropic_filter);
@@ -467,9 +514,9 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
setExtruded("no_texture.png", "", def.wield_scale, tsrc);
}
m_buffer_info.emplace_back();
m_buffer_info.emplace_back(0);
// overlay is white, if present
m_buffer_info.emplace_back(true, video::SColor(0xFFFFFFFF));
m_buffer_info.emplace_back(1, true, video::SColor(0xFFFFFFFF));
// initialize the color
setColor(video::SColor(0xFFFFFFFF));
@@ -490,9 +537,9 @@ void WieldMeshSceneNode::setColor(video::SColor c)
u8 green = c.getGreen();
u8 blue = c.getBlue();
const u32 mc = mesh->getMeshBufferCount();
if (mc > m_buffer_info.size())
m_buffer_info.resize(mc);
u32 mc = mesh->getMeshBufferCount();
assert(mc <= m_buffer_info.size());
mc = std::min<u32>(mc, m_buffer_info.size());
for (u32 j = 0; j < mc; j++) {
video::SColor bc(m_base_color);
m_buffer_info[j].applyOverride(bc);
@@ -555,7 +602,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
const NodeDefManager *ndef = client->getNodeDefManager();
const ItemDefinition &def = item.getDefinition(idef);
const ContentFeatures &f = ndef->get(def.name);
content_t id = ndef->getId(def.name);
assert(result);
FATAL_ERROR_IF(!g_extrusion_mesh_cache, "Extrusion mesh cache is not yet initialized");
@@ -569,14 +616,16 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
const std::string inventory_overlay = item.getInventoryOverlay(idef);
if (!inventory_image.empty()) {
mesh = getExtrudedMesh(tsrc, inventory_image, inventory_overlay);
result->buffer_info.emplace_back();
result->buffer_info.emplace_back(0);
// overlay is white, if present
result->buffer_info.emplace_back(true, video::SColor(0xFFFFFFFF));
// Items with inventory images do not need shading
result->buffer_info.emplace_back(1, true, video::SColor(0xFFFFFFFF));
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);
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;
} else if (def.type == ITEM_NODE) {
switch (f.drawtype) {
@@ -587,8 +636,8 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
extractTexture(f.tiledef[0], l0, tsrc),
extractTexture(f.tiledef[1], l1, tsrc));
// Add color
result->buffer_info.emplace_back(l0.has_color, l0.color);
result->buffer_info.emplace_back(l1.has_color, l1.color);
result->buffer_info.emplace_back(0, l0.has_color, l0.color);
result->buffer_info.emplace_back(1, l1.has_color, l1.color);
break;
}
case NDT_PLANTLIKE_ROOTED: {
@@ -597,17 +646,17 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
mesh = getExtrudedMesh(
extractTexture(f.tiledef_special[0], l0, tsrc), nullptr
);
result->buffer_info.emplace_back(l0.has_color, l0.color);
result->buffer_info.emplace_back(0, l0.has_color, l0.color);
break;
}
default: {
// Render all other drawtypes like the actual node
MapNode n(id);
MapNode n(ndef->getId(def.name));
if (def.place_param2)
n.setParam2(*def.place_param2);
mesh = createGenericNodeMesh(client, n, &result->buffer_info, f);
scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
scaleMesh(mesh, v3f(0.12f));
break;
}
}
@@ -615,9 +664,9 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
video::SMaterial &material = buf->getMaterial();
// FIXME: overriding this breaks different alpha modes the mesh may have
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialTypeParam = 0.5f;
// apply node's alpha mode
setAlphaBullshit(material, f.alpha,
result->buffer_info[i].layer == 1);
material.forEachTexture([] (auto &tex) {
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
tex.MagFilter = video::ETMAGF_NEAREST;
@@ -675,7 +724,7 @@ scene::SMesh *getExtrudedMesh(video::ITexture *texture,
tex.MagFilter = video::ETMAGF_NEAREST;
});
material.BackfaceCulling = true;
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.MaterialTypeParam = 0.5f;
}
scaleMesh(mesh, v3f(2));

View File

@@ -49,13 +49,14 @@ class ItemMeshBufferInfo
public:
ItemMeshBufferInfo() = default;
ItemMeshBufferInfo(int layer) : layer(layer) {}
ItemMeshBufferInfo(bool override, video::SColor color) :
override_color(color), override_color_set(override)
ItemMeshBufferInfo(int layer, bool override, video::SColor color) :
override_color(color), override_color_set(override),
layer(layer)
{}
ItemMeshBufferInfo(const TileLayer &layer);
ItemMeshBufferInfo(int layer_num, const TileLayer &layer);
void applyOverride(video::SColor &dest) const {
if (override_color_set)
@@ -70,6 +71,9 @@ public:
return true;
}
// Index of the tile layer this mesh buffer belongs to
u8 layer;
// Null for no animated parts
std::unique_ptr<AnimationInfo> animation_info;
};
@@ -132,6 +136,7 @@ private:
// Child scene node with the current wield mesh
scene::IMeshSceneNode *m_meshnode = nullptr;
// Material types used as fallback
video::E_MATERIAL_TYPE m_material_type;
bool m_anisotropic_filter;
@@ -156,6 +161,10 @@ private:
ShadowRenderer *m_shadow;
};
/**
* 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,

View File

@@ -118,9 +118,9 @@ void drawItemStack(
video::SColor basecolor = item_visuals->getItemstackColor(item, client);
const u32 mc = mesh->getMeshBufferCount();
if (mc > imesh->buffer_info.size())
imesh->buffer_info.resize(mc);
u32 mc = mesh->getMeshBufferCount();
assert(mc <= imesh->buffer_info.size());
mc = std::min<u32>(mc, imesh->buffer_info.size());
for (u32 j = 0; j < mc; ++j) {
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::SColor c = basecolor;
@@ -144,7 +144,6 @@ void drawItemStack(
p.animation_info->updateTexture(material, client->getAnimationTime());
}
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
driver->setMaterial(material);
driver->drawMeshBuffer(buf);
}