From 1bb89ac359bc115e245fc16bb2c4fffb1465be59 Mon Sep 17 00:00:00 2001 From: x2048 Date: Wed, 8 Feb 2023 01:10:13 +0100 Subject: [PATCH] Extract all mesh grid maths into a dedicated class --- src/client/client.cpp | 10 ++++----- src/client/client.h | 15 ++++++-------- src/client/clientmap.cpp | 15 +++++++------- src/client/mapblock_mesh.cpp | 20 +++++++++--------- src/client/mapblock_mesh.h | 1 + src/client/mesh_generator_thread.cpp | 27 ++++++++++++------------ src/util/numeric.h | 31 ++++++++++++++++++++++++++++ 7 files changed, 73 insertions(+), 46 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index aab7d3e80cfd..8fbd56ac8368 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -143,7 +143,7 @@ Client::Client( } m_cache_save_interval = g_settings->getU16("server_map_save_interval"); - m_mesh_chunk = g_settings->getU16("client_mesh_chunk"); + m_mesh_grid = { g_settings->getU16("client_mesh_chunk") }; } void Client::migrateModStorage() @@ -608,10 +608,10 @@ void Client::step(float dtime) v3s16 ofs; // See also mapblock_mesh.cpp for the code that creates the array of minimap blocks. - for (ofs.Z = 0; ofs.Z < m_mesh_chunk; ofs.Z++) - for (ofs.Y = 0; ofs.Y < m_mesh_chunk; ofs.Y++) - for (ofs.X = 0; ofs.X < m_mesh_chunk; ofs.X++) { - size_t i = ofs.Z * m_mesh_chunk * m_mesh_chunk + ofs.Y * m_mesh_chunk + ofs.X; + for (ofs.Z = 0; ofs.Z < m_mesh_grid.cell_size; ofs.Z++) + for (ofs.Y = 0; ofs.Y < m_mesh_grid.cell_size; ofs.Y++) + for (ofs.X = 0; ofs.X < m_mesh_grid.cell_size; ofs.X++) { + size_t i = m_mesh_grid.getOffsetIndex(ofs); if (i < minimap_mapblocks.size() && minimap_mapblocks[i]) m_minimap->addBlock(r.p + ofs, minimap_mapblocks[i]); } diff --git a/src/client/client.h b/src/client/client.h index ada11d3a25de..3c7fc0db2de9 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -39,6 +39,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "network/peerhandler.h" #include "gameparams.h" #include +#include "util/numeric.h" #define CLIENT_CHAT_MESSAGE_LIMIT_PER_10S 10.0f @@ -437,15 +438,11 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef { return m_env.getLocalPlayer()->formspec_prepend; } - inline u16 getMeshChunk() { - return m_mesh_chunk; - } - inline s16 getMeshPos(s16 p) { - return ((p - (p < 0) * (m_mesh_chunk - 1)) / m_mesh_chunk * m_mesh_chunk); - } - inline bool checkMeshPos(v3s16 &p) { - return ((p.X + p.Y + p.Z) % m_mesh_chunk) == 0; + inline MeshGrid getMeshGrid() + { + return m_mesh_grid; } + private: void loadMods(); @@ -613,5 +610,5 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef std::unique_ptr m_modchannel_mgr; // The number of blocks the client will combine for mesh generation. - u16 m_mesh_chunk; + MeshGrid m_mesh_grid; }; diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index fc114c791693..af77e5ab2afb 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -304,6 +304,7 @@ void ClientMap::updateDrawList() blocks_seen.getChunk(camera_block).getBits(camera_block) = 0x07; // mark all sides as visible std::set shortlist; + MeshGrid mesh_grid = m_client->getMeshGrid(); // Recursively walk the space and pick mapblocks for drawing while (blocks_to_consider.size() > 0) { @@ -375,11 +376,11 @@ void ClientMap::updateDrawList() continue; } - if (m_client->getMeshChunk() > 1) { + if (mesh_grid.cell_size > 1) { // Block meshes are stored in the corner block of a chunk // (where all coordinate are divisible by the chunk size) // Add them to the de-dup set. - shortlist.emplace(m_client->getMeshPos(block_coord.X), m_client->getMeshPos(block_coord.Y), m_client->getMeshPos(block_coord.Z)); + shortlist.emplace(mesh_grid.getMeshPos(block_coord.X), mesh_grid.getMeshPos(block_coord.Y), mesh_grid.getMeshPos(block_coord.Z)); // All other blocks we can grab and add to the keeplist right away. if (block) { m_keeplist.push_back(block); @@ -619,8 +620,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) auto is_frustum_culled = m_client->getCamera()->getFrustumCuller(); - const u16 mesh_chunk = m_client->getMeshChunk(); - const u16 mesh_chunk_vol = mesh_chunk * mesh_chunk * mesh_chunk; + const MeshGrid mesh_grid = m_client->getMeshGrid(); for (auto &i : m_drawlist) { v3s16 block_pos = i.first; MapBlock *block = i.second; @@ -749,7 +749,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) material.TextureLayer[ShadowRenderer::TEXTURE_LAYER_SHADOW].Texture = nullptr; } - v3f block_wpos = intToFloat(descriptor.m_pos / mesh_chunk_vol * mesh_chunk_vol * MAP_BLOCKSIZE, BS); + v3f block_wpos = intToFloat(mesh_grid.getMeshPos(descriptor.m_pos) * MAP_BLOCKSIZE, BS); m.setTranslation(block_wpos - offset); driver->setTransform(video::ETS_WORLD, m); @@ -987,8 +987,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, return; } - const u16 mesh_chunk = m_client->getMeshChunk(); - const u16 mesh_chunk_vol = mesh_chunk * mesh_chunk * mesh_chunk; + const MeshGrid mesh_grid = m_client->getMeshGrid(); for (const auto &i : m_drawlist_shadow) { // only process specific part of the list & break early ++count; @@ -1077,7 +1076,7 @@ void ClientMap::renderMapShadows(video::IVideoDriver *driver, ++material_swaps; } - v3f block_wpos = intToFloat(descriptor.m_pos / mesh_chunk_vol * mesh_chunk_vol * MAP_BLOCKSIZE, BS); + v3f block_wpos = intToFloat(mesh_grid.getMeshPos(descriptor.m_pos) * MAP_BLOCKSIZE, BS); m.setTranslation(block_wpos - offset); driver->setTransform(video::ETS_WORLD, m); diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 98e5f06f51f0..e6ccb764f4dc 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -38,7 +38,9 @@ with this program; if not, write to the Free Software Foundation, Inc., MeshMakeData::MeshMakeData(Client *client, bool use_shaders): m_client(client), - m_use_shaders(use_shaders) + m_use_shaders(use_shaders), + m_mesh_grid(client->getMeshGrid()), + side_length(MAP_BLOCKSIZE * m_mesh_grid.cell_size) {} void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos) @@ -1176,22 +1178,20 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): m_enable_shaders = data->m_use_shaders; m_enable_vbo = g_settings->getBool("enable_vbo"); - const u16 mesh_chunk = data->side_length / MAP_BLOCKSIZE; - const u16 mesh_chunk_vol = mesh_chunk * mesh_chunk * mesh_chunk; v3s16 bp = data->m_blockpos; // Only generate minimap mapblocks at even coordinates. - if (data->m_client->checkMeshPos(bp) && data->m_client->getMinimap()) { - m_minimap_mapblocks.resize(mesh_chunk_vol, nullptr); + if (data->m_mesh_grid.isMeshPos(bp) && data->m_client->getMinimap()) { + m_minimap_mapblocks.resize(data->m_mesh_grid.getCellVolume(), nullptr); v3s16 ofs; // See also client.cpp for the code that reads the array of minimap blocks. - for (ofs.Z = 0; ofs.Z < mesh_chunk; ofs.Z++) - for (ofs.Y = 0; ofs.Y < mesh_chunk; ofs.Y++) - for (ofs.X = 0; ofs.X < mesh_chunk; ofs.X++) { + for (ofs.Z = 0; ofs.Z < data->m_mesh_grid.cell_size; ofs.Z++) + for (ofs.Y = 0; ofs.Y < data->m_mesh_grid.cell_size; ofs.Y++) + for (ofs.X = 0; ofs.X < data->m_mesh_grid.cell_size; ofs.X++) { v3s16 p = (bp + ofs) * MAP_BLOCKSIZE; if (data->m_vmanip.getNodeNoEx(p).getContent() != CONTENT_IGNORE) { MinimapMapblock *block = new MinimapMapblock; - m_minimap_mapblocks[ofs.Z * mesh_chunk * mesh_chunk + ofs.Y * mesh_chunk + ofs.X] = block; + m_minimap_mapblocks[data->m_mesh_grid.getOffsetIndex(ofs)] = block; block->getMinimapNodes(&data->m_vmanip, p); } } @@ -1222,7 +1222,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): Convert FastFaces to MeshCollector */ - v3f offset = intToFloat((data->m_blockpos - data->m_blockpos / mesh_chunk_vol * mesh_chunk_vol ) * MAP_BLOCKSIZE, BS); + v3f offset = intToFloat((data->m_blockpos - data->m_mesh_grid.getMeshPos(data->m_blockpos)) * MAP_BLOCKSIZE, BS); MeshCollector collector(m_bounding_sphere_center, offset); { diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index 12b071709b47..6d5f0dae3a96 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -43,6 +43,7 @@ struct MeshMakeData v3s16 m_blockpos = v3s16(-1337,-1337,-1337); v3s16 m_crack_pos_relative = v3s16(-1337,-1337,-1337); bool m_smooth_lighting = false; + MeshGrid m_mesh_grid; u16 side_length = MAP_BLOCKSIZE; Client *m_client; diff --git a/src/client/mesh_generator_thread.cpp b/src/client/mesh_generator_thread.cpp index e5e2b28a5c27..95ae25074a6a 100644 --- a/src/client/mesh_generator_thread.cpp +++ b/src/client/mesh_generator_thread.cpp @@ -77,9 +77,11 @@ bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool 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(m_client->getMeshPos(p.X), m_client->getMeshPos(p.Y), m_client->getMeshPos(p.Z)); + v3s16 mesh_position(mesh_grid.getMeshPos(p)); /* Mark the block as urgent if requested */ @@ -90,7 +92,6 @@ bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool Find if block is already in queue. If it is, update the data and quit. */ - const u16 mesh_chunk = m_client->getMeshChunk(); for (QueuedMeshUpdate *q : m_queue) { if (q->p == mesh_position) { // NOTE: We are not adding a new position to the queue, thus @@ -102,9 +103,9 @@ bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool q->urgent |= urgent; v3s16 pos; int i = 0; - for (pos.X = q->p.X - 1; pos.X <= q->p.X + mesh_chunk; pos.X++) - for (pos.Z = q->p.Z - 1; pos.Z <= q->p.Z + mesh_chunk; pos.Z++) - for (pos.Y = q->p.Y - 1; pos.Y <= q->p.Y + mesh_chunk; pos.Y++) { + 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) { @@ -122,11 +123,11 @@ bool MeshUpdateQueue::addBlock(Map *map, v3s16 p, bool ack_block_to_server, bool Make a list of blocks necessary for mesh generation and lock the blocks in memory. */ std::vector map_blocks; - map_blocks.reserve((mesh_chunk+2)*(mesh_chunk+2)*(mesh_chunk+2)); + 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_chunk; pos.X++) - for (pos.Z = mesh_position.Z - 1; pos.Z <= mesh_position.Z + mesh_chunk; pos.Z++) - for (pos.Y = mesh_position.Y - 1; pos.Y <= mesh_position.Y + mesh_chunk; pos.Y++) { + 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) @@ -189,18 +190,16 @@ void MeshUpdateQueue::done(v3s16 pos) void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q) { - const u16 mesh_chunk = m_client->getMeshChunk(); MeshMakeData *data = new MeshMakeData(m_client, m_cache_enable_shaders); q->data = data; - data->side_length = mesh_chunk * MAP_BLOCKSIZE; data->fillBlockDataBegin(q->p); v3s16 pos; int i = 0; - for (pos.X = q->p.X - 1; pos.X <= q->p.X + mesh_chunk; pos.X++) - for (pos.Z = q->p.Z - 1; pos.Z <= q->p.Z + mesh_chunk; pos.Z++) - for (pos.Y = q->p.Y - 1; pos.Y <= q->p.Y + mesh_chunk; pos.Y++) { + for (pos.X = q->p.X - 1; pos.X <= q->p.X + data->m_mesh_grid.cell_size; pos.X++) + for (pos.Z = q->p.Z - 1; pos.Z <= q->p.Z + data->m_mesh_grid.cell_size; pos.Z++) + for (pos.Y = q->p.Y - 1; pos.Y <= q->p.Y + data->m_mesh_grid.cell_size; pos.Y++) { MapBlock *block = q->map_blocks[i++]; data->fillBlockData(pos, block ? block->getData() : block_placeholder.data); } diff --git a/src/util/numeric.h b/src/util/numeric.h index 265046a63243..f0d4fe48214b 100644 --- a/src/util/numeric.h +++ b/src/util/numeric.h @@ -145,6 +145,37 @@ inline v3s16 componentwise_max(const v3s16 &a, const v3s16 &b) return v3s16(MYMAX(a.X, b.X), MYMAX(a.Y, b.Y), MYMAX(a.Z, b.Z)); } +/// @brief Describes a grid with given step, oirginating at (0,0,0) +struct MeshGrid { + u16 cell_size; + + u32 getCellVolume() const { return cell_size * cell_size * cell_size; } + + /// @brief returns closest step of the grid smaller than p + s16 getMeshPos(s16 p) const + { + return ((p - (p < 0) * (cell_size - 1)) / cell_size * cell_size); + } + + /// @brief Returns coordinates of the origin of the grid cell containing p + v3s16 getMeshPos(v3s16 p) const + { + return v3s16(getMeshPos(p.X), getMeshPos(p.Y), getMeshPos(p.Z)); + } + + /// @brief Returns true if p is an origin of a cell in the grid. + bool isMeshPos(v3s16 &p) const + { + return ((p.X + p.Y + p.Z) % cell_size) == 0; + } + + /// @brief Returns index of the given offset in a grid cell + /// All offset coordinates must be smaller than the size of the cell + u16 getOffsetIndex(v3s16 offset) const + { + return (offset.Z * cell_size + offset.Y) * cell_size + offset.X; + } +}; /** Returns \p f wrapped to the range [-360, 360] *