]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/client/clientmap.cpp
Merge branch 'master' of https://github.com/minetest/minetest
[dragonfireclient.git] / src / client / clientmap.cpp
index 70fb3476784933eea0abf839dd798b01f04f3bfc..68fd41e397845dbd4aaa01cb2093d1f43bb93d48 100644 (file)
@@ -31,12 +31,43 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include <algorithm>
 #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<MeshBufList> &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,
                MapDrawControl &control,
                s32 id
 ):
-       Map(dout_client, client),
+       Map(client),
        scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
                RenderingEngine::get_scene_manager(), id),
        m_client(client),
@@ -63,14 +94,13 @@ ClientMap::ClientMap(
 MapSector * ClientMap::emergeSector(v2s16 p2d)
 {
        // Check that it doesn't exist already
-       try {
-               return getSectorNoGenerate(p2d);
-       } catch(InvalidPositionException &e) {
-       }
+       MapSector *sector = getSectorNoGenerate(p2d);
 
-       // Create a sector
-       MapSector *sector = new MapSector(this, p2d, m_gamedef);
-       m_sectors[p2d] = sector;
+       // Create it if it does not exist yet
+       if (!sector) {
+               sector = new MapSector(this, p2d, m_gamedef);
+               m_sectors[p2d] = sector;
+       }
 
        return sector;
 }
@@ -116,7 +146,6 @@ void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes,
 void ClientMap::updateDrawList()
 {
        ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
-       g_profiler->add("CM::updateDrawList() count", 1);
 
        for (auto &i : m_drawlist) {
                MapBlock *block = i.second;
@@ -124,52 +153,45 @@ void ClientMap::updateDrawList()
        }
        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);
 
-       // Number of blocks in rendering range
-       u32 blocks_in_range = 0;
+       // 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;
-       // Number of blocks in rendering range but don't have a mesh
-       u32 blocks_in_range_without_mesh = 0;
-       // Blocks that had mesh that would have been drawn according to
-       // rendering range (if max blocks limit didn't kick in)
-       u32 blocks_would_have_drawn = 0;
-       // Blocks that were drawn and had a mesh
-       u32 blocks_drawn = 0;
-       // Blocks which had a corresponding meshbuffer for this pass
-       //u32 blocks_had_pass_meshbuf = 0;
-       // Blocks from which stuff was actually drawn
-       //u32 blocks_without_stuff = 0;
-       // Distance to farthest drawn block
-       float farthest_drawn = 0;
 
        // No occlusion culling when free_move is on and camera is
        // inside ground
        bool occlusion_culling_enabled = true;
-       if (g_settings->getBool("free_move")) {
+       if ((g_settings->getBool("free_move") && g_settings->getBool("noclip")) || g_settings->getBool("freecam")) {
                MapNode n = getNode(cam_pos_nodes);
                if (n.getContent() == CONTENT_IGNORE ||
                                m_nodedef->get(n).solidness == 2)
                        occlusion_culling_enabled = false;
        }
 
+       // 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)
+       //    occlusion_culling_enabled = porting::getTimeS() & 1;
+
        for (const auto &sector_it : m_sectors) {
                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)
@@ -185,14 +207,16 @@ void ClientMap::updateDrawList()
 
                u32 sector_blocks_drawn = 0;
 
-               for (auto block : sectorblocks) {
+               for (MapBlock *block : sectorblocks) {
                        /*
-                       Compare block position to camera position, skip
-                       if not seen on display
-               */
+                               Compare block position to camera position, skip
+                               if not seen on display
+                       */
 
-                       if (block->mesh)
-                               block->mesh->updateCameraOffset(m_camera_offset);
+                       if (!block->mesh) {
+                               // Ignore if mesh doesn't exist
+                               continue;
+                       }
 
                        float range = 100000 * BS;
                        if (!m_control.range_all)
@@ -203,20 +227,13 @@ void ClientMap::updateDrawList()
                                        camera_direction, camera_fov, range, &d))
                                continue;
 
-                       blocks_in_range++;
-
-                       /*
-                               Ignore if mesh doesn't exist
-                       */
-                       if (!block->mesh) {
-                               blocks_in_range_without_mesh++;
-                               continue;
-                       }
+                       blocks_in_range_with_mesh++;
 
                        /*
                                Occlusion culling
                        */
-                       if (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes)) {
+                       if ((!m_control.range_all && d > m_control.wanted_range * BS) ||
+                                       (occlusion_culling_enabled && isBlockOccluded(block, cam_pos_nodes))) {
                                blocks_occlusion_culled++;
                                continue;
                        }
@@ -224,91 +241,32 @@ void ClientMap::updateDrawList()
                        // This block is in range. Reset usage timer.
                        block->resetUsageTimer();
 
-                       // Limit block count in case of a sudden increase
-                       blocks_would_have_drawn++;
-                       if (blocks_drawn >= m_control.wanted_max_blocks &&
-                                       !m_control.range_all &&
-                                       d > m_control.wanted_range * BS)
-                               continue;
-
                        // Add to set
                        block->refGrab();
                        m_drawlist[block->getPos()] = block;
 
                        sector_blocks_drawn++;
-                       blocks_drawn++;
-                       if (d / BS > farthest_drawn)
-                               farthest_drawn = d / BS;
-
                } // foreach sectorblocks
 
                if (sector_blocks_drawn != 0)
                        m_last_drawn_sectors.insert(sp);
        }
 
-       g_profiler->avg("CM: blocks in range", blocks_in_range);
-       g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
-       if (blocks_in_range != 0)
-               g_profiler->avg("CM: blocks in range without mesh (frac)",
-                               (float)blocks_in_range_without_mesh / blocks_in_range);
-       g_profiler->avg("CM: blocks drawn", blocks_drawn);
-       g_profiler->avg("CM: farthest drawn", farthest_drawn);
-       g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
+       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<scene::IMeshBuffer*> 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<MeshBufList> 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<MeshBufList> &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;
 
        std::string prefix;
        if (pass == scene::ESNRP_SOLID)
-               prefix = "CM: solid: ";
+               prefix = "renderMap(SOLID): ";
        else
-               prefix = "CM: transparent: ";
+               prefix = "renderMap(TRANSPARENT): ";
 
        /*
                This is called two times per frame, reset on the non-transparent one
@@ -316,53 +274,36 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
        if (pass == scene::ESNRP_SOLID)
                m_last_drawn_sectors.clear();
 
-       /*
-               Get time for measuring timeout.
-
-               Measuring time is very useful for long delays when the
-               machine is swapping a lot.
-       */
-       std::time_t time1 = time(0);
-
        /*
                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;
+       const v3f camera_direction = m_camera_direction;
+       const f32 camera_fov = m_camera_fov;
 
        /*
                Get all blocks and draw all visible ones
        */
 
        u32 vertex_count = 0;
-       u32 meshbuffer_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;
-
-       // Blocks that were drawn and had a mesh
-       u32 blocks_drawn = 0;
-       // Blocks which had a corresponding meshbuffer for this pass
-       u32 blocks_had_pass_meshbuf = 0;
-       // Blocks from which stuff was actually drawn
-       u32 blocks_without_stuff = 0;
+       //u32 mesh_animate_count_far = 0;
 
        /*
                Draw the selected MapBlocks
        */
 
-       {
-       ScopeProfiler sp(g_profiler, prefix + "drawing blocks", SPT_AVG);
-
        MeshBufListList drawbufs;
 
        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
@@ -381,15 +322,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                        assert(mapBlockMesh);
                        // Pretty random but this should work somewhat nicely
                        bool faraway = d >= BS * 50;
-                       //bool faraway = d >= m_control.wanted_range * BS;
                        if (mapBlockMesh->isAnimationForced() || !faraway ||
-                                       mesh_animate_count_far < (m_control.range_all ? 200 : 50)) {
+                                       mesh_animate_count < (m_control.range_all ? 200 : 50)) {
+
                                bool animated = mapBlockMesh->animate(faraway, animation_time,
                                        crack, daynight_ratio);
                                if (animated)
                                        mesh_animate_count++;
-                               if (animated && faraway)
-                                       mesh_animate_count_far++;
                        } else {
                                mapBlockMesh->decreaseAnimationForceTimer();
                        }
@@ -430,53 +369,51 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                                                material.setFlag(video::EMF_WIREFRAME,
                                                        m_control.show_wireframe);
 
-                                               drawbufs.add(buf, layer);
+                                               drawbufs.add(buf, block_pos, layer);
                                        }
                                }
                        }
                }
        }
 
+       TimeTaker draw("Drawing mesh buffers");
+
+       core::matrix4 m; // Model matrix
+       v3f offset = intToFloat(m_camera_offset, BS);
+
        // Render all layers in order
        for (auto &lists : drawbufs.lists) {
-               int timecheck_counter = 0;
                for (MeshBufList &list : lists) {
-                       timecheck_counter++;
-                       if (timecheck_counter > 50) {
-                               timecheck_counter = 0;
-                               std::time_t time2 = time(0);
-                               if (time2 > time1 + 4) {
-                                       infostream << "ClientMap::renderMap(): "
-                                               "Rendering takes ages, returning."
-                                               << std::endl;
-                                       return;
-                               }
+                       // Check and abort if the machine is swapping a lot
+                       if (draw.getTimerTime() > 2000) {
+                               infostream << "ClientMap::renderMap(): Rendering took >2s, " <<
+                                               "returning." << std::endl;
+                               return;
                        }
-
                        driver->setMaterial(list.m);
 
-                       for (scene::IMeshBuffer *buf : list.bufs) {
+                       drawcall_count += list.bufs.size();
+                       for (auto &pair : list.bufs) {
+                               scene::IMeshBuffer *buf = pair.second;
+
+                               v3f block_wpos = intToFloat(pair.first * MAP_BLOCKSIZE, BS);
+                               m.setTranslation(block_wpos - offset);
+
+                               driver->setTransform(video::ETS_WORLD, m);
                                driver->drawMeshBuffer(buf);
                                vertex_count += buf->getVertexCount();
-                               meshbuffer_count++;
                        }
                }
        }
-       } // ScopeProfiler
+       g_profiler->avg(prefix + "draw meshes [ms]", draw.stop(true));
 
        // Log only on solid pass because values are the same
        if (pass == scene::ESNRP_SOLID) {
-               g_profiler->avg("CM: animated meshes", mesh_animate_count);
-               g_profiler->avg("CM: animated meshes (far)", mesh_animate_count_far);
+               g_profiler->avg("renderMap(): animated meshes [#]", mesh_animate_count);
        }
 
-       g_profiler->avg(prefix + "vertices drawn", vertex_count);
-       if (blocks_had_pass_meshbuf != 0)
-               g_profiler->avg(prefix + "meshbuffers per block",
-                       (float)meshbuffer_count / (float)blocks_had_pass_meshbuf);
-       if (blocks_drawn != 0)
-               g_profiler->avg(prefix + "empty blocks (frac)",
-                       (float)blocks_without_stuff / blocks_drawn);
+       g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
+       g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
 }
 
 static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
@@ -555,6 +492,7 @@ static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
 int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
                int oldvalue, bool *sunlight_seen_result)
 {
+       ScopeProfiler sp(g_profiler, "CM::getBackgroundBrightness", SPT_AVG);
        static v3f z_directions[50] = {
                v3f(-100, 0, 0)
        };
@@ -647,8 +585,8 @@ void ClientMap::renderPostFx(CameraMode cam_mode)
        // - Do not if player is in third person mode
        const ContentFeatures& features = m_nodedef->get(n);
        video::SColor post_effect_color = features.post_effect_color;
-       if(features.solidness == 2 && !(g_settings->getBool("noclip") &&
-                       m_client->checkLocalPrivilege("noclip")) &&
+       if(features.solidness == 2 && !((g_settings->getBool("noclip") || g_settings->getBool("freecam")) &&
+                       (m_client->checkLocalPrivilege("noclip") || g_settings->getBool("freecam"))) &&
                        cam_mode == CAMERA_MODE_FIRST)
        {
                post_effect_color = video::SColor(255, 0, 0, 0);
@@ -667,5 +605,3 @@ void ClientMap::PrintInfo(std::ostream &out)
 {
        out<<"ClientMap: ";
 }
-
-