X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient%2Fclientmap.cpp;h=10967c0cb1eec4009b307528d4eb8a8e64f0ca49;hb=7cea688a1c463c5e8caa28bbdb588a6b497a5d7d;hp=3e4ab2e94aefed7ebf7f048b16c8fac1bc66359c;hpb=6ada090bb05d9e6d5961a59f33ff6e104b44061a;p=minetest.git diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 3e4ab2e94..10967c0cb 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -31,17 +31,57 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "client/renderingengine.h" +// struct MeshBufListList +void MeshBufListList::clear() +{ + for (auto &list : lists) + list.clear(); +} + +void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer) +{ + // Append to the correct layer + std::vector &list = lists[layer]; + const video::SMaterial &m = buf->getMaterial(); + for (MeshBufList &l : list) { + // comparing a full material is quite expensive so we don't do it if + // not even first texture is equal + if (l.m.TextureLayer[0].Texture != m.TextureLayer[0].Texture) + continue; + + if (l.m == m) { + l.bufs.emplace_back(position, buf); + return; + } + } + MeshBufList l; + l.m = m; + l.bufs.emplace_back(position, buf); + list.emplace_back(l); +} + +// ClientMap + ClientMap::ClientMap( Client *client, + RenderingEngine *rendering_engine, MapDrawControl &control, s32 id ): - Map(dout_client, client), - scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(), - RenderingEngine::get_scene_manager(), id), + Map(client), + scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(), + rendering_engine->get_scene_manager(), id), m_client(client), - m_control(control) + m_rendering_engine(rendering_engine), + m_control(control), + m_drawlist(MapBlockComparer(v3s16(0,0,0))) { + + /* + * @Liso: Sadly C++ doesn't have introspection, so the only way we have to know + * the class is whith a name ;) Name property cames from ISceneNode base class. + */ + Name = "ClientMap"; m_box = aabb3f(-BS*1000000,-BS*1000000,-BS*1000000, BS*1000000,BS*1000000,BS*1000000); @@ -57,9 +97,32 @@ ClientMap::ClientMap( m_cache_trilinear_filter = g_settings->getBool("trilinear_filter"); m_cache_bilinear_filter = g_settings->getBool("bilinear_filter"); m_cache_anistropic_filter = g_settings->getBool("anisotropic_filter"); + m_cache_transparency_sorting_distance = g_settings->getU16("transparency_sorting_distance"); } +void ClientMap::updateCamera(v3f pos, v3f dir, f32 fov, v3s16 offset) +{ + v3s16 previous_node = floatToInt(m_camera_position, BS) + m_camera_offset; + v3s16 previous_block = getContainerPos(previous_node, MAP_BLOCKSIZE); + + m_camera_position = pos; + m_camera_direction = dir; + m_camera_fov = fov; + m_camera_offset = offset; + + v3s16 current_node = floatToInt(m_camera_position, BS) + m_camera_offset; + v3s16 current_block = getContainerPos(current_node, MAP_BLOCKSIZE); + + // reorder the blocks when camera crosses block boundary + if (previous_block != current_block) + m_needs_update_drawlist = true; + + // reorder transparent meshes when camera crosses node boundary + if (previous_node != current_node) + m_needs_update_transparent_meshes = true; +} + MapSector * ClientMap::emergeSector(v2s16 p2d) { // Check that it doesn't exist already @@ -83,12 +146,21 @@ void ClientMap::OnRegisterSceneNode() } ISceneNode::OnRegisterSceneNode(); + + if (!m_added_to_shadow_renderer) { + m_added_to_shadow_renderer = true; + if (auto shadows = m_rendering_engine->get_shadow_renderer()) + shadows->addNodeToShadowList(this); + } } void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes, - v3s16 *p_blocks_min, v3s16 *p_blocks_max) + v3s16 *p_blocks_min, v3s16 *p_blocks_max, float range) { - v3s16 box_nodes_d = m_control.wanted_range * v3s16(1, 1, 1); + if (range <= 0.0f) + range = m_control.wanted_range; + + v3s16 box_nodes_d = range * v3s16(1, 1, 1); // Define p_nodes_min/max as v3s32 because 'cam_pos_nodes -/+ box_nodes_d' // can exceed the range of v3s16 when a large view range is used near the // world edges. @@ -116,26 +188,32 @@ void ClientMap::updateDrawList() { ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG); + m_needs_update_drawlist = false; + for (auto &i : m_drawlist) { MapBlock *block = i.second; block->refDrop(); } m_drawlist.clear(); - v3f camera_position = m_camera_position; - v3f camera_direction = m_camera_direction; - f32 camera_fov = m_camera_fov; + const v3f camera_position = m_camera_position; + const v3f camera_direction = m_camera_direction; // Use a higher fov to accomodate faster camera movements. // Blocks are cropped better when they are drawn. - // Or maybe they aren't? Well whatever. - camera_fov *= 1.2; + const f32 camera_fov = m_camera_fov * 1.1f; v3s16 cam_pos_nodes = floatToInt(camera_position, BS); + v3s16 p_blocks_min; v3s16 p_blocks_max; getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max); + // Read the vision range, unless unlimited range is enabled. + float range = m_control.range_all ? 1e7 : m_control.wanted_range; + + // Number of blocks currently loaded by the client + u32 blocks_loaded = 0; // Number of blocks with mesh in rendering range u32 blocks_in_range_with_mesh = 0; // Number of blocks occlusion culled @@ -151,6 +229,9 @@ void ClientMap::updateDrawList() occlusion_culling_enabled = false; } + v3s16 camera_block = getContainerPos(cam_pos_nodes, MAP_BLOCKSIZE); + m_drawlist = std::map(MapBlockComparer(camera_block)); + // Uncomment to debug occluded blocks in the wireframe mode // TODO: Include this as a flag for an extended debugging setting //if (occlusion_culling_enabled && m_control.show_wireframe) @@ -160,6 +241,7 @@ void ClientMap::updateDrawList() MapSector *sector = sector_it.second; v2s16 sp = sector->getPos(); + blocks_loaded += sector->size(); if (!m_control.range_all) { if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X || sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z) @@ -181,42 +263,39 @@ void ClientMap::updateDrawList() if not seen on display */ - if (block->mesh) - block->mesh->updateCameraOffset(m_camera_offset); - - float range = 100000 * BS; - if (!m_control.range_all) - range = m_control.wanted_range * BS; - - float d = 0.0; - if (!isBlockInSight(block->getPos(), camera_position, - camera_direction, camera_fov, range, &d)) + if (!block->mesh) { + // Ignore if mesh doesn't exist continue; + } + v3s16 block_coord = block->getPos(); + v3s16 block_position = block->getPosRelative() + MAP_BLOCKSIZE / 2; - /* - Ignore if mesh doesn't exist - */ - if (!block->mesh) - continue; + // First, perform a simple distance check, with a padding of one extra block. + if (!m_control.range_all && + block_position.getDistanceFrom(cam_pos_nodes) > range + MAP_BLOCKSIZE) + continue; // Out of range, skip. + // Keep the block alive as long as it is in range. + block->resetUsageTimer(); blocks_in_range_with_mesh++; - /* - Occlusion culling - */ + // Frustum culling + float d = 0.0; + if (!isBlockInSight(block_coord, camera_position, + camera_direction, camera_fov, range * BS, &d)) + continue; + + // Occlusion culling if ((!m_control.range_all && d > m_control.wanted_range * BS) || (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes))) { blocks_occlusion_culled++; continue; } - // This block is in range. Reset usage timer. - block->resetUsageTimer(); - // Add to set block->refGrab(); - m_drawlist[block->getPos()] = block; + m_drawlist[block_coord] = block; sector_blocks_drawn++; } // foreach sectorblocks @@ -228,52 +307,9 @@ void ClientMap::updateDrawList() g_profiler->avg("MapBlock meshes in range [#]", blocks_in_range_with_mesh); g_profiler->avg("MapBlocks occlusion culled [#]", blocks_occlusion_culled); g_profiler->avg("MapBlocks drawn [#]", m_drawlist.size()); + g_profiler->avg("MapBlocks loaded [#]", blocks_loaded); } -struct MeshBufList -{ - video::SMaterial m; - std::vector bufs; -}; - -struct MeshBufListList -{ - /*! - * Stores the mesh buffers of the world. - * The array index is the material's layer. - * The vector part groups vertices by material. - */ - std::vector lists[MAX_TILE_LAYERS]; - - void clear() - { - for (auto &list : lists) - list.clear(); - } - - void add(scene::IMeshBuffer *buf, u8 layer) - { - // Append to the correct layer - std::vector &list = lists[layer]; - const video::SMaterial &m = buf->getMaterial(); - for (MeshBufList &l : list) { - // comparing a full material is quite expensive so we don't do it if - // not even first texture is equal - if (l.m.TextureLayer[0].Texture != m.TextureLayer[0].Texture) - continue; - - if (l.m == m) { - l.bufs.push_back(buf); - return; - } - } - MeshBufList l; - l.m = m; - l.bufs.push_back(buf); - list.push_back(l); - } -}; - void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) { bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT; @@ -293,45 +329,51 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) /* Get animation parameters */ - float animation_time = m_client->getAnimationTime(); - int crack = m_client->getCrackLevel(); - u32 daynight_ratio = m_client->getEnv().getDayNightRatio(); + const float animation_time = m_client->getAnimationTime(); + const int crack = m_client->getCrackLevel(); + const u32 daynight_ratio = m_client->getEnv().getDayNightRatio(); - v3f camera_position = m_camera_position; - v3f camera_direction = m_camera_direction; - f32 camera_fov = m_camera_fov; + const v3f camera_position = m_camera_position; /* Get all blocks and draw all visible ones */ u32 vertex_count = 0; + u32 drawcall_count = 0; // For limiting number of mesh animations per frame u32 mesh_animate_count = 0; //u32 mesh_animate_count_far = 0; + /* + Update transparent meshes + */ + if (is_transparent_pass) + updateTransparentMeshBuffers(); + /* Draw the selected MapBlocks */ - MeshBufListList drawbufs; + MeshBufListList grouped_buffers; + std::vector draw_order; + video::SMaterial previous_material; for (auto &i : m_drawlist) { + v3s16 block_pos = i.first; MapBlock *block = i.second; // If the mesh of the block happened to get deleted, ignore it if (!block->mesh) continue; - float d = 0.0; - if (!isBlockInSight(block->getPos(), camera_position, - camera_direction, camera_fov, 100000 * BS, &d)) - continue; + v3f block_pos_r = intToFloat(block->getPosRelative() + MAP_BLOCKSIZE / 2, BS); + float d = camera_position.getDistanceFrom(block_pos_r); + d = MYMAX(0,d - BLOCK_MAX_RADIUS); // Mesh animation if (pass == scene::ESNRP_SOLID) { - //MutexAutoLock lock(block->mesh_mutex); MapBlockMesh *mapBlockMesh = block->mesh; assert(mapBlockMesh); // Pretty random but this should work somewhat nicely @@ -351,9 +393,15 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) /* Get the meshbuffers of the block */ - { - //MutexAutoLock lock(block->mesh_mutex); - + if (is_transparent_pass) { + // In transparent pass, the mesh will give us + // the partial buffers in the correct order + for (auto &buffer : block->mesh->getTransparentBuffers()) + draw_order.emplace_back(block_pos, &buffer); + } + else { + // otherwise, group buffers across meshes + // using MeshBufListList MapBlockMesh *mapBlockMesh = block->mesh; assert(mapBlockMesh); @@ -367,48 +415,94 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) video::SMaterial& material = buf->getMaterial(); video::IMaterialRenderer* rnd = - driver->getMaterialRenderer(material.MaterialType); + driver->getMaterialRenderer(material.MaterialType); bool transparent = (rnd && rnd->isTransparent()); - if (transparent == is_transparent_pass) { + if (!transparent) { if (buf->getVertexCount() == 0) errorstream << "Block [" << analyze_block(block) - << "] contains an empty meshbuf" << std::endl; - - material.setFlag(video::EMF_TRILINEAR_FILTER, - m_cache_trilinear_filter); - material.setFlag(video::EMF_BILINEAR_FILTER, - m_cache_bilinear_filter); - material.setFlag(video::EMF_ANISOTROPIC_FILTER, - m_cache_anistropic_filter); - material.setFlag(video::EMF_WIREFRAME, - m_control.show_wireframe); - - drawbufs.add(buf, layer); + << "] contains an empty meshbuf" << std::endl; + + grouped_buffers.add(buf, block_pos, layer); } } } } } - TimeTaker draw("Drawing mesh buffers"); - - // Render all layers in order - for (auto &lists : drawbufs.lists) { + // Capture draw order for all solid meshes + for (auto &lists : grouped_buffers.lists) { for (MeshBufList &list : lists) { - // Check and abort if the machine is swapping a lot - if (draw.getTimerTime() > 2000) { - infostream << "ClientMap::renderMap(): Rendering took >2s, " << - "returning." << std::endl; - return; + // iterate in reverse to draw closest blocks first + for (auto it = list.bufs.rbegin(); it != list.bufs.rend(); ++it) { + draw_order.emplace_back(it->first, it->second, it != list.bufs.rbegin()); } - driver->setMaterial(list.m); + } + } + + TimeTaker draw("Drawing mesh buffers"); + + core::matrix4 m; // Model matrix + v3f offset = intToFloat(m_camera_offset, BS); + u32 material_swaps = 0; + + // Render all mesh buffers in order + drawcall_count += draw_order.size(); + + for (auto &descriptor : draw_order) { + scene::IMeshBuffer *buf; + + if (descriptor.m_use_partial_buffer) { + descriptor.m_partial_buffer->beforeDraw(); + buf = descriptor.m_partial_buffer->getBuffer(); + } + else { + buf = descriptor.m_buffer; + } + + // Check and abort if the machine is swapping a lot + if (draw.getTimerTime() > 2000) { + infostream << "ClientMap::renderMap(): Rendering took >2s, " << + "returning." << std::endl; + return; + } - for (scene::IMeshBuffer *buf : list.bufs) { - driver->drawMeshBuffer(buf); - vertex_count += buf->getVertexCount(); + if (!descriptor.m_reuse_material) { + auto &material = buf->getMaterial(); + + // Apply filter settings + material.setFlag(video::EMF_TRILINEAR_FILTER, + m_cache_trilinear_filter); + material.setFlag(video::EMF_BILINEAR_FILTER, + m_cache_bilinear_filter); + material.setFlag(video::EMF_ANISOTROPIC_FILTER, + m_cache_anistropic_filter); + material.setFlag(video::EMF_WIREFRAME, + m_control.show_wireframe); + + // pass the shadow map texture to the buffer texture + ShadowRenderer *shadow = m_rendering_engine->get_shadow_renderer(); + if (shadow && shadow->is_active()) { + auto &layer = material.TextureLayer[3]; + layer.Texture = shadow->get_texture(); + layer.TextureWrapU = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE; + layer.TextureWrapV = video::E_TEXTURE_CLAMP::ETC_CLAMP_TO_EDGE; + // Do not enable filter on shadow texture to avoid visual artifacts + // with colored shadows. + // Filtering is done in shader code anyway + layer.TrilinearFilter = false; } + driver->setMaterial(material); + ++material_swaps; } + + v3f block_wpos = intToFloat(descriptor.m_pos * MAP_BLOCKSIZE, BS); + m.setTranslation(block_wpos - offset); + + driver->setTransform(video::ETS_WORLD, m); + driver->drawMeshBuffer(buf); + vertex_count += buf->getIndexCount(); } + g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true)); // Log only on solid pass because values are the same @@ -416,7 +510,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count); } + if (pass == scene::ESNRP_TRANSPARENT) { + g_profiler->avg("renderMap(): transparent buffers [#]", draw_order.size()); + } + g_profiler->avg(prefix + "vertices drawn [#]", vertex_count); + g_profiler->avg(prefix + "drawcalls [#]", drawcall_count); + g_profiler->avg(prefix + "material swaps [#]", material_swaps); } static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step, @@ -499,12 +599,12 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor, static v3f z_directions[50] = { v3f(-100, 0, 0) }; - static f32 z_offsets[sizeof(z_directions)/sizeof(*z_directions)] = { + static f32 z_offsets[50] = { -1000, }; - if(z_directions[0].X < -99){ - for(u32 i=0; i 35*BS) sunlight_min_d = 35*BS; std::vector values; - for(u32 i=0; i a; a.buildRotateFromTo(v3f(0,1,0), z_dir); @@ -609,4 +710,257 @@ void ClientMap::PrintInfo(std::ostream &out) out<<"ClientMap: "; } +void ClientMap::renderMapShadows(video::IVideoDriver *driver, + const video::SMaterial &material, s32 pass, int frame, int total_frames) +{ + bool is_transparent_pass = pass != scene::ESNRP_SOLID; + std::string prefix; + if (is_transparent_pass) + prefix = "renderMap(SHADOW TRANS): "; + else + prefix = "renderMap(SHADOW SOLID): "; + + u32 drawcall_count = 0; + u32 vertex_count = 0; + + MeshBufListList grouped_buffers; + std::vector draw_order; + + + int count = 0; + int low_bound = is_transparent_pass ? 0 : m_drawlist_shadow.size() / total_frames * frame; + int high_bound = is_transparent_pass ? m_drawlist_shadow.size() : m_drawlist_shadow.size() / total_frames * (frame + 1); + + // transparent pass should be rendered in one go + if (is_transparent_pass && frame != total_frames - 1) { + return; + } + + for (auto &i : m_drawlist_shadow) { + // only process specific part of the list & break early + ++count; + if (count <= low_bound) + continue; + if (count > high_bound) + break; + + v3s16 block_pos = i.first; + MapBlock *block = i.second; + + // If the mesh of the block happened to get deleted, ignore it + if (!block->mesh) + continue; + + /* + Get the meshbuffers of the block + */ + if (is_transparent_pass) { + // In transparent pass, the mesh will give us + // the partial buffers in the correct order + for (auto &buffer : block->mesh->getTransparentBuffers()) + draw_order.emplace_back(block_pos, &buffer); + } + else { + // otherwise, group buffers across meshes + // using MeshBufListList + MapBlockMesh *mapBlockMesh = block->mesh; + assert(mapBlockMesh); + + for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) { + scene::IMesh *mesh = mapBlockMesh->getMesh(layer); + assert(mesh); + + u32 c = mesh->getMeshBufferCount(); + for (u32 i = 0; i < c; i++) { + scene::IMeshBuffer *buf = mesh->getMeshBuffer(i); + + video::SMaterial &mat = buf->getMaterial(); + auto rnd = driver->getMaterialRenderer(mat.MaterialType); + bool transparent = rnd && rnd->isTransparent(); + if (!transparent) + grouped_buffers.add(buf, block_pos, layer); + } + } + } + } + + u32 buffer_count = 0; + for (auto &lists : grouped_buffers.lists) + for (MeshBufList &list : lists) + buffer_count += list.bufs.size(); + + draw_order.reserve(draw_order.size() + buffer_count); + + // Capture draw order for all solid meshes + for (auto &lists : grouped_buffers.lists) { + for (MeshBufList &list : lists) { + // iterate in reverse to draw closest blocks first + for (auto it = list.bufs.rbegin(); it != list.bufs.rend(); ++it) + draw_order.emplace_back(it->first, it->second, it != list.bufs.rbegin()); + } + } + + TimeTaker draw("Drawing shadow mesh buffers"); + + core::matrix4 m; // Model matrix + v3f offset = intToFloat(m_camera_offset, BS); + u32 material_swaps = 0; + + // Render all mesh buffers in order + drawcall_count += draw_order.size(); + + for (auto &descriptor : draw_order) { + scene::IMeshBuffer *buf; + + if (descriptor.m_use_partial_buffer) { + descriptor.m_partial_buffer->beforeDraw(); + buf = descriptor.m_partial_buffer->getBuffer(); + } + else { + buf = descriptor.m_buffer; + } + + // Check and abort if the machine is swapping a lot + if (draw.getTimerTime() > 1000) { + infostream << "ClientMap::renderMapShadows(): Rendering " + "took >1s, returning." << std::endl; + break; + } + + if (!descriptor.m_reuse_material) { + // override some material properties + video::SMaterial local_material = buf->getMaterial(); + local_material.MaterialType = material.MaterialType; + local_material.BackfaceCulling = material.BackfaceCulling; + local_material.FrontfaceCulling = material.FrontfaceCulling; + local_material.BlendOperation = material.BlendOperation; + local_material.Lighting = false; + driver->setMaterial(local_material); + ++material_swaps; + } + + v3f block_wpos = intToFloat(descriptor.m_pos * MAP_BLOCKSIZE, BS); + m.setTranslation(block_wpos - offset); + + driver->setTransform(video::ETS_WORLD, m); + driver->drawMeshBuffer(buf); + vertex_count += buf->getIndexCount(); + } + + // restore the driver material state + video::SMaterial clean; + clean.BlendOperation = video::EBO_ADD; + driver->setMaterial(clean); // reset material to defaults + driver->draw3DLine(v3f(), v3f(), video::SColor(0)); + + g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true)); + g_profiler->avg(prefix + "vertices drawn [#]", vertex_count); + g_profiler->avg(prefix + "drawcalls [#]", drawcall_count); + g_profiler->avg(prefix + "material swaps [#]", material_swaps); +} + +/* + Custom update draw list for the pov of shadow light. +*/ +void ClientMap::updateDrawListShadow(v3f shadow_light_pos, v3f shadow_light_dir, float radius, float length) +{ + ScopeProfiler sp(g_profiler, "CM::updateDrawListShadow()", SPT_AVG); + + v3s16 cam_pos_nodes = floatToInt(shadow_light_pos, BS); + v3s16 p_blocks_min; + v3s16 p_blocks_max; + getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max, radius + length); + + std::vector blocks_in_range; + + for (auto &i : m_drawlist_shadow) { + MapBlock *block = i.second; + block->refDrop(); + } + m_drawlist_shadow.clear(); + + // Number of blocks currently loaded by the client + u32 blocks_loaded = 0; + // Number of blocks with mesh in rendering range + u32 blocks_in_range_with_mesh = 0; + // Number of blocks occlusion culled + u32 blocks_occlusion_culled = 0; + + for (auto §or_it : m_sectors) { + MapSector *sector = sector_it.second; + if (!sector) + continue; + blocks_loaded += sector->size(); + + MapBlockVect sectorblocks; + sector->getBlocks(sectorblocks); + + /* + Loop through blocks in sector + */ + for (MapBlock *block : sectorblocks) { + if (!block->mesh) { + // Ignore if mesh doesn't exist + continue; + } + + v3f block_pos = intToFloat(block->getPos() * MAP_BLOCKSIZE, BS); + v3f projection = shadow_light_pos + shadow_light_dir * shadow_light_dir.dotProduct(block_pos - shadow_light_pos); + if (projection.getDistanceFrom(block_pos) > radius) + continue; + + blocks_in_range_with_mesh++; + + // This block is in range. Reset usage timer. + block->resetUsageTimer(); + + // Add to set + if (m_drawlist_shadow.find(block->getPos()) == m_drawlist_shadow.end()) { + block->refGrab(); + m_drawlist_shadow[block->getPos()] = block; + } + } + } + + g_profiler->avg("SHADOW MapBlock meshes in range [#]", blocks_in_range_with_mesh); + g_profiler->avg("SHADOW MapBlocks occlusion culled [#]", blocks_occlusion_culled); + g_profiler->avg("SHADOW MapBlocks drawn [#]", m_drawlist_shadow.size()); + g_profiler->avg("SHADOW MapBlocks loaded [#]", blocks_loaded); +} + +void ClientMap::updateTransparentMeshBuffers() +{ + ScopeProfiler sp(g_profiler, "CM::updateTransparentMeshBuffers", SPT_AVG); + u32 sorted_blocks = 0; + u32 unsorted_blocks = 0; + f32 sorting_distance_sq = pow(m_cache_transparency_sorting_distance * BS, 2.0f); + + + // Update the order of transparent mesh buffers in each mesh + for (auto it = m_drawlist.begin(); it != m_drawlist.end(); it++) { + MapBlock* block = it->second; + if (!block->mesh) + continue; + + if (m_needs_update_transparent_meshes || + block->mesh->getTransparentBuffers().size() == 0) { + + v3s16 block_pos = block->getPos(); + v3f block_pos_f = intToFloat(block_pos * MAP_BLOCKSIZE + MAP_BLOCKSIZE / 2, BS); + f32 distance = m_camera_position.getDistanceFromSQ(block_pos_f); + if (distance <= sorting_distance_sq) { + block->mesh->updateTransparentBuffers(m_camera_position, block_pos); + ++sorted_blocks; + } + else { + block->mesh->consolidateTransparentBuffers(); + ++unsorted_blocks; + } + } + } + + g_profiler->avg("CM::Transparent Buffers - Sorted", sorted_blocks); + g_profiler->avg("CM::Transparent Buffers - Unsorted", unsorted_blocks); + m_needs_update_transparent_meshes = false; +}