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

Fix crack on animated tiles

This commit is contained in:
cx384 2025-04-07 21:51:01 +02:00
parent bed36139db
commit 3a607c545c
4 changed files with 75 additions and 22 deletions

View file

@ -647,6 +647,9 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
m_bounding_radius = std::sqrt(collector.m_bounding_radius_sq);
// Using the current time avoids flickering before animate() gets called
auto animation_time = client->getAnimationTime();
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
scene::SMesh *mesh = static_cast<scene::SMesh *>(m_mesh[layer].get());
@ -657,9 +660,39 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
p.applyTileColor();
// Generate animation data
// - Cracks
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
// Find the texture name plus ^[crack:N:
// - Texture animation with crack
std::vector<std::string> crack_frames{p.layer.frames->size()};
for (std::size_t j = 0; j < p.layer.frames->size(); j++) {
std::ostringstream os(std::ios::binary);
os << m_tsrc->getTextureName((*p.layer.frames)[j].texture_id) << "^[crack";
if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
os << "o"; // use ^[cracko
os << ":" << 1 << ":";
crack_frames[j] = os.str();
}
AnimationInfo animation_info = AnimationInfo(p.layer);
animation_info.needUpdate(animation_time); // Update current frame
// Replace tile texture with the cracked animated one
p.layer.texture = m_tsrc->getTextureForMesh(
crack_frames[animation_info.getCurrentFrame()] + "0",
&p.layer.texture_id);
m_animation_info_crack.emplace(std::make_pair(layer, i),
std::make_pair(std::move(animation_info), std::move(crack_frames)));
} else {
// - Texture animation
AnimationInfo animation_info = AnimationInfo(p.layer);
animation_info.needUpdate(animation_time); // Update current frame
// Replace tile texture with the current animation frame
p.layer.texture = (*p.layer.frames)[animation_info.getCurrentFrame()].texture;
// Add to MapBlockMesh in order to animate these tiles
m_animation_info.emplace(std::make_pair(layer, i), std::move(animation_info));
}
} else if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
// - Cracks
std::ostringstream os(std::ios::binary);
os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
@ -675,13 +708,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
os.str() + "0",
&p.layer.texture_id);
}
// - Texture animation
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
// Add to MapBlockMesh in order to animate these tiles
m_animation_info.emplace(std::make_pair(layer, i), AnimationInfo(p.layer));
// Replace tile texture with the first animation frame
p.layer.texture = (*p.layer.frames)[0].texture;
}
// Create material
video::SMaterial material;
@ -731,7 +757,8 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
// Check if animation is required for this mesh
m_has_animation =
!m_crack_materials.empty() ||
!m_animation_info.empty();
!m_animation_info.empty() ||
!m_animation_info_crack.empty();
}
MapBlockMesh::~MapBlockMesh()
@ -761,12 +788,6 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack,
// Cracks
if (crack != m_last_crack) {
for (auto &crack_material : m_crack_materials) {
// TODO crack on animated tiles does not work
auto anim_it = m_animation_info.find(crack_material.first);
if (anim_it != m_animation_info.end())
continue;
scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
getMeshBuffer(crack_material.first.second);
@ -777,8 +798,6 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack,
m_tsrc->getTextureForMesh(s, &new_texture_id);
buf->getMaterial().setTexture(0, new_texture);
}
m_last_crack = crack;
}
// Texture animation
@ -788,6 +807,20 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack,
it.second.updateTexture(material, time);
}
// Texture animation with crack
for (auto &it : m_animation_info_crack) {
if (crack != m_last_crack || it.second.first.needUpdate(time)) {
scene::IMeshBuffer *buf = m_mesh[it.first.first]->getMeshBuffer(it.first.second);
u16 frame = it.second.first.getCurrentFrame();
std::string s = it.second.second[frame] + itos(crack);
u32 new_texture_id = 0;
video::ITexture *new_texture = m_tsrc->getTextureForMesh(s, &new_texture_id);
buf->getMaterial().setTexture(0, new_texture);
}
}
m_last_crack = crack;
return true;
}

View file

@ -266,10 +266,15 @@ private:
std::map<std::pair<u8, u32>, std::string> m_crack_materials;
// Animation info: texture animation
// Maps mesh and mesh buffer indices to TileSpecs
// Maps mesh and mesh buffer indices to AnimationInfo
// Keys are pairs of (mesh index, buffer index in the mesh)
std::map<std::pair<u8, u32>, AnimationInfo> m_animation_info;
// Same as above, but in the case both are needed, animation and crack
// The vector contains base crack textures for each animation frame
std::map<std::pair<u8, u32>, std::pair<AnimationInfo, std::vector<std::string>>>
m_animation_info_crack;
// list of all semitransparent triangles in the mapblock
std::vector<MeshTriangle> m_transparent_triangles;
// Binary Space Partitioning tree for the block

View file

@ -6,15 +6,23 @@
#include <cassert>
void AnimationInfo::updateTexture(video::SMaterial &material, float animation_time)
{
if (needUpdate(animation_time)) {
assert(m_frame < m_frames->size());
material.setTexture(0, (*m_frames)[m_frame].texture);
}
};
bool AnimationInfo::needUpdate(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);
return true;
}
return false;
};
void TileLayer::applyMaterialOptions(video::SMaterial &material, int layer) const

View file

@ -164,6 +164,13 @@ struct AnimationInfo {
void updateTexture(video::SMaterial &material, float animation_time);
// Returns true if texture needs to be updated
// Also proceeds to next frame if update is needed
bool needUpdate(float animation_time);
// Returns last used frame
u16 getCurrentFrame() const { return m_frame; };
private:
u16 m_frame = 0; // last animation frame
u16 m_frame_length_ms = 0;