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 0ea89d4112
commit 6545710c8e
6 changed files with 95 additions and 61 deletions

View file

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

View file

@ -472,7 +472,6 @@ void MapblockMeshGenerator::drawSolidNode()
if (!faces)
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.
cur_node.origin = intToFloat(cur_node.p, BS);
auto box = aabb3f(v3f(-0.5 * BS), v3f(0.5 * BS));
box.MinEdge += cur_node.origin;
box.MaxEdge += cur_node.origin;
@ -1773,6 +1772,7 @@ void MapblockMeshGenerator::errorUnknownDrawtype()
void MapblockMeshGenerator::drawNode()
{
cur_node.origin = intToFloat(cur_node.p, BS);
switch (cur_node.f->drawtype) {
case NDT_AIRLIKE: // Not drawn at all
return;
@ -1783,7 +1783,6 @@ void MapblockMeshGenerator::drawNode()
default:
break;
}
cur_node.origin = intToFloat(cur_node.p, BS);
if (data->m_smooth_lighting) {
getSmoothLightFrame();
} else {

View file

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

View file

@ -212,6 +212,20 @@ public:
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
{
return m_animation_force_timer == 0;
@ -242,7 +256,7 @@ public:
/// get the list of transparent buffers
const std::vector<PartialMeshBuffer> &getTransparentBuffers() const
{
return this->m_transparent_buffers;
return m_transparent_buffers;
}
private:

View file

@ -20,6 +20,38 @@ QueuedMeshUpdate::~QueuedMeshUpdate()
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
*/
@ -36,26 +68,28 @@ MeshUpdateQueue::~MeshUpdateQueue()
MutexAutoLock lock(m_mutex);
for (QueuedMeshUpdate *q : m_queue) {
for (auto block : q->map_blocks)
if (block)
block->refDrop();
q->dropBlocks();
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);
if (!main_block)
return false;
MutexAutoLock lock(m_mutex);
MeshGrid mesh_grid = m_client->getMeshGrid();
// Mesh is placed at the corner block of a chunk
// (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
*/
@ -68,57 +102,27 @@ bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool
*/
for (QueuedMeshUpdate *q : m_queue) {
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->crack_level = m_client->getCrackLevel();
q->crack_pos = m_client->getCrackPos();
q->urgent |= urgent;
v3s16 pos;
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++;
}
q->retrieveBlocks(map, mesh_grid.cell_size);
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
*/
QueuedMeshUpdate *q = new QueuedMeshUpdate;
q->p = mesh_position;
if(ack_block_to_server)
if (ack_block_to_server)
q->ack_list.push_back(p);
q->crack_level = m_client->getCrackLevel();
q->crack_pos = m_client->getCrackPos();
q->urgent = urgent;
q->map_blocks = std::move(map_blocks);
q->retrieveBlocks(map, mesh_grid.cell_size);
m_queue.push_back(q);
return true;
@ -208,6 +212,7 @@ void MeshUpdateWorkerThread::doUpdate()
ScopeProfiler sp(g_profiler, "Client: Mesh making (sum)");
// This generates the mesh:
MapBlockMesh *mesh_new = new MapBlockMesh(m_client, q->data);
MeshUpdateResult r;
@ -216,7 +221,7 @@ void MeshUpdateWorkerThread::doUpdate()
r.solid_sides = get_solid_sides(q->data);
r.ack_list = std::move(q->ack_list);
r.urgent = q->urgent;
r.map_blocks = q->map_blocks;
r.map_blocks = std::move(q->map_blocks);
m_manager->putResult(r);
m_queue_in->done(q->p);
@ -251,7 +256,7 @@ void MeshUpdateManager::updateBlock(Map *map, v3s16 p, bool ack_block_to_server,
static thread_local const bool many_neighbors =
g_settings->getBool("smooth_lighting")
&& !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 "
<< p << std::endl;
return;
@ -259,10 +264,10 @@ void MeshUpdateManager::updateBlock(Map *map, v3s16 p, bool ack_block_to_server,
if (update_neighbors) {
if (many_neighbors) {
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 {
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();

View file

@ -22,11 +22,24 @@ struct QueuedMeshUpdate
int crack_level = -1;
v3s16 crack_pos;
MeshMakeData *data = nullptr; // This is generated in MeshUpdateQueue::pop()
std::vector<MapBlock *> map_blocks;
std::vector<MapBlock*> map_blocks;
bool urgent = false;
QueuedMeshUpdate() = default;
~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();
// Caches the block at p and its neighbors (if needed) and queues a mesh
// update for the block at p
bool addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent);
/**
* Caches the block at p and its neighbors (if needed) and queues a mesh
* 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
// Returns NULL if queue is empty
@ -56,7 +76,7 @@ public:
// Marks a position as finished, unblocking the next update
void done(v3s16 pos);
u32 size()
size_t size()
{
MutexAutoLock lock(m_mutex);
return m_queue.size();
@ -83,7 +103,7 @@ struct MeshUpdateResult
u8 solid_sides;
std::vector<v3s16> ack_list;
bool urgent = false;
std::vector<MapBlock *> map_blocks;
std::vector<MapBlock*> map_blocks;
MeshUpdateResult() = default;
};
@ -117,6 +137,7 @@ public:
void updateBlock(Map *map, v3s16 p, bool ack_block_to_server, bool urgent,
bool update_neighbors = false);
void putResult(const MeshUpdateResult &r);
/// @note caller needs to refDrop() the affected map_blocks
bool getNextResult(MeshUpdateResult &r);