1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Soft node overlay (#5186)

This commit adds node overlays, which are tiles that are drawn on top of
other tiles.
This commit is contained in:
Dániel Juhász 2017-04-21 15:34:59 +02:00 committed by Zeno-
parent 2ad74a9e8b
commit 1ffb180868
18 changed files with 763 additions and 467 deletions

View file

@ -235,27 +235,16 @@ WieldMeshSceneNode::~WieldMeshSceneNode()
g_extrusion_mesh_cache = NULL;
}
void WieldMeshSceneNode::setCube(const TileSpec tiles[6],
void WieldMeshSceneNode::setCube(const ContentFeatures &f,
v3f wield_scale, ITextureSource *tsrc)
{
scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
changeToMesh(cubemesh);
scene::SMesh *copy = cloneMesh(cubemesh);
cubemesh->drop();
postProcessNodeMesh(copy, f, false, true, &m_material_type, &m_colors);
changeToMesh(copy);
copy->drop();
m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR);
// Customize materials
for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) {
assert(i < 6);
video::SMaterial &material = m_meshnode->getMaterial(i);
if (tiles[i].animation_frame_count == 1) {
material.setTexture(0, tiles[i].texture);
} else {
FrameSpec animation_frame = tiles[i].frames[0];
material.setTexture(0, animation_frame.texture);
}
tiles[i].applyMaterialOptions(material);
}
}
void WieldMeshSceneNode::setExtruded(const std::string &imagename,
@ -274,8 +263,10 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
dim = core::dimension2d<u32>(dim.Width, frame_height);
}
scene::IMesh *mesh = g_extrusion_mesh_cache->create(dim);
changeToMesh(mesh);
scene::SMesh *copy = cloneMesh(mesh);
mesh->drop();
changeToMesh(copy);
copy->drop();
m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR_EXTRUDED);
@ -321,12 +312,12 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
// Color-related
m_colors.clear();
video::SColor basecolor = idef->getItemstackColor(item, client);
m_base_color = idef->getItemstackColor(item, client);
// If wield_image is defined, it overrides everything else
if (def.wield_image != "") {
setExtruded(def.wield_image, def.wield_scale, tsrc, 1);
m_colors.push_back(basecolor);
m_colors.push_back(ItemPartColor());
return;
}
// Handle nodes
@ -334,66 +325,50 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
else if (def.type == ITEM_NODE) {
if (f.mesh_ptr[0]) {
// e.g. mesh nodes and nodeboxes
changeToMesh(f.mesh_ptr[0]);
// mesh_ptr[0] is pre-scaled by BS * f->visual_scale
scene::SMesh *mesh = cloneMesh(f.mesh_ptr[0]);
postProcessNodeMesh(mesh, f, m_enable_shaders, true,
&m_material_type, &m_colors);
changeToMesh(mesh);
mesh->drop();
// mesh is pre-scaled by BS * f->visual_scale
m_meshnode->setScale(
def.wield_scale * WIELD_SCALE_FACTOR
/ (BS * f.visual_scale));
} else if (f.drawtype == NDT_AIRLIKE) {
changeToMesh(NULL);
} else if (f.drawtype == NDT_PLANTLIKE) {
setExtruded(tsrc->getTextureName(f.tiles[0].texture_id), def.wield_scale, tsrc, f.tiles[0].animation_frame_count);
setExtruded(tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
def.wield_scale, tsrc,
f.tiles[0].layers[0].animation_frame_count);
} else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) {
setCube(f.tiles, def.wield_scale, tsrc);
setCube(f, def.wield_scale, tsrc);
} else {
MeshMakeData mesh_make_data(client, false);
MapNode mesh_make_node(id, 255, 0);
mesh_make_data.fillSingleNode(&mesh_make_node);
MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0));
changeToMesh(mapblock_mesh.getMesh());
translateMesh(m_meshnode->getMesh(), v3f(-BS, -BS, -BS));
scene::SMesh *mesh = cloneMesh(mapblock_mesh.getMesh());
translateMesh(mesh, v3f(-BS, -BS, -BS));
postProcessNodeMesh(mesh, f, m_enable_shaders, true,
&m_material_type, &m_colors);
changeToMesh(mesh);
mesh->drop();
m_meshnode->setScale(
def.wield_scale * WIELD_SCALE_FACTOR
/ (BS * f.visual_scale));
}
u32 material_count = m_meshnode->getMaterialCount();
if (material_count > 6) {
errorstream << "WieldMeshSceneNode::setItem: Invalid material "
"count " << material_count << ", truncating to 6" << std::endl;
material_count = 6;
}
for (u32 i = 0; i < material_count; ++i) {
const TileSpec *tile = &(f.tiles[i]);
video::SMaterial &material = m_meshnode->getMaterial(i);
material.setFlag(video::EMF_BACK_FACE_CULLING, true);
material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
bool animated = (tile->animation_frame_count > 1);
if (animated) {
FrameSpec animation_frame = tile->frames[0];
material.setTexture(0, animation_frame.texture);
} else {
material.setTexture(0, tile->texture);
}
m_colors.push_back(tile->has_color ? tile->color : basecolor);
material.MaterialType = m_material_type;
if (m_enable_shaders) {
if (tile->normal_texture) {
if (animated) {
FrameSpec animation_frame = tile->frames[0];
material.setTexture(1, animation_frame.normal_texture);
} else {
material.setTexture(1, tile->normal_texture);
}
}
material.setTexture(2, tile->flags_texture);
}
}
return;
}
else if (def.inventory_image != "") {
setExtruded(def.inventory_image, def.wield_scale, tsrc, 1);
m_colors.push_back(basecolor);
m_colors.push_back(ItemPartColor());
return;
}
@ -413,9 +388,9 @@ void WieldMeshSceneNode::setColor(video::SColor c)
u8 blue = c.getBlue();
u32 mc = mesh->getMeshBufferCount();
for (u32 j = 0; j < mc; j++) {
video::SColor bc(0xFFFFFFFF);
if (m_colors.size() > j)
bc = m_colors[j];
video::SColor bc(m_base_color);
if ((m_colors.size() > j) && (m_colors[j].override_base))
bc = m_colors[j].color;
video::SColor buffercolor(255,
bc.getRed() * red / 255,
bc.getGreen() * green / 255,
@ -439,19 +414,7 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh)
m_meshnode->setMesh(dummymesh);
dummymesh->drop(); // m_meshnode grabbed it
} else {
if (m_lighting) {
m_meshnode->setMesh(mesh);
} else {
/*
Lighting is disabled, this means the caller can (and probably will)
call setColor later. We therefore need to clone the mesh so that
setColor will only modify this scene node's mesh, not others'.
*/
scene::IMeshManipulator *meshmanip = SceneManager->getMeshManipulator();
scene::IMesh *new_mesh = meshmanip->createMeshCopy(mesh);
m_meshnode->setMesh(new_mesh);
new_mesh->drop(); // m_meshnode grabbed it
}
m_meshnode->setMesh(mesh);
}
m_meshnode->setMaterialFlag(video::EMF_LIGHTING, m_lighting);
@ -475,24 +438,24 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
g_extrusion_mesh_cache->grab();
}
scene::IMesh *mesh;
scene::SMesh *mesh;
// If inventory_image is defined, it overrides everything else
if (def.inventory_image != "") {
mesh = getExtrudedMesh(tsrc, def.inventory_image);
result->mesh = mesh;
result->buffer_colors.push_back(
std::pair<bool, video::SColor>(false, video::SColor(0xFFFFFFFF)));
result->buffer_colors.push_back(ItemPartColor());
} else if (def.type == ITEM_NODE) {
if (f.mesh_ptr[0]) {
mesh = cloneMesh(f.mesh_ptr[0]);
scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
} else if (f.drawtype == NDT_PLANTLIKE) {
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(f.tiles[0].texture_id));
tsrc->getTextureName(f.tiles[0].layers[0].texture_id));
} else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES
|| f.drawtype == NDT_LIQUID || f.drawtype == NDT_FLOWINGLIQUID) {
mesh = cloneMesh(g_extrusion_mesh_cache->createCube());
scene::IMesh *cube = g_extrusion_mesh_cache->createCube();
mesh = cloneMesh(cube);
cube->drop();
scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
} else {
MeshMakeData mesh_make_data(client, false);
@ -519,32 +482,27 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
u32 mc = mesh->getMeshBufferCount();
for (u32 i = 0; i < mc; ++i) {
const TileSpec *tile = &(f.tiles[i]);
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
result->buffer_colors.push_back(
std::pair<bool, video::SColor>(tile->has_color, tile->color));
colorizeMeshBuffer(buf, &tile->color);
video::SMaterial &material = buf->getMaterial();
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_TRILINEAR_FILTER, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, true);
material.setFlag(video::EMF_LIGHTING, false);
if (tile->animation_frame_count > 1) {
FrameSpec animation_frame = tile->frames[0];
material.setTexture(0, animation_frame.texture);
} else {
material.setTexture(0, tile->texture);
}
}
rotateMeshXZby(mesh, -45);
rotateMeshYZby(mesh, -30);
result->mesh = mesh;
postProcessNodeMesh(mesh, f, false, false, NULL,
&result->buffer_colors);
}
result->mesh = mesh;
}
scene::IMesh * getExtrudedMesh(ITextureSource *tsrc,
scene::SMesh * getExtrudedMesh(ITextureSource *tsrc,
const std::string &imagename)
{
video::ITexture *texture = tsrc->getTextureForMesh(imagename);
@ -553,7 +511,9 @@ scene::IMesh * getExtrudedMesh(ITextureSource *tsrc,
}
core::dimension2d<u32> dim = texture->getSize();
scene::IMesh *mesh = cloneMesh(g_extrusion_mesh_cache->create(dim));
scene::IMesh *original = g_extrusion_mesh_cache->create(dim);
scene::SMesh *mesh = cloneMesh(original);
original->drop();
// Customize material
video::SMaterial &material = mesh->getMeshBuffer(0)->getMaterial();
@ -569,3 +529,57 @@ scene::IMesh * getExtrudedMesh(ITextureSource *tsrc,
return mesh;
}
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
bool use_shaders, bool set_material, video::E_MATERIAL_TYPE *mattype,
std::vector<ItemPartColor> *colors)
{
u32 mc = mesh->getMeshBufferCount();
// Allocate colors for existing buffers
colors->clear();
for (u32 i = 0; i < mc; ++i)
colors->push_back(ItemPartColor());
for (u32 i = 0; i < mc; ++i) {
const TileSpec *tile = &(f.tiles[i]);
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
const TileLayer *layer = &tile->layers[layernum];
if (layer->texture_id == 0)
continue;
if (layernum != 0) {
scene::IMeshBuffer *copy = cloneMeshBuffer(buf);
copy->getMaterial() = buf->getMaterial();
mesh->addMeshBuffer(copy);
copy->drop();
buf = copy;
colors->push_back(
ItemPartColor(layer->has_color, layer->color));
} else {
(*colors)[i] = ItemPartColor(layer->has_color, layer->color);
}
video::SMaterial &material = buf->getMaterial();
if (set_material)
layer->applyMaterialOptions(material);
if (mattype) {
material.MaterialType = *mattype;
}
if (layer->animation_frame_count > 1) {
FrameSpec animation_frame = layer->frames[0];
material.setTexture(0, animation_frame.texture);
} else {
material.setTexture(0, layer->texture);
}
if (use_shaders) {
if (layer->normal_texture) {
if (layer->animation_frame_count > 1) {
FrameSpec animation_frame = layer->frames[0];
material.setTexture(1, animation_frame.normal_texture);
} else
material.setTexture(1, layer->normal_texture);
}
material.setTexture(2, layer->flags_texture);
}
}
}
}