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:
parent
bed36139db
commit
3a607c545c
4 changed files with 75 additions and 22 deletions
|
@ -647,6 +647,9 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
|
||||||
|
|
||||||
m_bounding_radius = std::sqrt(collector.m_bounding_radius_sq);
|
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++) {
|
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
|
||||||
scene::SMesh *mesh = static_cast<scene::SMesh *>(m_mesh[layer].get());
|
scene::SMesh *mesh = static_cast<scene::SMesh *>(m_mesh[layer].get());
|
||||||
|
|
||||||
|
@ -657,9 +660,39 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
|
||||||
p.applyTileColor();
|
p.applyTileColor();
|
||||||
|
|
||||||
// Generate animation data
|
// Generate animation data
|
||||||
// - Cracks
|
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
|
||||||
if (p.layer.material_flags & MATERIAL_FLAG_CRACK) {
|
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);
|
std::ostringstream os(std::ios::binary);
|
||||||
os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
|
os << m_tsrc->getTextureName(p.layer.texture_id) << "^[crack";
|
||||||
if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
|
if (p.layer.material_flags & MATERIAL_FLAG_CRACK_OVERLAY)
|
||||||
|
@ -675,13 +708,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
|
||||||
os.str() + "0",
|
os.str() + "0",
|
||||||
&p.layer.texture_id);
|
&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
|
// Create material
|
||||||
video::SMaterial material;
|
video::SMaterial material;
|
||||||
|
@ -731,7 +757,8 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data):
|
||||||
// Check if animation is required for this mesh
|
// Check if animation is required for this mesh
|
||||||
m_has_animation =
|
m_has_animation =
|
||||||
!m_crack_materials.empty() ||
|
!m_crack_materials.empty() ||
|
||||||
!m_animation_info.empty();
|
!m_animation_info.empty() ||
|
||||||
|
!m_animation_info_crack.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
MapBlockMesh::~MapBlockMesh()
|
MapBlockMesh::~MapBlockMesh()
|
||||||
|
@ -761,12 +788,6 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack,
|
||||||
// Cracks
|
// Cracks
|
||||||
if (crack != m_last_crack) {
|
if (crack != m_last_crack) {
|
||||||
for (auto &crack_material : m_crack_materials) {
|
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]->
|
scene::IMeshBuffer *buf = m_mesh[crack_material.first.first]->
|
||||||
getMeshBuffer(crack_material.first.second);
|
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);
|
m_tsrc->getTextureForMesh(s, &new_texture_id);
|
||||||
buf->getMaterial().setTexture(0, new_texture);
|
buf->getMaterial().setTexture(0, new_texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_last_crack = crack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texture animation
|
// Texture animation
|
||||||
|
@ -788,6 +807,20 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack,
|
||||||
it.second.updateTexture(material, time);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -266,10 +266,15 @@ private:
|
||||||
std::map<std::pair<u8, u32>, std::string> m_crack_materials;
|
std::map<std::pair<u8, u32>, std::string> m_crack_materials;
|
||||||
|
|
||||||
// Animation info: texture animation
|
// 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)
|
// Keys are pairs of (mesh index, buffer index in the mesh)
|
||||||
std::map<std::pair<u8, u32>, AnimationInfo> m_animation_info;
|
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
|
// list of all semitransparent triangles in the mapblock
|
||||||
std::vector<MeshTriangle> m_transparent_triangles;
|
std::vector<MeshTriangle> m_transparent_triangles;
|
||||||
// Binary Space Partitioning tree for the block
|
// Binary Space Partitioning tree for the block
|
||||||
|
|
|
@ -6,15 +6,23 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
void AnimationInfo::updateTexture(video::SMaterial &material, float animation_time)
|
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
|
// Figure out current frame
|
||||||
u16 frame = (u16)(animation_time * 1000 / m_frame_length_ms) % m_frame_count;
|
u16 frame = (u16)(animation_time * 1000 / m_frame_length_ms) % m_frame_count;
|
||||||
// Only adjust if frame changed
|
// Only adjust if frame changed
|
||||||
if (frame != m_frame) {
|
if (frame != m_frame) {
|
||||||
m_frame = frame;
|
m_frame = frame;
|
||||||
assert(m_frame < m_frames->size());
|
return true;
|
||||||
material.setTexture(0, (*m_frames)[m_frame].texture);
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void TileLayer::applyMaterialOptions(video::SMaterial &material, int layer) const
|
void TileLayer::applyMaterialOptions(video::SMaterial &material, int layer) const
|
||||||
|
|
|
@ -164,6 +164,13 @@ struct AnimationInfo {
|
||||||
|
|
||||||
void updateTexture(video::SMaterial &material, float animation_time);
|
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:
|
private:
|
||||||
u16 m_frame = 0; // last animation frame
|
u16 m_frame = 0; // last animation frame
|
||||||
u16 m_frame_length_ms = 0;
|
u16 m_frame_length_ms = 0;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue