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

Refactor meshgen-related code

This commit is contained in:
sfan5 2025-06-23 12:30:44 +02:00
parent 0794145b64
commit 241766acf6
6 changed files with 95 additions and 61 deletions

View file

@ -612,12 +612,7 @@ void Client::step(float dtime)
if (minimap_mapblocks.empty()) if (minimap_mapblocks.empty())
do_mapper_update = false; do_mapper_update = false;
bool is_empty = true; if (r.mesh->isEmpty()) {
for (int l = 0; l < MAX_TILE_LAYERS; l++)
if (r.mesh->getMesh(l)->getMeshBufferCount() != 0)
is_empty = false;
if (is_empty) {
delete r.mesh; delete r.mesh;
} else { } else {
// Replace with the new mesh // Replace with the new mesh

View file

@ -472,7 +472,6 @@ void MapblockMeshGenerator::drawSolidNode()
if (!faces) if (!faces)
return; return;
u8 mask = faces ^ 0b0011'1111; // k-th bit is set if k-th face is to be *omitted*, as expected by cuboid drawing functions. u8 mask = faces ^ 0b0011'1111; // k-th bit is set if k-th face is to be *omitted*, as expected by cuboid drawing functions.
cur_node.origin = intToFloat(cur_node.p, BS);
auto box = aabb3f(v3f(-0.5 * BS), v3f(0.5 * BS)); auto box = aabb3f(v3f(-0.5 * BS), v3f(0.5 * BS));
box.MinEdge += cur_node.origin; box.MinEdge += cur_node.origin;
box.MaxEdge += cur_node.origin; box.MaxEdge += cur_node.origin;
@ -1773,6 +1772,7 @@ void MapblockMeshGenerator::errorUnknownDrawtype()
void MapblockMeshGenerator::drawNode() void MapblockMeshGenerator::drawNode()
{ {
cur_node.origin = intToFloat(cur_node.p, BS);
switch (cur_node.f->drawtype) { switch (cur_node.f->drawtype) {
case NDT_AIRLIKE: // Not drawn at all case NDT_AIRLIKE: // Not drawn at all
return; return;
@ -1783,7 +1783,6 @@ void MapblockMeshGenerator::drawNode()
default: default:
break; break;
} }
cur_node.origin = intToFloat(cur_node.p, BS);
if (data->m_smooth_lighting) { if (data->m_smooth_lighting) {
getSmoothLightFrame(); getSmoothLightFrame();
} else { } else {

View file

@ -27,7 +27,7 @@ struct LightInfo {
float light_night; float light_night;
float light_boosted; float light_boosted;
LightPair getPair(float sunlight_boost = 0.0) const LightPair getPair(float sunlight_boost = 0.0f) const
{ {
return LightPair( return LightPair(
(1 - sunlight_boost) * light_day (1 - sunlight_boost) * light_day

View file

@ -212,6 +212,20 @@ public:
return minimap_mapblocks; return minimap_mapblocks;
} }
/// @return true if the mesh contains nothing to draw
bool isEmpty() const
{
if (!m_transparent_triangles.empty())
return false;
for (auto &mesh : m_mesh) {
for (u32 i = 0; i < mesh->getMeshBufferCount(); i++) {
if (mesh->getMeshBuffer(i)->getIndexCount() != 0)
return false;
}
}
return true;
}
bool isAnimationForced() const bool isAnimationForced() const
{ {
return m_animation_force_timer == 0; return m_animation_force_timer == 0;
@ -242,7 +256,7 @@ public:
/// get the list of transparent buffers /// get the list of transparent buffers
const std::vector<PartialMeshBuffer> &getTransparentBuffers() const const std::vector<PartialMeshBuffer> &getTransparentBuffers() const
{ {
return this->m_transparent_buffers; return m_transparent_buffers;
} }
private: private:

View file

@ -32,6 +32,38 @@ QueuedMeshUpdate::~QueuedMeshUpdate()
delete data; delete data;
} }
void QueuedMeshUpdate::retrieveBlocks(Map *map, u16 cell_size)
{
const size_t total = (cell_size+2)*(cell_size+2)*(cell_size+2);
if (map_blocks.empty())
map_blocks.resize(total);
else
assert(map_blocks.size() == total); // must not change
size_t i = 0;
v3s16 pos;
for (pos.X = p.X - 1; pos.X <= p.X + cell_size; pos.X++)
for (pos.Z = p.Z - 1; pos.Z <= p.Z + cell_size; pos.Z++)
for (pos.Y = p.Y - 1; pos.Y <= p.Y + cell_size; pos.Y++) {
if (!map_blocks[i]) {
MapBlock *block = map->getBlockNoCreateNoEx(pos);
if (block) {
block->refGrab();
map_blocks[i] = block;
}
}
i++;
}
}
void QueuedMeshUpdate::dropBlocks()
{
for (auto *block : map_blocks) {
if (block)
block->refDrop();
}
map_blocks.clear();
}
/* /*
MeshUpdateQueue MeshUpdateQueue
*/ */
@ -48,26 +80,28 @@ MeshUpdateQueue::~MeshUpdateQueue()
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);
for (QueuedMeshUpdate *q : m_queue) { for (QueuedMeshUpdate *q : m_queue) {
for (auto block : q->map_blocks) q->dropBlocks();
if (block)
block->refDrop();
delete q; delete q;
} }
} }
bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent) bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server,
bool urgent, bool from_neighbor)
{ {
// FIXME: with cell_size > 1 there isn't a "main block" and this check is
// probably incorrect and broken
MapBlock *main_block = map->getBlockNoCreateNoEx(p); MapBlock *main_block = map->getBlockNoCreateNoEx(p);
if (!main_block) if (!main_block)
return false; return false;
MutexAutoLock lock(m_mutex);
MeshGrid mesh_grid = m_client->getMeshGrid(); MeshGrid mesh_grid = m_client->getMeshGrid();
// Mesh is placed at the corner block of a chunk // Mesh is placed at the corner block of a chunk
// (where all coordinate are divisible by the chunk size) // (where all coordinate are divisible by the chunk size)
v3s16 mesh_position(mesh_grid.getMeshPos(p)); v3s16 mesh_position = mesh_grid.getMeshPos(p);
MutexAutoLock lock(m_mutex);
/* /*
Mark the block as urgent if requested Mark the block as urgent if requested
*/ */
@ -80,46 +114,16 @@ bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool
*/ */
for (QueuedMeshUpdate *q : m_queue) { for (QueuedMeshUpdate *q : m_queue) {
if (q->p == mesh_position) { if (q->p == mesh_position) {
// NOTE: We are not adding a new position to the queue, thus
// refcount_from_queue stays the same.
if (ack_block_to_server) if (ack_block_to_server)
q->ack_list.push_back(p); q->ack_list.push_back(p);
q->crack_level = m_client->getCrackLevel(); q->crack_level = m_client->getCrackLevel();
q->crack_pos = m_client->getCrackPos(); q->crack_pos = m_client->getCrackPos();
q->urgent |= urgent; q->urgent |= urgent;
v3s16 pos; q->retrieveBlocks(map, mesh_grid.cell_size);
int i = 0;
for (pos.X = q->p.X - 1; pos.X <= q->p.X + mesh_grid.cell_size; pos.X++)
for (pos.Z = q->p.Z - 1; pos.Z <= q->p.Z + mesh_grid.cell_size; pos.Z++)
for (pos.Y = q->p.Y - 1; pos.Y <= q->p.Y + mesh_grid.cell_size; pos.Y++) {
if (!q->map_blocks[i]) {
MapBlock *block = map->getBlockNoCreateNoEx(pos);
if (block) {
block->refGrab();
q->map_blocks[i] = block;
}
}
i++;
}
return true; return true;
} }
} }
/*
Make a list of blocks necessary for mesh generation and lock the blocks in memory.
*/
std::vector<MapBlock *> map_blocks;
map_blocks.reserve((mesh_grid.cell_size+2)*(mesh_grid.cell_size+2)*(mesh_grid.cell_size+2));
v3s16 pos;
for (pos.X = mesh_position.X - 1; pos.X <= mesh_position.X + mesh_grid.cell_size; pos.X++)
for (pos.Z = mesh_position.Z - 1; pos.Z <= mesh_position.Z + mesh_grid.cell_size; pos.Z++)
for (pos.Y = mesh_position.Y - 1; pos.Y <= mesh_position.Y + mesh_grid.cell_size; pos.Y++) {
MapBlock *block = map->getBlockNoCreateNoEx(pos);
map_blocks.push_back(block);
if (block)
block->refGrab();
}
/* /*
Add the block Add the block
*/ */
@ -130,7 +134,7 @@ bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool
q->crack_level = m_client->getCrackLevel(); q->crack_level = m_client->getCrackLevel();
q->crack_pos = m_client->getCrackPos(); q->crack_pos = m_client->getCrackPos();
q->urgent = urgent; q->urgent = urgent;
q->map_blocks = std::move(map_blocks); q->retrieveBlocks(map, mesh_grid.cell_size);
m_queue.push_back(q); m_queue.push_back(q);
return true; return true;
@ -219,6 +223,7 @@ void MeshUpdateWorkerThread::doUpdate()
ScopeProfiler sp(g_profiler, "Client: Mesh making (sum)"); ScopeProfiler sp(g_profiler, "Client: Mesh making (sum)");
// This generates the mesh:
MapBlockMesh *mesh_new = new MapBlockMesh(m_client, q->data); MapBlockMesh *mesh_new = new MapBlockMesh(m_client, q->data);
MeshUpdateResult r; MeshUpdateResult r;
@ -227,7 +232,7 @@ void MeshUpdateWorkerThread::doUpdate()
r.solid_sides = get_solid_sides(q->data); r.solid_sides = get_solid_sides(q->data);
r.ack_list = std::move(q->ack_list); r.ack_list = std::move(q->ack_list);
r.urgent = q->urgent; r.urgent = q->urgent;
r.map_blocks = q->map_blocks; r.map_blocks = std::move(q->map_blocks);
m_manager->putResult(r); m_manager->putResult(r);
m_queue_in->done(q->p); m_queue_in->done(q->p);
@ -262,7 +267,7 @@ void MeshUpdateManager::updateBlock(Map *map, v3s16 p, bool ack_block_to_server,
static thread_local const bool many_neighbors = static thread_local const bool many_neighbors =
g_settings->getBool("smooth_lighting") g_settings->getBool("smooth_lighting")
&& !g_settings->getFlag("performance_tradeoffs"); && !g_settings->getFlag("performance_tradeoffs");
if (!m_queue_in.addBlock(map, p, ack_block_to_server, urgent)) { if (!m_queue_in.addBlock(map, p, ack_block_to_server, urgent, false)) {
warningstream << "Update requested for non-existent block at " warningstream << "Update requested for non-existent block at "
<< p << std::endl; << p << std::endl;
return; return;
@ -270,10 +275,10 @@ void MeshUpdateManager::updateBlock(Map *map, v3s16 p, bool ack_block_to_server,
if (update_neighbors) { if (update_neighbors) {
if (many_neighbors) { if (many_neighbors) {
for (v3s16 dp : g_26dirs) for (v3s16 dp : g_26dirs)
m_queue_in.addBlock(map, p + dp, false, urgent); m_queue_in.addBlock(map, p + dp, false, urgent, true);
} else { } else {
for (v3s16 dp : g_6dirs) for (v3s16 dp : g_6dirs)
m_queue_in.addBlock(map, p + dp, false, urgent); m_queue_in.addBlock(map, p + dp, false, urgent, true);
} }
} }
deferUpdate(); deferUpdate();

View file

@ -27,6 +27,19 @@ struct QueuedMeshUpdate
QueuedMeshUpdate() = default; QueuedMeshUpdate() = default;
~QueuedMeshUpdate(); ~QueuedMeshUpdate();
/**
* Get blocks needed for this mesh update from the map.
* Blocks that were already loaded are skipped.
* @param map Map
* @param cell_size mesh grid cell size
*/
void retrieveBlocks(Map *map, u16 cell_size);
/**
* Drop block references.
* @note not done by destructor, since this is only safe on main thread
*/
void dropBlocks();
}; };
/* /*
@ -45,9 +58,16 @@ public:
~MeshUpdateQueue(); ~MeshUpdateQueue();
// Caches the block at p and its neighbors (if needed) and queues a mesh /**
// update for the block at p * Caches the block at p and its neighbors (if needed) and queues a mesh
bool addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent); * update for the block p.
* @param map Map
* @param p block position
* @param ack_to_server Should be acked to server when done?
* @param urget High-priority?
* @param from_neighbor was this update only necessary due to a neighbor change?
*/
bool addBlock(Map *map, v3s16 p, bool ack_to_server, bool urgent, bool from_neighbor);
// Returned pointer must be deleted // Returned pointer must be deleted
// Returns NULL if queue is empty // Returns NULL if queue is empty
@ -56,7 +76,7 @@ public:
// Marks a position as finished, unblocking the next update // Marks a position as finished, unblocking the next update
void done(v3s16 pos); void done(v3s16 pos);
u32 size() size_t size()
{ {
MutexAutoLock lock(m_mutex); MutexAutoLock lock(m_mutex);
return m_queue.size(); return m_queue.size();
@ -117,6 +137,7 @@ public:
void updateBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent, void updateBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent,
bool update_neighbors = false); bool update_neighbors = false);
void putResult(const MeshUpdateResult &r); void putResult(const MeshUpdateResult &r);
/// @note caller needs to refDrop() the affected map_blocks
bool getNextResult(MeshUpdateResult &r); bool getNextResult(MeshUpdateResult &r);