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") local S = core.get_translator("testnodes")
-- Complex mesh for use_texture_alpha, description in pairs({
core.register_node("testnodes:performance_mesh_clip", { opaque = S("Marble with 'opaque' transparency"),
description = S("Performance Test Node") .. "\n" .. S("Marble with 'clip' transparency"), clip = S("Marble with 'clip' transparency"),
drawtype = "mesh", blend = S("Marble with 'blend' transparency"),
mesh = "testnodes_marble_glass.obj", }) do
tiles = {"testnodes_marble_glass.png"}, core.register_node("testnodes:performance_mesh_" .. use_texture_alpha, {
paramtype = "light", description = S("Performance Test Node") .. "\n" .. description,
use_texture_alpha = "clip", drawtype = "mesh",
mesh = "testnodes_marble_glass.obj",
tiles = {"testnodes_marble_glass.png"},
paramtype = "light",
use_texture_alpha = use_texture_alpha,
groups = {dig_immediate=3}, groups = {dig_immediate=3},
}) })
end
-- 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},
})
-- Overlay -- Overlay
core.register_node("testnodes:performance_overlay_clip", { core.register_node("testnodes:performance_overlay_clip", {

View File

@@ -31,9 +31,10 @@
#define MIN_EXTRUSION_MESH_RESOLUTION 16 #define MIN_EXTRUSION_MESH_RESOLUTION 16
#define MAX_EXTRUSION_MESH_RESOLUTION 512 #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(layer.color),
override_color_set(layer.has_color), override_color_set(layer.has_color),
layer(layer_num),
animation_info((layer.material_flags & MATERIAL_FLAG_ANIMATION) ? animation_info((layer.material_flags & MATERIAL_FLAG_ANIMATION) ?
std::make_unique<AnimationInfo>(layer) : std::make_unique<AnimationInfo>(layer) :
nullptr) nullptr)
@@ -131,6 +132,51 @@ static video::ITexture *extractTexture(const TileDef &def, const TileLayer &laye
return nullptr; 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 Caches extrusion meshes so that only one of them per resolution
is needed. Also caches one cube (for convenience). 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); extractTexture(d1, l1, tsrc), wield_scale);
// Add color // Add color
m_buffer_info.clear(); m_buffer_info.clear();
m_buffer_info.emplace_back(l0.has_color, l0.color); m_buffer_info.emplace_back(0, l0.has_color, l0.color);
m_buffer_info.emplace_back(l1.has_color, l1.color); m_buffer_info.emplace_back(1, l1.has_color, l1.color);
} }
void WieldMeshSceneNode::setExtruded(const std::string &image, 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); p.layer.applyMaterialOptions(buf->Material, layer);
mesh->addMeshBuffer(buf.get()); mesh->addMeshBuffer(buf.get());
buffer_info->emplace_back(p.layer); buffer_info->emplace_back(layer, p.layer);
} }
} }
mesh->recalculateBoundingBox(); mesh->recalculateBoundingBox();
@@ -371,17 +417,19 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
ITextureSource *tsrc = client->getTextureSource(); ITextureSource *tsrc = client->getTextureSource();
IItemDefManager *idef = client->getItemDefManager(); IItemDefManager *idef = client->getItemDefManager();
ItemVisualsManager *item_visuals = client->getItemVisualsManager(); ItemVisualsManager *item_visuals = client->getItemVisualsManager();
IShaderSource *shdrsrc = client->getShaderSource(); IShaderSource *shdsrc = client->getShaderSource();
const NodeDefManager *ndef = client->getNodeDefManager(); const NodeDefManager *ndef = client->getNodeDefManager();
const ItemDefinition &def = item.getDefinition(idef); const ItemDefinition &def = item.getDefinition(idef);
const ContentFeatures &f = ndef->get(def.name); 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; 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 // Color-related
m_buffer_info.clear(); m_buffer_info.clear();
m_base_color = item_visuals->getItemstackColor(item, client); 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 needs to be checked and is defined, it overrides everything else
if (!wield_image.empty() && check_wield_image) { if (!wield_image.empty() && check_wield_image) {
setExtruded(wield_image, wield_overlay, wield_scale, tsrc); setExtruded(wield_image, wield_overlay, wield_scale, tsrc);
m_buffer_info.emplace_back(); m_buffer_info.emplace_back(0);
// overlay is white, if present // 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 // initialize the color
setColor(video::SColor(0xFFFFFFFF)); setColor(video::SColor(0xFFFFFFFF));
return; return;
@@ -403,7 +451,6 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
// Handle nodes // Handle nodes
if (def.type == ITEM_NODE) { if (def.type == ITEM_NODE) {
switch (f.drawtype) { switch (f.drawtype) {
case NDT_AIRLIKE: case NDT_AIRLIKE:
setExtruded("no_texture_airlike.png", "", setExtruded("no_texture_airlike.png", "",
@@ -429,7 +476,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
} }
default: { default: {
// Render all other drawtypes like the actual node // Render all other drawtypes like the actual node
MapNode n(id); MapNode n(ndef->getId(def.name));
if (def.place_param2) if (def.place_param2)
n.setParam2(*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(); u32 material_count = m_meshnode->getMaterialCount();
for (u32 i = 0; i < material_count; ++i) { for (u32 i = 0; i < material_count; ++i) {
video::SMaterial &material = m_meshnode->getMaterial(i); video::SMaterial &material = m_meshnode->getMaterial(i);
// FIXME: we should take different alpha modes of the mesh into account here // apply node's alpha mode
material.MaterialType = m_material_type; setAlphaBullshit(material, shdsrc, f.alpha,
material.MaterialTypeParam = 0.5f; m_buffer_info[i].layer == 1);
material.forEachTexture([this] (auto &tex) { material.forEachTexture([this] (auto &tex) {
setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter, setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter,
m_anisotropic_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); setExtruded("no_texture.png", "", def.wield_scale, tsrc);
} }
m_buffer_info.emplace_back(); m_buffer_info.emplace_back(0);
// overlay is white, if present // 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 // initialize the color
setColor(video::SColor(0xFFFFFFFF)); setColor(video::SColor(0xFFFFFFFF));
@@ -490,9 +537,9 @@ void WieldMeshSceneNode::setColor(video::SColor c)
u8 green = c.getGreen(); u8 green = c.getGreen();
u8 blue = c.getBlue(); u8 blue = c.getBlue();
const u32 mc = mesh->getMeshBufferCount(); u32 mc = mesh->getMeshBufferCount();
if (mc > m_buffer_info.size()) assert(mc <= m_buffer_info.size());
m_buffer_info.resize(mc); mc = std::min<u32>(mc, m_buffer_info.size());
for (u32 j = 0; j < mc; j++) { for (u32 j = 0; j < mc; j++) {
video::SColor bc(m_base_color); video::SColor bc(m_base_color);
m_buffer_info[j].applyOverride(bc); 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 NodeDefManager *ndef = client->getNodeDefManager();
const ItemDefinition &def = item.getDefinition(idef); const ItemDefinition &def = item.getDefinition(idef);
const ContentFeatures &f = ndef->get(def.name); 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"); 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); const std::string inventory_overlay = item.getInventoryOverlay(idef);
if (!inventory_image.empty()) { if (!inventory_image.empty()) {
mesh = getExtrudedMesh(tsrc, inventory_image, inventory_overlay); mesh = getExtrudedMesh(tsrc, inventory_image, inventory_overlay);
result->buffer_info.emplace_back(); result->buffer_info.emplace_back(0);
// overlay is white, if present // overlay is white, if present
result->buffer_info.emplace_back(true, video::SColor(0xFFFFFFFF)); result->buffer_info.emplace_back(1, true, video::SColor(0xFFFFFFFF));
// Items with inventory images do not need shading
result->needs_shading = false; result->needs_shading = false;
} else if (def.type == ITEM_NODE && f.drawtype == NDT_AIRLIKE) { } else if (def.type == ITEM_NODE && f.drawtype == NDT_AIRLIKE) {
// Fallback image for airlike node // Fallback image for airlike node
mesh = getExtrudedMesh(tsrc, "no_texture_airlike.png", inventory_overlay); 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; result->needs_shading = false;
} else if (def.type == ITEM_NODE) { } else if (def.type == ITEM_NODE) {
switch (f.drawtype) { 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[0], l0, tsrc),
extractTexture(f.tiledef[1], l1, tsrc)); extractTexture(f.tiledef[1], l1, tsrc));
// Add color // Add color
result->buffer_info.emplace_back(l0.has_color, l0.color); result->buffer_info.emplace_back(0, l0.has_color, l0.color);
result->buffer_info.emplace_back(l1.has_color, l1.color); result->buffer_info.emplace_back(1, l1.has_color, l1.color);
break; break;
} }
case NDT_PLANTLIKE_ROOTED: { case NDT_PLANTLIKE_ROOTED: {
@@ -597,17 +646,17 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
mesh = getExtrudedMesh( mesh = getExtrudedMesh(
extractTexture(f.tiledef_special[0], l0, tsrc), nullptr 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; break;
} }
default: { default: {
// Render all other drawtypes like the actual node // Render all other drawtypes like the actual node
MapNode n(id); MapNode n(ndef->getId(def.name));
if (def.place_param2) if (def.place_param2)
n.setParam2(*def.place_param2); n.setParam2(*def.place_param2);
mesh = createGenericNodeMesh(client, n, &result->buffer_info, f); mesh = createGenericNodeMesh(client, n, &result->buffer_info, f);
scaleMesh(mesh, v3f(0.12, 0.12, 0.12)); scaleMesh(mesh, v3f(0.12f));
break; break;
} }
} }
@@ -615,9 +664,9 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) { for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
video::SMaterial &material = buf->getMaterial(); video::SMaterial &material = buf->getMaterial();
// FIXME: overriding this breaks different alpha modes the mesh may have // apply node's alpha mode
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; setAlphaBullshit(material, f.alpha,
material.MaterialTypeParam = 0.5f; result->buffer_info[i].layer == 1);
material.forEachTexture([] (auto &tex) { material.forEachTexture([] (auto &tex) {
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
tex.MagFilter = video::ETMAGF_NEAREST; tex.MagFilter = video::ETMAGF_NEAREST;
@@ -675,7 +724,7 @@ scene::SMesh *getExtrudedMesh(video::ITexture *texture,
tex.MagFilter = video::ETMAGF_NEAREST; tex.MagFilter = video::ETMAGF_NEAREST;
}); });
material.BackfaceCulling = true; material.BackfaceCulling = true;
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
material.MaterialTypeParam = 0.5f; material.MaterialTypeParam = 0.5f;
} }
scaleMesh(mesh, v3f(2)); scaleMesh(mesh, v3f(2));

View File

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

View File

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