]> git.lizzy.rs Git - minetest.git/blobdiff - src/clientmap.cpp
Fix memory leaks due to messed up memory handling for particles as well as their...
[minetest.git] / src / clientmap.cpp
index c0806836704e11d10a483277ea428e5efe55877c..0e53ab678606b9ca51bc97ea3678bfd99dd92d25 100644 (file)
@@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mapblock.h"
 #include "profiler.h"
 #include "settings.h"
+#include "camera.h" // CameraModes
 #include "util/mathconstants.h"
 #include <algorithm>
 
@@ -50,17 +51,28 @@ ClientMap::ClientMap(
        m_camera_direction(0,0,1),
        m_camera_fov(M_PI)
 {
-       m_camera_mutex.Init();
-       assert(m_camera_mutex.IsInitialized());
-       
        m_box = core::aabbox3d<f32>(-BS*1000000,-BS*1000000,-BS*1000000,
                        BS*1000000,BS*1000000,BS*1000000);
+
+       /* TODO: Add a callback function so these can be updated when a setting
+        *       changes.  At this point in time it doesn't matter (e.g. /set
+        *       is documented to change server settings only)
+        *
+        * TODO: Local caching of settings is not optimal and should at some stage
+        *       be updated to use a global settings object for getting thse values
+        *       (as opposed to the this local caching). This can be addressed in
+        *       a later release.
+        */
+       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");
+
 }
 
 ClientMap::~ClientMap()
 {
        /*JMutexAutoLock lock(mesh_mutex);
-       
+
        if(mesh != NULL)
        {
                mesh->drop();
@@ -78,15 +90,15 @@ MapSector * ClientMap::emergeSector(v2s16 p2d)
        catch(InvalidPositionException &e)
        {
        }
-       
+
        // Create a sector
        ClientMapSector *sector = new ClientMapSector(this, p2d, m_gamedef);
-       
+
        {
                //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
                m_sectors[p2d] = sector;
        }
-       
+
        return sector;
 }
 
@@ -97,7 +109,7 @@ void ClientMap::deSerializeSector(v2s16 p2d, std::istream &is)
        ClientMapSector *sector = NULL;
 
        //JMutexAutoLock lock(m_sector_mutex); // Bulk comment-out
-       
+
        core::map<v2s16, MapSector*>::Node *n = m_sectors.find(p2d);
 
        if(n != NULL)
@@ -178,6 +190,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
        v3f camera_position = m_camera_position;
        v3f camera_direction = m_camera_direction;
        f32 camera_fov = m_camera_fov;
+       v3s16 camera_offset = m_camera_offset;
        m_camera_mutex.Unlock();
 
        // Use a higher fov to accomodate faster camera movements.
@@ -199,7 +212,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
                        p_nodes_max.X / MAP_BLOCKSIZE + 1,
                        p_nodes_max.Y / MAP_BLOCKSIZE + 1,
                        p_nodes_max.Z / MAP_BLOCKSIZE + 1);
-       
+
        // Number of blocks in rendering range
        u32 blocks_in_range = 0;
        // Number of blocks occlusion culled
@@ -215,6 +228,8 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
        //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;
 
        for(std::map<v2s16, MapSector*>::iterator
                        si = m_sectors.begin();
@@ -222,7 +237,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
        {
                MapSector *sector = si->second;
                v2s16 sp = sector->getPos();
-               
+
                if(m_control.range_all == false)
                {
                        if(sp.X < p_blocks_min.X
@@ -234,13 +249,13 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
 
                std::list< MapBlock * > sectorblocks;
                sector->getBlocks(sectorblocks);
-               
+
                /*
                        Loop through blocks in sector
                */
 
                u32 sector_blocks_drawn = 0;
-               
+
                std::list< MapBlock * >::iterator i;
                for(i=sectorblocks.begin(); i!=sectorblocks.end(); i++)
                {
@@ -250,7 +265,10 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
                                Compare block position to camera position, skip
                                if not seen on display
                        */
-                       
+
+                       if (block->mesh != NULL)
+                               block->mesh->updateCameraOffset(m_camera_offset);
+
                        float range = 100000 * BS;
                        if(m_control.range_all == false)
                                range = m_control.wanted_range * BS;
@@ -269,7 +287,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
                                continue;*/
 
                        blocks_in_range++;
-                       
+
                        /*
                                Ignore if mesh doesn't exist
                        */
@@ -330,7 +348,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
                                blocks_occlusion_culled++;
                                continue;
                        }
-                       
+
                        // This block is in range. Reset usage timer.
                        block->resetUsageTimer();
 
@@ -347,6 +365,8 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
 
                        sector_blocks_drawn++;
                        blocks_drawn++;
+                       if(d/BS > farthest_drawn)
+                               farthest_drawn = d/BS;
 
                } // foreach sectorblocks
 
@@ -356,6 +376,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
 
        m_control.blocks_would_have_drawn = blocks_would_have_drawn;
        m_control.blocks_drawn = blocks_drawn;
+       m_control.farthest_drawn = farthest_drawn;
 
        g_profiler->avg("CM: blocks in range", blocks_in_range);
        g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
@@ -363,6 +384,7 @@ void ClientMap::updateDrawList(video::IVideoDriver* driver)
                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);
 }
 
@@ -375,18 +397,25 @@ struct MeshBufList
 struct MeshBufListList
 {
        std::list<MeshBufList> lists;
-       
+
        void clear()
        {
                lists.clear();
        }
-       
+
        void add(scene::IMeshBuffer *buf)
        {
                for(std::list<MeshBufList>::iterator i = lists.begin();
                                i != lists.end(); ++i){
                        MeshBufList &l = *i;
-                       if(l.m == buf->getMaterial()){
+                       video::SMaterial &m = buf->getMaterial();
+
+                       // 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;
                        }
@@ -403,7 +432,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
        DSTACK(__FUNCTION_NAME);
 
        bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
-       
+
        std::string prefix;
        if(pass == scene::ESNRP_SOLID)
                prefix = "CM: solid: ";
@@ -418,13 +447,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                m_last_drawn_sectors.clear();
        }
 
-       bool use_trilinear_filter = g_settings->getBool("trilinear_filter");
-       bool use_bilinear_filter = g_settings->getBool("bilinear_filter");
-       bool use_anisotropic_filter = g_settings->getBool("anisotropic_filter");
-
        /*
                Get time for measuring timeout.
-               
+
                Measuring time is very useful for long delays when the
                machine is swapping a lot.
        */
@@ -448,7 +473,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
        */
 
        v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
-       
+
        v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
 
        v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
@@ -464,14 +489,14 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                        p_nodes_max.X / MAP_BLOCKSIZE + 1,
                        p_nodes_max.Y / MAP_BLOCKSIZE + 1,
                        p_nodes_max.Z / MAP_BLOCKSIZE + 1);
-       
+
        u32 vertex_count = 0;
        u32 meshbuffer_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
@@ -497,7 +522,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                // If the mesh of the block happened to get deleted, ignore it
                if(block->mesh == NULL)
                        continue;
-               
+
                float d = 0.0;
                if(isBlockInSight(block->getPos(), camera_position,
                                camera_direction, camera_fov,
@@ -551,9 +576,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                        {
                                scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
 
-                               buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, use_trilinear_filter);
-                               buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, use_bilinear_filter);
-                               buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, use_anisotropic_filter);
+                               buf->getMaterial().setFlag(video::EMF_TRILINEAR_FILTER, m_cache_trilinear_filter);
+                               buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, m_cache_bilinear_filter);
+                               buf->getMaterial().setFlag(video::EMF_ANISOTROPIC_FILTER, m_cache_anistropic_filter);
 
                                const video::SMaterial& material = buf->getMaterial();
                                video::IMaterialRenderer* rnd =
@@ -569,9 +594,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                        }
                }
        }
-       
+
        std::list<MeshBufList> &lists = drawbufs.lists;
-       
+
        int timecheck_counter = 0;
        for(std::list<MeshBufList>::iterator i = lists.begin();
                        i != lists.end(); ++i)
@@ -593,9 +618,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
                }
 
                MeshBufList &list = *i;
-               
+
                driver->setMaterial(list.m);
-               
+
                for(std::list<scene::IMeshBuffer*>::iterator j = list.bufs.begin();
                                j != list.bufs.end(); ++j)
                {
@@ -652,13 +677,13 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
 #endif
        }
        } // ScopeProfiler
-       
+
        // 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(prefix+"vertices drawn", vertex_count);
        if(blocks_had_pass_meshbuf != 0)
                g_profiler->avg(prefix+"meshbuffers per block",
@@ -709,7 +734,7 @@ static bool getVisibleBrightness(Map *map, v3f p0, v3f dir, float step,
                pf += dir * step;
                distance += step;
                step *= step_multiplier;
-               
+
                v3s16 p = floatToInt(pf, BS);
                MapNode n = map->getNodeNoEx(p);
                if(allow_allowing_non_sunlight_propagates && i == 0 &&
@@ -829,7 +854,6 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
                        ret = decode_light(n.getLightBlend(daylight_factor, ndef));
                } else {
                        ret = oldvalue;
-                       //ret = blend_light(255, 0, daylight_factor);
                }
        } else {
                /*float pre = (float)brightness_sum / (float)brightness_count;
@@ -848,7 +872,7 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
        return ret;
 }
 
-void ClientMap::renderPostFx()
+void ClientMap::renderPostFx(CameraMode cam_mode)
 {
        INodeDefManager *nodemgr = m_gamedef->ndef();
 
@@ -863,9 +887,12 @@ void ClientMap::renderPostFx()
 
        // - If the player is in a solid node, make everything black.
        // - If the player is in liquid, draw a semi-transparent overlay.
+       // - Do not if player is in third person mode
        const ContentFeatures& features = nodemgr->get(n);
        video::SColor post_effect_color = features.post_effect_color;
-       if(features.solidness == 2 && !(g_settings->getBool("noclip") && m_gamedef->checkLocalPrivilege("noclip")))
+       if(features.solidness == 2 && !(g_settings->getBool("noclip") &&
+                       m_gamedef->checkLocalPrivilege("noclip")) &&
+                       cam_mode == CAMERA_MODE_FIRST)
        {
                post_effect_color = video::SColor(255, 0, 0, 0);
        }