1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-30 19:22:14 +00:00
This commit is contained in:
cx384 2025-09-30 15:07:43 +03:00 committed by GitHub
commit 854c1c8bcc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 76 additions and 24 deletions

View file

@ -638,6 +638,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());
@ -648,9 +651,39 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
p.applyTileColor();
// Generate animation data
// - Cracks
if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
// Find the texture name plus ^[crack:N:
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
// - 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)
@ -658,7 +691,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
u8 tiles = p.layer.scale;
if (tiles > 1)
os << ":" << (u32)tiles;
os << ":" << (u32)p.layer.animation_frame_count << ":";
os << ":1:";
m_crack_materials.insert(std::make_pair(
std::pair<u8, u32>(layer, i), os.str()));
// Replace tile texture with the cracked one
@ -666,13 +699,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;
@ -722,7 +748,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()
@ -752,12 +779,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);
@ -768,8 +789,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
@ -779,6 +798,19 @@ 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);
video::ITexture *new_texture = m_tsrc->getTextureForMesh(s);
buf->getMaterial().setTexture(0, new_texture);
}
}
m_last_crack = crack;
return true;
}

View file

@ -278,10 +278,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,16 +6,24 @@
#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;